Is hiding lower level APIs bad?
There are many good arguments for hiding away the lower layers in your stack – essentially the building blocks upon which your public API is built - however the ‘we don’t have the time and resources to test that layer completely’ argument seems a little flawed to me.
Surely if you are sitting above a layer you have to test it thoroughly anyway?
And if the lower layer is all locked away, private or internal, that is going to be a LOT harder.
Imagine somebody trying to paint the bottom of a can through an open stay tab.
Not exactly the easiest thing in the world. But that is exactly what testing a private lower level API is like.
It would be much easier if you had complete and unfettered access to the inside of the can / lower level.
So if you have to test that surface anyway why not just make it public?
Counter Arguments?
Well, like all programming decisions, it’s not quite that simple. There are many nuances.
What for example if exposing your lower level API…
- Just isn’t that useful to your target audience?
- Requires too much orchestration and non-obvious call orders?
- Exposes you to more legal obligations?
- Would require a lot of supporting work like documentation etc?
- Might be wrong, and you don’t want to be locked into the current design forever?
- Means your software is no longer opinionated?
I’m sure you can think of many similar pivots.
That there are good reasons to keep things internal is beyond debate, what I hope everyone realizes though is that test cost alone probably isn’t reason enough.
Comments
Anonymous
February 22, 2010
Good post,recently i was struggling with the same dilemma on one project.In my experience the underlying layers can (and sometimes should) be private/internal but they should always be completely covered with unit tests and then we can concentrate on testing the higher layers.See my post on how to unit test/mock internal interfaces and classes (with RhinoMocks in this case):http://blog.roboblob.com/2010/02/18/unit-testing-and-mocking-internal-interfaces-with-rhinomocks/nice blog,keep up the good work!Anonymous
February 23, 2010
@Roboblob (or should I say Slobodan),Thanks for the link, interesting stuff, and thanks for the kind words.AlexAnonymous
February 23, 2010
The comment has been removedAnonymous
February 23, 2010
Layers should be tested in the context of the layer. So a layer should have its own tests. So all the nitty gritty details can be tested.Integration between layers should be testable through the most public level Layer if its interesting enough to test, it should be public to something! its easy enough to hide public things behind a higher layer If you have private stuff that is interesting enough to test in its own right, make it public and hide it away :) class A{ private void X() {} public void B() { X(); }}becomesclass A{ private CX _x; public void B() { CX.X();}}class CX{ public void X() {}}You can do the same type of thing with larger chunks of code.... eg, Data Access layers can hide the data technology yet the data technology is public and testable.Anonymous
February 23, 2010
@Keith,Good to hear from you again...And yes I kind of agree you... I like that principle, i.e. the lower layers are implemented in public classes, but are NOT publically exposed. That makes a lot of sense.AlexAnonymous
February 23, 2010
Counter Arguments?Um... .NET Team's generic coding style with usage of "internals" for whole implementation of the CLR, made a pile of pain to any single developer ever tried to extend base framework functionality :)