So here's an interesting question that I'd like to pose to my silent readership: how would *you* solve this particular issue, and why would you solve it in that particular way.
Let's say you have a published API called Foobar, and Foobar's job is to tell you whether the user can access a particular resource. This API was sensible when you first published it, but over the years, the operating system has changed the game a bit. Now the OS has decided that the user can have "pretend access" to a particular resource in some circumstances, but they don't have true access to it. Instead, they have access to a resource that mimics the original, but is really just a proxy. What should the behavior of your API be? Should it report back whether the caller has access to the *actual* resource, or whether it has access to the *proxy* resource when dealing with this special case?
I think this is a hard case to solve, since the answer really can go either way. From one perspective, you can access the resource since the ultimate operation still succeeds. From another perspective, you can't access the resource because the operation fails on the intended target resource. So, given an existing API, what's the proper answer when the OS changes the rules after the API's been published?
deprecate the old API and create a new one for the proxy?
I should note that there are no wrong answers here, I'm just trying to stimulate a discussion for a real world problem. :-)
@Steve -- why do you think that's the best solution? Also, how do you deal with the naming issue? Let's say the original name was CanAccesXXX (where XXX is the name of the resource). What would the new name be, and would it make as much sense as the old name?
well I don't know. Eventually you are going to break backwards compatibility, or end up with tons of functions that you are not supposed to use but still are able to access. You could end up having the same function do two different things based on framework version maybe, or as I see with some web api's you pass in the version to the function that you want to use as an options, so like CanAccessBlah(version#, {other params})
or just come up with a better name, or use namespaces to differentiate. One that comes to mind is in .net with the System.Configuration namespace. They just went and added ConfigurationManager namespace for newer functions where the old ones were just in System.Configuration and new ones were in System.Configuration.ConfigurationManager. and the compiler gave warnings on deprecations.
@Steve -- Correct me if I'm wrong, but you view the issue as more of a feature, of sorts, than a bug? So you think of CanAccessXXXv2 as being a logical extension of CanAccessXXXv1 where v1's behavior may be more desirable in some cases, and v2's behavior may be more desirable in others?
depends i guess
If a better way of doing it was figured out in version 2, but version 1 is there just not break old code i guess. but in the next version of your framework, version 1 wouldnt be there, so either you stay on framework1 or change your code to use the version 2+ versions. most (majority) devs i think dont care how the underlying stuff is happening as long as it gives them the right result and the compiler doesnt whine
Any reason that you'd not add a means to tell if what you CanAccess is the real item or the proxy item ?
Kind of how folderitems have a "true child" and "child"
ow that does leave the old methods still functional but at least you could tell which you get back and do something appropriate.
Dunno if that'd be adequate though
@Steve -- ah, so if there are no functional differences, then the API doesn't need to diverge. But if there are functional differences, then the old code path should remain valid because people may have written code which relies on the old behavior that would break.
Interesting take on the issue, to be sure! Thanks!
Other people have other comments to add?
@Norman -- that's sort of akin to what Steve was touching on with regards to divergent APIs, I think.
The issue I take with that approach is that it becomes harder for someone new to the issue to know which API to use. If the names sound equally as likely, then it's a cause for confusion. God knows there's enough confusion between Item and TrueItem!
However, there's certainly no technical limitation holding us back from adding a second API to differentiate between the proxy and the real object.
To throw another wrench into the discussion, I think a bit more information is needed. However, I don't want to give out *too* much information as it may jade people's comments. Suffice it to say that the OS's proxy vs real resource is actually a temporary shim for backwards compatibility. So the requirement for two different APIs like Item and TrueItem would probably be overkill since the underlying issue is likely to go away in a future release of the OS.
New thoughts?
I think Steve is saying that if you want to change the API, you either break existing code (makes people mad) or change the name or namespace of the API. The only reason to use the old one would be for backwards compatibility, and it should be depreciated. The compiler should warn you that this is the case and allow the user to update it. The new API should give access to the same kind of information, just adding in the new stuff the OS provides.
For your example, the api should tell the program if it has complete access, virtual access, or no access. whereas the old API only said yes or no. This in between value changes stuff. Some people might want just to be able to write, and don't care the specifics, but others do. So the new API might provide information like that. Or say what level of access the user has (if at least this level...). It's not saying keep the old stuff for some situations, it's keep the old stuff for backwards compatibility.
It might even be possible to change the current API to expose this new information, and warn when you are using old information.
@jdiwnab -- but what about the (new, exposed in the comments) problem where this proxy access is actually not a constant feature of the OS? In that case, would it make sense to commit to an API that exposes this underlying proxy information when that proxy information may only be valid for a release or two? Basically: do you pollute the namespace for a temporary problem? Eventually, CanAccessXXX will go back to being a yes or no question with definitive results (just like it used to be).
This is all really good discussion, btw! I'm getting more of a response than I was anticipating, which is a nice thing. :-) I'm trying to play devil's advocate a bit here just to keep things lively, and I plan to give a more concrete example in the near future to put this discussion on more real terms (pun intended after the fact, I promise).
Considering that the "interim" may be several years I don't see how you can avoid having a second fuller featured API in addition to the original API
That way the user can not break code but will have whatever odd functiosn the old API had but could update to a newer more "correct" and current API
@Norman -- ok.. what about this angle though: was the user's code correct in the first place?
The purpose of CanAccessXXX was to tell you whether you can access that resource. On version 1 of the OS, this would return true and this was correct. On version 2 of the OS, the answer is no, except, for now I'll let you access this thing which acts like it. On version 3 of the OS, the answer will be no, which will be correct. In all three cases, this is given identical input.
I guess where my confusion comes in to play is: if a programmer is asking "can I access this", isn't it expected that the programmer handle the case where the answer is "no", even if they've not run into it previously? If that's true, then would a secondary API even be needed? The OS obviously wants you to migrate away from that resource... you'd be on the leading edge of the migration, but that's not a bad thing as that's the direction you ultimately need to go anyway...
I don't think there's any good solutions - just ugly ones to this problem. I think it depends on how much backwards compatibility you want from your API's.
The safest thing would be to have a completely new set of API's on your new OS that don't exist in your old OS. This ticks off your developer community but it's the safest thing to do if the functionality is different.
The application would then have to check for OS version and then call the appropriate API. It sucks, and it breaks backwards compatibility but you have to draw the line somewhere, in my opinion.
How much do you love your developers and how loud will they scream? Will they scream loud enough and long enough for you to leave the old API in?
Aaron wrote:
[quote]
if a programmer is asking "can I access this", isn't it expected that the programmer handle the case where the answer is "no", even if they've not run into it previously? If that's true, then would a secondary API even be needed?
[/quote]
That depends on if there any practical consequences to using the virtual resource. For example if it will be 10X slower. If so another code path may be needed in those case or perhaps asking the user for a new location (assuming you are talking about where to write writing files for example).
Also I agree with Norm. What is planned may take a longer time to come to fruition than expected - if ever (aka Longhorn/Vista features and timing)
- Karen
I vote for the API change. Instead of returning a boolean to say yea or nay, it should return a number representing the level of access. For example:
0 = no access
1 = proxy
2 = full access
Then developers who don't care about the proxy just need to check for > 0 instead of true. Not a big deal in my opinion.
@Christian -- the API is already published, so there's no way to just modify the return type (as that would break code for sure!). And you can't overload based on return type (in REALbasic), so that pretty much means you're stuck picking a new name (or finding a parameter to pass in). Also, once the proxying feature is removed from the OS, then what? Now it's back to a simple boolean return value, but you have this complex API to deal with it (which pretty much requires the user to read the documentation, no less).
The purpose of CanAccessXXX is to answer a simple question. The problem, as I understand it, is that the OS now has the ability to give you access to a copy of it instead of the original? Then just let the developer know what they're getting when it's returned.
if Foobar.CanAccess then
if Foobar.IsVirtual
//Do strange things to it.
end if
end if
With the new API, I think that if you had a system like Christian's, that it would work on any version of the OS, just with some extra on v1 and v3. With version 1, it would return 0 or 2. On version 2, it would return 0, 1, o 2, and on version 3, you'd be back to 0 or 2. Thus the new API would work on older OSs, thus the old API could be depreciated.
However, I do see your point about having extra information in the API with version 3 of the OS. That wouldn't be all that good. But I think that with the OS removing such ability, they are breaking old programs and code more than our API. I think that this version 3 of the OS would have to wait a while after version 2, in order to allow transition.
One option I just though of would be to keep the original API (with boolean information), and add a second one that would tell you if the access is virtual or not. This isn't pretty either, but it wouldn't break old code. The programmer would have to check to see if it is virtual if they cared about that. You would be left with an extra API after version 3 is out, but it could probably be left for backwards compatibility with the (now older) version 2.
Hi Aaron,
I don´t want to give you the answer to you question, but I want to tell you, what I think, where it lies:
Stop thinking too much about the Resource and the API. Stop thinking about the Proxy. Start thinking about the user of the API. Who is he? What´s his perspective? Is it code of another Programmer? Is it code that directly interacts with the User of the application? This might lead to a good and reasonable answer.
Yours,
Jens