1. 7

  2. 6

    This is a pretty nice justification for the whole conventional belief system that leads to “abstraction”, “coupling vs cohesion”, “SOLID”, etc. But that whole memeplex is dangerously misguided. It has a kernel of truth, but it’s incomplete, and it’s dangerous because the vast majority of programmers seem to get brainwashed by it until they’re blind to anything else.

    To see how it’s misleading, let’s focus on this sentence:

    ..a triangle is actually very highly interconnected for the number of nodes it has..

    This is a telling sentence, because it highlights that this entire notion of ‘complexity’ is really about density of complexity. Which means that if you just took your triangle and started spliting the vertices into lots of nodes, so that it has lots of nodes along each edge of the triangle, the whole would seem a lot less complex. But you haven’t really made the whole any less complex, you’ve just spread the complexity out into a smooth thin layer. The inherent complexity of the system remains. It’s just harder to find; randomly selected nodes/modules seem simple, and you have to jump through a lot of hoops to find the ‘complex node’ that invariably gets the lion’s share of updates.

    The whole thing takes me back to my childhood years, when I would shove my stuff into my closet to try to convince my mom I’d cleaned up my room.

    Abstraction is useful, and it’s useful to think about the right places to draw module boundaries. But as a rule of thumb, mistrust anybody who tries to pontificate about the difference between simplicity and complexity merely by making reference to module/interface boundaries, without any attention to what the system does.

    So much for tearing down somebody else who in fairness wrote very elegantly indeed. Can I be constructive instead? I’ll suggest an alternative memeplex for thinking about complexity that gets a lot less attention than it should. Complexity comes from the state space of inputs a system needs to handle, and the number of regimes this state space gets broken down into. (Imagine something like the characteristics of a transistor.) The more regimes a state space has, the more intrinsically complex the domain is.

    If we could demarcate this state space, and make the regimes in the state space explicit in our representation of the system – rather than implicit in lines of code as happens today – I think we’d make far larger strides in controlling complexity than any number of attempts at redrawing internal boundaries between sub-systems. In particular, we’d be able to detect over-engineering and architecture astronomy: they would be situations where a code has significantly higher complexity than the domain it’s trying to address.

    I think such a representation has to start at (no surprises for people here who’ve heard me ranting before) tests. Tests are great because they’re like a Fourier transform applied to the conventional representation of a program as code. Instead of focusing on what to do at each point in time for a program, looking at a program as a collection of tests tells you how the entire trajectory of processing needs to go for the major regimes in the input space. Tests allow you to get past what your current program does, and think about the essential things any program has to do to achieve the same ends.

    (I’ve written about this idea before. Hopefully this latest attempt is clearer.)

    1. 2

      I’ll add the state space is my favorite way of looking at complexity because it’s actual values/actions of your software. Different implementations will have different state spaces to assess complexity. Different techniques for reducing complexity can show they do with the state space reductions. Either actual reductions or what it lets us ignore in an analysis for correctness.

      1. 2

        I like the idea of thinking in terms of a state space! I have a couple of questions:

        • Aren’t there really three spaces/sets involved: the set of inputs, the set of possible programs that handle such inputs, and the set of internal program states?
        • I noticed you say in the linked post that tests are the only way to delineate boundaries in the state of programs. What about formal verification methods?
        1. 1

          Sorry I thought I’d responded to this. I’m glad to see more thinking about state spaces of different stripes.

          I overstated my case. Formal methods may well be an alternative. I just don’t know much about them.

        2. 2

          Can you define what you mean by “regime” here?

          1. 1

            It’s meaning 1b at Merriam -Webster:

            a regular pattern of occurrence or action (as of seasonal rainfall)

            I see now that the figure of transistor characteristics I linked to above refers to active and saturation “regions”. I seem to recall learning them as regimes in undergrad in India.

            Basically it’s a subset of the input space for which the program behavior is the same. How you define “same” is flexible. One definition would be identical control flow paths through the program. Alternatively you can think of timing attacks on encryption schemes as exposing regimes in the underlying algorithm.

          2. 1

            Whether the triangle has three nodes, or many along each edge, it still has the same number of loops: 1. That’s perhaps a more important observation. A graph that’s easy to color is probably a graph with few loops.

            1. 1

              Loops might be part of it, but imagine a ‘necklace’ of loops. Each loop can be 2-coloured, and you can join the links at points with the same colour, so you can have as many loops as you like and still only need 2 colours.