Stable API.
We know that the 'scary corner' of the Abstractness/Instability graph is reserved for the native types (int, string, arrays) who are completely concrete but are the core building blocks of all our applications. We also know that we don't care for any of the code *we* write to dwell there, since "concrete" == "changeable", and "stable" = "hard-to-change".
But what about the other denizens of the scary corner? The platform API and the third-party APIs also tend to hunkerdown around 0,0 territory. The question is whether we should write our own objects to abstract away from platform and add-on APIs or whether we should instead let DRY/YAGNI drive us to depend on it until the first change.
Our IT history is littered with stories about big changes in platform APIs (MS has had a few) that cause last-minute panic as software houses and IS groups and platform (embedded or control) integrators find that their work is about to become obsolete. But Are You Going To Need It is still a tough call.
Is the third-party API more reliable or less reliable than the platform API? Is it more fearful to use commercial components or open-source components? OSS tends to take frequent upgrades, but never goes out of business leaving you with the task of chasing down a new vendor. Is that better? Or just different?
If you choose to trust the platform, I think one can make a case for either trusting it as-written or trusting it as-documented.
Looking at these issues, one tends to think that the platform API is not to be trusted, but YAGNI calls to us.....
!commentForm
Ask yourself how much effort would it be to shield from the core API. I think that even if it's likely to
change, it's simply not worth the extra effort.
For add-on APIs things are different. It depends on two factors:
1. Costs of shielding from the 3rd Party APIs. If it's something that connects to the outside world
(Mail API, Database, Connection to a Web Service etc.) you need some abstraction to get unit tests in
place so you need some abstraction anyway.
2. "Trust" in the API's stability. This depends on many things.
I once blogged about that...
http://jroller.com/page/sebastianKuebeck/20050709
For stability of the microsoft APIs have a look at...
http://www.joelonsoftware.com/articles/APIWar.html
change, it's simply not worth the extra effort.
For add-on APIs things are different. It depends on two factors:
1. Costs of shielding from the 3rd Party APIs. If it's something that connects to the outside world
(Mail API, Database, Connection to a Web Service etc.) you need some abstraction to get unit tests in
place so you need some abstraction anyway.
2. "Trust" in the API's stability. This depends on many things.
I once blogged about that...
http://jroller.com/page/sebastianKuebeck/20050709
For stability of the microsoft APIs have a look at...
http://www.joelonsoftware.com/articles/APIWar.html
The other problem with wrapping all platform APIs is that you end up with one of three conditions:
a. A perfect analogue to the wrapped API -- which means changing the implementation will require an unknown amount of translation.
b. A subset of the API, which will need tweaking as you discover new things you need to provide access to, thus making the wrapper less stable.
c. A superset of the API, which means translation code again, which needs unit tests and which might have bugs (more than the underlying API, since it's just yours).
(All three conditions can occur at once, in different parts of the API.)
I've seen, for example, our own wrappers around a logging API, which (a) mimics the underlying interface exactly, which after we decided on a logging package seems both fortunate and silly, (b) relies on a constructor that limits how we can name loggers (e.g. with a class, but not an arbitrary name), and (c) has extraneous crap left over from old requirements that prevents us from simply converting wholesale with a Perl script.
YAGNI notwithstanding, it's better to make a few key decisions up front, rather than "stay flexible" and end up with more code to maintain. Some of those decisions would be logging, error reporting, exception handling, configuration, installation, utilities (e.g. regexps), and anything else more part of the programming domain than the problem domain.
a. A perfect analogue to the wrapped API -- which means changing the implementation will require an unknown amount of translation.
b. A subset of the API, which will need tweaking as you discover new things you need to provide access to, thus making the wrapper less stable.
c. A superset of the API, which means translation code again, which needs unit tests and which might have bugs (more than the underlying API, since it's just yours).
(All three conditions can occur at once, in different parts of the API.)
I've seen, for example, our own wrappers around a logging API, which (a) mimics the underlying interface exactly, which after we decided on a logging package seems both fortunate and silly, (b) relies on a constructor that limits how we can name loggers (e.g. with a class, but not an arbitrary name), and (c) has extraneous crap left over from old requirements that prevents us from simply converting wholesale with a Perl script.
YAGNI notwithstanding, it's better to make a few key decisions up front, rather than "stay flexible" and end up with more code to maintain. Some of those decisions would be logging, error reporting, exception handling, configuration, installation, utilities (e.g. regexps), and anything else more part of the programming domain than the problem domain.
Frank - THANK YOU for that distinction. I hear a lot that code is code, period, and all the same rules apply to all code. I have a tough time with that - for example tests - I think "code clarity" and "test clarity" are two very different animals. And now you've helped me make understand important distinction. Much obliged.
Add Child Page to StableApi