Welcome to the first in a series of posts in which we will answer the questions:
- How does complexity sneak into software?
- How can we recognize it before it becomes painful?
- And, how can we remove it permanently?
Source Code Complexity
Before we dive into answering these questions though, let's define what we mean when we use the word "complexity".
In the context of software development, complexity refers to how hard it is to understand a bit of source code. More precisely, complexity refers to how the arrangement of the source code clarifies or obscures the intention behind the code.
Complex source code obscures intention, making it difficult to change, and prone to regression upon modification. Simple source code, on the other hand, reveals intention, making it far simpler to extend, and highly resistant to regression.
There are other kinds of complexity in software, of course. Algorithms can be complex. Problem domains can be hard to understand. But, the source code used to express these things need not be complex.
In fact, the complexity we're describing is most accurately described as source code complexity. But, that's a bit of a handful to type over and over again. So, we'll use the word "complexity" as a shorthand for "source code complexity" throughout this series of posts.
Sandi Metz briefly covers the history of software complexity metrics in her book 99 Bottles of OOP. She mentions three different ways to measure complexity:
Source Lines of Code
Source Lines of Code measures exactly what it sounds like it measures: the number of lines of source code in a method.
Cyclomatic Complexity measures the number of code paths through a method, class, or application.
Assignments, Branches, and Conditionals (ABC)
Assignments, Branches, and Conditionals (ABC) is the newest metric. It calculates a complexity score for a method, class, or application using this formula:
√(A² + B² + C²)
where A, B, and C are the number of assignments, branches (method calls), and conditionals present in the code.
The Ruby community has largely settled on Ryan Davis' Flog gem for measuring complexity. Flog is a Ruby-centric implementation of the ABC metric that also penalizes metaprogramming since it generally obscures the intention of the code.
We will be referencing flog scores throughout the series to quantitatively compare the complexity of multiple arrangements of source code.
The Coffee Machine
Over the course of the next several posts, we're going to build a little coffee machine application and use it to point out key concepts, one user story at a time.
That's all for now. Up next, we'll write our first user story in the coffee machine: As a patron, I want coffee.