Somewhere I heard someone claim that: “Programming is an exercise in managing complexity.” The word “is” makes the sentence slightly ambiguous. It could mean: “Programming is just an exercise in managing complexity,” implying that that’s all programming is. Or it could mean: “Programming is an exercise in managing complexity (in addition to other things).”
I would absolutely disagree with the first interpretation; programming is definitely more than just managing complexity. On the other hand, managing complexity is a huge aspect of programming.
We can start by examining what complexity means. There’s no formal definition, because complexity means different things in different areas. But a good general definition might be that complexity refers to something with many parts that interact in many ways. We might add that complex systems tend to have multiple levels of many parts interacting.
For one example, your body is a complex bio-machine with many part that interact in such complex ways that we still haven’t completely figured out the human body. And there are multiple levels: chemical, genetic, complete organs, food processing, etc.
Even some of our individual organs are complex systems all on their own, and certainly the brain is the most complex machine we know.
Designing and writing software does involve many parts that interact in many ways and on multiple levels.
Every callable unit (sub-routine, method, function, etc.) is a part that interacts with others. A key design goal (a complexity management technique) involves decoupling these pieces as much as possible. A good design seeks to minimize the interaction to a specific “contract” expressing the acceptable inputs and expected outputs.
This is why global objects are considered such a no-no. Any global object stands “naked” in the code environment, potentially interacting with anyone and everyone. The exception to the rule is read-only (constant) global objects. When no one can change the public state, there is no real interaction and therefore no problem.
In fact, global constants are not only not a problem, they are an important technique in reducing synchronization issues. P.J. Plauger once wrote that (except for defining constants), the only numbers that should ever appear in your code are zero and one (and that you should even view those with appropriate suspicion). A similar rule applies to strings.
Another type of global object that I think is okay is (for example) a global logger object. Obviously such an object is not a constant and is “written to” as various parts of your code emit logging info. But the public state doesn’t (or shouldn’t) change, so again there is no interaction in the sense of changing the state affecting others in the environment.
Object-Oriented Design is one way of managing the complexity of interacting parts. A key aspect of OOD is that data is encapsulated (and isolated) along with code that knows about and operates on that data. Outsiders can only ask the object to modify its state; they cannot do it directly.
Compare this to an imperative programming technique where you might call one routine to create a resource and others to do things with it. (For example, opening a file and then reading from or writing to it.) Often in such circumstances, the first routine returns a token of some kind that represents the resource. You pass this token to other routines to work with the resource. Sometimes you even have to be careful to “clean up” or deallocate the resource.
By wrapping that protocol in an object, the token is managed by the object, and the client only interacts with the resource through well-defined object methods. In many languages, the object can guarantee resource clean up through its deconstructor or “final” method.
[As will become clear as I write this blog, I’m a big fan of OOD.]
But whether a design has lots of classes or lots of sub-routines and functions, any serious software package has a lot of parts to keep track of. Some of the larger parts may have smaller parts the coder needs to manage. And the more parts there are, the more ways they can interact.
Modern IDEs and other tools can be a big help. It’s been a joy to see how they’ve grown over the years. Working in an IDE — such as Eclipse, for example — almost makes it easy. Almost.
Even color syntax highlighting (something I disdained at first and now wouldn’t live without) helps manage the low-level complexity of keywords versus object names versus strings versus numbers versus comments. It takes a lot more concentration to work with unhighlighted source!
So while programming isn’t just managing complexity, that is a huge part of the job. Any tools or techniques you can find to help you manage the complexity benefit you and your code!