The Boundary Conditions — Should you even care?
The boundary conditions of any sufficiently complex system define the system’s solution.
The boundary conditions of any sufficiently complex system define the system’s solution. The universe has been understood this way by physics for many years. It is governed by a small set of equations (as we understand it): the Lagrange equations. They are simple differential equations that model the interactions that govern the entire universe. What makes the universe take the particular *form* that it is in is not the equation but the boundary conditions. Speed of light, charge of electron, gravitational constant, etc all bound the infinite possibilities defined by the standard model and constrain it to the one solution that is our universe.
With this model in mind the possible actions of a computer system can also be seen as an infinite space of possible conditions. It is then, by this analogy, the requirements of the system that define the solution to a particular problem. This is intuitively true but what is not is that adding or subtracting a single requirement doesn’t just change one facet of the system but may rearrange the entire underlying structure of the system.
For instance, if the charge of an electron was altered it wouldn’t just make electrons behave differently with respect to protons but would instead make water no longer liquid at room temperature. It would change the fundamental properties of magnetics, it would alter the activity series such that chemical bonds that are stable in our universe would be unstable in the new universe. Ultimately a change to one small requirement can preclude the existence of organic life. This is true for all of the physical constants, each having a very small margin in which the universe is held together the way it is and organic life is possible.
I’m not saying that organic life is a good or bad thing, though, only that these changes are seemingly unrelated to the final result. Organic life, in this example, is what is referred to as an “emergent phenomenon” of the system. There is nothing about the charge of an electron that directly connects to the existence of organic life, instead it is the combination of the equations governing the universe and all the boundary conditions having particular values that allows organic life to “exist”. It is a consequence.
How does this relate to software design again? Once again seeing the infinite space of programs that can be run on a digital computer as the “universe” and the laws of boolean logic as the “equation” you can see a particular program or system as the “manifestation” of a universe base on the constraints. The results of the program are the solution of the equation but the intermediate methods of solving it are in fact the emergent properties of the system (organic life in the physics example). Just as the universe is indifferent to the existence of life so is a software system indifferent to particular emergent properties.
Some example properties of a system are “uses POSTGRES as a database” or “uses SNS as a messaging layer”. None of these emergent properties are part of the system constraints (at least they shouldn’t be, more on that later) but they are what software developers continuously lean on in order to satisfy requirements.
So why do I bring this up? Now consider the universe again. Imagine that the specification changed mid way through the development process of the universe. Perhaps the Higgs-boson started falling into a vacuum energy state tomorrow and then all the pent up energy of the metastable energy state of gravity suddenly started to be released. It wouldn’t just make stuff “less heavy” it would tear apart the very fabric of existence in a wave of destruction moving at the speed of light. (see: https://www.youtube.com/watch?v=ijFm6DxNVyI ).
Now consider this scenario in terms of moving requirements of a software system. The product manager may think that “just a little tweak” to the requirements is only going to change the part of the system that made them think of the change, however, experience says it behaves more like the video. Whole sections of code must be refactored, removed, rearranged and written. Databases migrations need to occur or databases dropped completely. Messaging layers need to be replaced, updated or redesigned. Whole sections of the code will be rewritten and thousands of tests that mistakenly enforced the old boundary conditions will fail.
So, as creators of software systems what do we do about this issue? Can we continue to let our carefully crafted work be bulldozed repeatedly every time the needs of a product change? I believe the answer is no, and the way to get there isn’t necessarily as painful as it sounds. How software systems differ from the universe is in our ability to choose which constraints we want to make. If we let a system constraint be an extremely high cost item, something that is seen not just as a change to a specific behavior of the system but a fundamental change in the entire structure of the system we can start avoiding these seismic shifts. Somewhat like a “carbon tax” these changes should not be measured merely on the cost to implement directly (E.G. how long would it take for you to code a new button on the interface) but their potential to rearrange the very properties of the system. The first step to making good decisions on this front is to know you are making them.
While we cannot always choose our functional requirements, the non-functional ones are within our power. Once you make all the non-functional requirements visible then you can assign cost to them and decide if they should be kept or dropped.
Examples of important but potentially costly non-functional constraints could include
Api requests to external systems should always be batched
Storage of data should be ACID compliant
All API interactions should have an audit trail
The system supports multi-tenancy
Users can only view data associated with their role
Examples of unimportant non-functional constraints could include
Use noSQL databases
Code should be written in Java
Code should have 90% unit test coverage
The list is potentially limitless but the more it is elaborated on the more it is visible which constraints are essentially making design decisions for us.
So what about the arguments about how noSQL databases are great for solving the problems in your business space? This is where I come back to emergence. Just as the equation for the universe does not describe the specification that organic life must exist, so should your non-functional requirements not specify potentially emergent solutions. If your functional and non-functional requirements include things like “input data comes from many different sources with a varied number of fields” the use of a noSQL database will “emerge” as a solution to the problem. If however you have that constraint along with the non-functional constraint “the product uses Microsoft SQL” the rest of the system will morph and contort in order to work around the fundamental dissonance between requirements.
Letting go of our prejudice towards particular non-functional requirements is actually freeing the systems we design to fit the best solution to the necessary constraints that will make our systems successful. In this way, hopefully, if a system is constrained to allow life to exist it will do so not because we made it but because it was the correct solution all along.