In my last post I talked about how software has both a primary and secondary value, and how this idea relates to complexity within the framework of Scrum. I want to take a deeper dive into the ideas of complexity and simplicity in order to establish a common vocabulary that I can use in future posts (and hopefully to spur on a discussion with you, from which we will all gain a better understanding).
My favorite way to think about complexity is through the idea of emergence.
"Emergence is a process whereby larger entities, patterns, and regularities arise through interactions among smaller or simpler entities that themselves do not exhibit such properties"
As software systems grow in interconnectedness and size they will become harder to reason about. This inability to reason about the software system is a reflection of that systems complexity.
It is the interconnectedness of the software that makes it complex. This is not a novel idea as interconnectedness can be thought of as coupling and cohesion, and we all know that in order to write readable, scalable, maintainable code we need to minimize coupling while maximizing cohesion.
What do I mean why I say, "reason about our code"? We can reason about our code in two ways; internally by inspecting the code, and externally by testing the code. By testing the code I am able to understand what it does, I give it these inputs and get those outputs. By looking at the source code I am able to understand how it works.
Our ability to reason about our code both internally and externally is impacted by the complexity of the code. Complex code is hard to test and complex hard is hard to understand, this is why complex code is the root cause of the vast majority of problems with our software. Complex code breeds unreliability, late delivery, and poor performance.
As I am defining the complexity of my code by its interconnectedness, i.e. highly coupled and loosely cohesive code is complex, I can say that simple code is loosely coupled and highly cohesive. This definition makes sense because it is reasonable to expect that code that is loosely coupled and highly cohesive will be easier to reason about. Simple code will be easier to test and simple code will be easier to inspect and understand.
It is important to note that simple and easy are not necessarily the same thing. Simple is objective while easy is subjective. Simple software is loosely coupled and highly cohesive, these are objective metrics that we can measure. Software that is easy for me to write may not be easy for someone else read, because easy is subjective. As an example outside the context of software; it is easy for my mechanic to work on my cars engine, however this does not mean that working on car engines is simple. The reason I go to a mechanic is because I don't know how to work on my cars engine, to me the engine is complicated.
Complicated is not necessarily complex. Just because I can't currently reason about the engine in my car does not mean that it is impossible to reason about. If I spent time studying how it worked I would have a good chance of understanding it, meaning that it would become easier for me to work on. Complicated is subjective, while complex is objective.
To summarize, software is complex if we are unable to reason about it through either testing or inspection. A large contributor to complexity in our software is its interconnectedness, which can be measured as its coupling and cohesion. From this understanding of complexity, we can define simple software as having loose coupling and high cohesion. Writing simple software is not easy, and software that is easy to write is not necessarily simple. Furthermore, writing simple software may be complicated but this does not make it complex. Simple and complex are objective, easy and complicated are subjective.
While writing software our goal is to maximize our software's primary value while still delivering the secondary value required by our customer. Taking the easy route delivering on secondary value can increase our code's complexity over time, which by definition decreases our code's primary value. The path to maximizing our software's primary value is simplicity.
Jon McBee is a Principal Software Engineer at Cambridge NanoTech and is a Certified LabVIEW Architect, Certified LabVIEW Embedded Developer, Certified TestStand Developer, an NI Certified Professional Instructor, a LabVIEW Champion, and a Certified ScrumMaster