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.


photo


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…



  1. Just isn’t that useful to your target audience?

  2. Requires too much orchestration and non-obvious call orders?

  3. Exposes you to more legal obligations?

  4. Would require a lot of supporting work like documentation etc?

  5. Might be wrong, and you don’t want to be locked into the current design forever?

  6. 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 (6)

  1. Anonymous says:

    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!

  2. Alex D James says:

    @Roboblob (or should I say Slobodan),

    Thanks for the link, interesting stuff, and thanks for the kind words.

    Alex

  3. Interesting points Alex.

    Here’s something that came to mind though. You seem to argue that "we don’t have time to test it" is not a good reason to make something public/private, and then proceed to give some better reasons.

    There’s also a degree to which they are interlocked though. Typically a public API has a different design API than a private one. For example, trade-off usability for performance (because there’s a small, bound codebase to which the API has to be usable), or trade-off extensibility for predictability (because we can enumerate the limited ways in which a component will be customized).

    The set of deltas you’d make to a private API to make it into a consumer-ready public API could very well increase your test cost and push it beyond whatever threshold makes you have a go/no-go decision.

    Just my 2 cents though…

    Great post by the way – love to read stuff that stimulates thinking.

  4. Anonymous says:
    • 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(); }

    }

    becomes

    class 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.

  5. Alex D James says:

    @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.

    Alex

  6. Anonymous says:

    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 🙂