Systems can be broadly categorized based on how complex they are. This applies to any system, but I'm mainly interested in software. That's where my expertise is, and it also seems remarkably common for people to misattribute the level of complexity in software systems. Maybe software is special in that regard, or maybe I just have a particularly clear view of it happening. Either way, that misattribution makes it harder to discuss and reason about those systems. I've never found a useful and concise summary of what it means for us that a system is complex or not. So, I'm going to try to write one.
To begin, systems exist along a spectrum of complexity, and these categories are a model of that reality. That model, like all models, is wrong; or rather it's imperfect. But it's also useful. It's even more useful if we understand what each other means when we use these words. Here is my understanding.
Simple systems can be thoroughly understood. We can reliably influence them to enter or exit certain states, as we choose. We can easily modify these systems, and accurately predict the outcomes. Simple systems likely exist within very constrained environments, or have highly constrained inputs and operating states, or both. As a consequence, they are themselves quite constrained. This means they're often not useful. In addition, they're also not very useful to discuss, or study, or teach. Despite that, simple systems are the only systems we can discuss, study, and directly teach. This is because of the practical necessity to establish a shared context, and more complex systems cannot be reduced to a describable state.
Complicated systems cannot be thoroughly understood. But they can be partially or momentarily understood. We can model these systems along with proposed modifications to them. We can make useful—if not necessarily accurate—predictions based on those models. It's likely not possible to know in advance how the system will respond to every input, but it usually is possible to recreate those responses after the fact. As a practical matter, this is the best we can get as software engineers. Any system that's large enough to be useful will be at least complicated.
Complex systems cannot be understood in any kind of systematic way. They exist in only partially known states that arise from only partially known interactions between only partially known inputs. A complex system can't be easily reduced to a useful, predictive model. But, portions of a complex system sometimes can be modeled. These systems can be observed, analyzed, and reasoned about. Rather than rigorously understand these systems, we can become intuitively familiar with them. We can operate based on that familiarity. I couldn't say what proportion of real world software systems are complex, but it's certainly not unusual. We can try to manage and reduce that complexity. We can try to avoid adding complexity beyond what's inherent to the domain. And we can make the system more amenable to analysis. There's been a great deal written on how to do that. For instance, adhering to patterns, maintaining boundaries and interfaces, and emitting more intentional signals to observe.
A chaotic system is not merely unknown, but also unknowable. The system's inputs and behaviors are to some degree random, not just unpredictable. In fact it may not even make sense to think of the sytem as having a singular state. Chaotic systems behave probabilistically. That is, we can estimate, anticipate, and forecast how it will behave in response to various conditions. But we can't control it. Modifying a chaotic system is practically a leap of faith. Operating a chaotic system is not really feasible. So we pretend that we don't. We find or develop abstractions and layer them on top of each other until the system makes enough sense that we can do something with it.
By way of example, a wave is simple. At least, in the abstract intro-to-physics sense. Multiple waves are complicated. Waves in an enclosed or otherwise real space are complex, at least. And the ocean is chaotic. But we identify patterns and use them to build abstractions until we can sail boats around the world. The boat starts out simple. It grows more complex the more capable and resilient it needs to be. The boat and the ocean are a single system. They also interact through very clear interfaces with very clear boundaries. That permits the sailors to treat them as distinct, in which the boat reacts to the chaotic environment of the ocean.
Cover photo by Walid Ahmad