1. 9

  2. 3

    This is a good post, and one which I agree with, in terms of superfluous, bad abstractions. On the other hand, I’ve seen a lot more “under-abstracted” code bases than “seam-obsessed” code bases. It’s a balance that has to be struck.

    1. 1

      It seems (NPI) the main complaint is coupling the public interface to the implementation, vice the actual problem abstraction. I would very much agree with the idea that the abstraction should model the problem and hide the implementation details. However, not being super familiar with seams in general it’s difficult for me to judge if this issue is causal to using seams or just something that can happen with any methodology.

      1. 1

        Interesting and short, but I disagree with one of the conclusions about testing.

        Since we’ve tied the tests to the internal structure of the system, and refactoring changes internal structure, tests will often break after refactoring, even if the external behaviour of the system has not changed.

        One abstraction’s insides is constructed from other abstraction’s outsides. Which abstractions an outer abstraction is made up of may or may not be an implementation detail. (Is the interaction an important side effect?) But, it’s outside observable behavior should be tested, where outside observable is defined as “outside of this component” not “outside from some other arbitrary perspective”.

        If an “abstraction” doesn’t hide any information about the system (all of it’s interactions are important side-effects that must be tested) you’re already in a bad place. Don’t do that!

        1. 1

          I often see code bases where every domain class has an interface, such that the signatures in the interface map one-to-one with the public signatures in the domain class. It’s usually motivated by a desire for test mocks but sometimes also as an interpretation of DIP and dependency injection.

          So far, every time I’ve seen that there were real abstractions struggling to get out of the mammoth interface. Usually some smaller set of methods are used together by a subset of callers. Another set of methods will be used by a different set of callers.

          That’s what the segregated interface principle is about. Each of those subsets of methods show cohesion, so each should be separated into a more descriptive, more abstract interface.

          As a rule, I scrutinize any interface that has exactly one implementer.