Wednesday, October 26, 2011

Layering, Architecture and Convergence

The central problem in software development is managing complexity. This complexity comes from the sea of details and decisions, large and small, that need to converge into a stable, working system in order for it to be successfully used for its intended purpose. That not only includes the code, but also the analysis, management, documentation, packaging, distribution, training, support, configuration and operations that inevitably precede a user being able to utilize some functionality on a computer.

Unchecked, rampant complexity growth in any area can swamp a project, making it impossible to continue substantial progress. About the only way I know to contain complexity is by breaking it off into manageable chunks and getting it encapsulated into well-defined sub-problems. This works at a base level, but new problems emerge. Overlapping sub-problems create redundancies which add significantly to the complexity. This can be managed typing and categorizing the sub-problems carefully, so that overlap is rare or negligible, which gets one past the first hurdle. But as the number of sub-problems grows, their inherent complexity needs to checked as well. At this upper level, they just form a slightly higher, more abstract version of the overall problem, but all of the same issues apply.

Thus, at some point in order to manage the complexity another higher layer becomes necessary and the same issues repeat over again. As the complexity grows, the number of layers to manage it grows as well. Thus, in any attempt to manage growing complexity, a steadily increasing number of layers will need to be created. This is the inevitable consequence of our existence, we can’t handle unlimited sized problems. Smart people or well-running teams may have higher limits, but there is always some limit, and it is always reached earlier than expected.

Layering occurs in all aspects of software development, but for this post I’d like to just focus on how it effects the code, data and operations of software.

The first and most obvious layer in software is the underlying code itself. Programmers get presented with a number of domain or technical problems for which they assemble a large number of instructions for a computer to follow. It is well understood that failure to organize these instructions results in ‘spaghetti code’. That is code with a logical structure so intertwined it resembles the noodles in a plate of spaghetti. Of course this is bad, because any attempt to alter the code is hampered by a significant wall of complexity. From this, within the context of coding, we can draw the conclusion that dis-organization increases complexity.

As the code base begins to grow, it becomes necessary to break it off into more and more sub-problems to manage it. This layer is most often referred to as system’s architecture. It introduces conceptual groups like modules, sub-systems, components, etc. Each of these pieces encapsulates a larger subset of the functionality, and the interactions between them gets formalized. Although I’ve never seen it mentioned, dis-organization at this level can produce a spaghetti architecture, one that impedes both changes and overall stability. Experience coding in the base layer does not easily translate into understanding the organizational issues at this layer. They appear similar, but they are fundamentally different problems.

Once a system has grown out of its base components, it is often desirable to widen its functionality to a larger group of developers. This creates essentially a platform layer where the core abilities are exposed, and controlled, allowing for the existing work to be leveraged for more divergent purposes. Once again, failure to organize this layer results in more pasta, and of course understanding the dynamics of the necessary organization is not directly related to the layers below.

Continuing upwards we get to the product or system layer. This layer generally introduces a new set of problems because it is driven more often by the desires or needs of non-technical people. Organization at this level comes more as ‘paths’ that are followed serially or in parallel, but they still need the same generalized principles of organization. Experience at this level generally involves far more people and negotiating skills, than technical ones. A product manager for a commercial system for instance is balancing the technical issues against the direction and current of the market place.

The final layer that I’m going to discuss is the one that is completely ignored by most technical people. For users to access the system, it has to be running somewhere. In an effort to contain the complexity of design and work most systems form vertical silos. That is they handle a very specific problem and don't easily inter-operate with the other systems being run in their environment. There are some interconnections, but standards are weak because they interfere with individual goals or profit margins. As such, most modern large organizations have a large number of these silos. Like every other layer, redundancies cause significant problems. Thus, at an operational level, all large organizations need an organizational scheme to coordinate the building or purchasing of these silos into a manageable affair. This drives concepts such as the common enterprise software ‘categories’ like CRM and CM, which implicitly contain the primitive building blocks of the operational environment. Again, dis-organization at this level results in an enterprise wide plate of pasta, which diminishes that usefulness of the tools.

No doubt there are many more layers, since they are dynamic and unlimited in number. For any given layer, as it gets better organized we can say it is ‘converging’. By this we mean that in some overall way, its base complexity matches closely to the underlying ‘necessary’ complexity of the layer. If it’s not managed then it diverges, generally as a result of disorganization, over-engineering, over-simplification or any other amplifier that isn’t fundamentally inherent to solving the problem.

It should be noted that there is a subjective (human-based) component to minimal complexity. That is, for reasons based on the way individuals think, the lines between over, under and minimal complexity tend to move around. One person’s perfect trade-offs can appear overly complex to another person. Thus rather than a fixed point, a layer will generally converge within a range, particularly if there are many people involved.

Thus in software development, in order to manage complexity, we want to see the overall system converge on a reasonable number of layers, while each layer is converging on a reasonable system of organization. Development is an ongoing progress, and thus so is converging. We simply need to track all of these ‘paths towards organization’ and continually insure that they are headed for the correct goal. At the bottom layer that is accomplished by programmers pushing themselves for elegance, while at the upper layers is it often architects or managers trying to place some organizational constraints on the chaos below. Every layer needs to get close in order to win.