1. 14

  2. 8

    I like to think of this as structuring your software such that you can easily jettison/replace dependencies. Say you want to use Stripe as a payment processor. You grab their client library and start integrating with it. The easy way is to just spray calls to Sprite’s client library through your logic. And this is fine, up until you want to ask more of the code, at which point you might start wishing it’d been confined to a boundary object that you could inject or otherwise instrument.

    Judicious use of this pattern really goes a long way cleaning up some codebases because it forces all the gross interface code to be locked up somewhere. It’s still there, but you can keep it in the closet, and only visit it if need be.

    I think it’s kind of a subtle point though. A newer dev might prefer to see the third party code because it was hard to write and they’re proud of it. A design-pattern-everything dev might prefer not to see it because they got to use a pattern. And a nihilistic-its-all-just-bytes dev might prefer to keep it in there because, who cares? Me, I like my business logic clean and separate from the gory details of the world.

    1. 5

      I think a very useful architecture pattern is to have a well defined boundary between your code and the outside worlds code that you own. This gives you all kind of useful benefits like

      • The system boundaries are well defined and easier to follow
      • Adding middleware is easy when you need to
      • Upgrading or swapping a dependency doesn’t spray itself all over your codebase
      • Fakes are easier to use which reduce your reliance on one off mocks
      1. 2

        A newer dev might prefer to see the third party code because it was hard to write and they’re proud of it

        Does this actually happen?

        1. 2

          I was once that newer dev. I learned quickly that it had all kinds of problems but I’m self taught so I hadn’t learned the importance of the whole encapsulation thing yet.

      2. 6

        This is one of the biggest advantages of mocks, that you don’t need their underlying type to be extensible, just their API stable.

        I don’t understand why it’s not “make your code interface stable, and add new interfaces rather than upgrade old” as opposed to “just don’t assume any code you call’s behavior will follow any assumptions at any time”.

        1. 1

          Make new interfaces but keep the old. One is silver, the other is gold.

        2. 6

          The only times I’ve gone through the trouble of mocking out someone else’s interface are cases where the library authors did not provide any testing capability, or wanted me to run a whole damn simulator process in addition to my test code. Google in particular has been guilty of this.

          1. 3

            Yes I wrote an alternative implementation of their message bus once because the simulator barely worked. Some fat java app to run in the background but managing it’s state was really hard which made it tricky to use for testing. Sadly that code never got open sourced :(