Do you know the difference between “complex” and “complicated”? Most of us certainly mix both concepts, sometimes even several times a day. Spoiler alert: they do not mean what you think they mean.
Being an etymology geek, I opened my beloved “Dictionnaire Historique de la Langue Française,” this monumental work by Alain Rey published chez Éditions Robert, and found out the ancestors of both words. Not just because doing it in French makes everything look more intellectual, mind you.
Complex is borrowed from the Latin complexus, meaning “made of intertwined elements”. This word is the past participle adjectived of complecti (“embrace, understand”) itself derived from plectere (“bend, intertwine”). This word has been used since the XVI century to qualify that which is made of heterogenous elements.
Complex shares the same root (plectere) with the words “perplex” (in use since the 14th century in France) and the medical term “plexus” meaning “interlacing” and used since the 16th century as a medical term for “network of nerves or blood vessels”.
One of the most common uses of the word in science is the concept of “complex numbers”, created by the Italian mathematicians Gerolamo Cardano and Raffaele Bombelli (between 1545 and 1560), later rigourously defined by William Rowan Hamilton in 1828, born from the need to solve the problem of the square root of -1.
On the other hand, “Complicated” has a similar origin but a different construction:
Complicated comes from the Latin complicare, literally meaning “to fold by rolling up”. Figuratively speaking this was taken as close to the notion of embarrassment or awkwardness. The word is composed of the word plicare which means “to fold”.
The Spanish word “plegar” and the French “plier” are direct descendants of this Latin root.
To summarise, “Complex” and “Complicated” stem from slightly different roots: the Latin root plectere (“to intertwine”) in the former, and plicare (“to fold”) for the latter.
Complex conveys the idea of a network of intertwined objects, whose state and behavior are continuously modified by their peers in that network. The word complicated implies an intrinsic apparent “obscurity” through folding unto itself, inviting to a simple “unfolding” discovery process.
Or, put in another way: complex numbers are not complicated. They are made of real and imaginary parts. Maths can be complicated, though.
In page 12 of the “NeXT Object-Oriented Programming and the Objective-C Language” book, available at the GNUStep project website, the image of a pocket watch conveys an explanation to the abstract concept of “encapsulation.” Encapsulation of what? Of complication, precisely.
Watches commonly known as “Complications” (such as the Patek Philippe Calibre 89, the Franck Muller Aeternitas Mega and the “Référence 57260” de Vacheron Constantin) are complicated, yet not complex, machines. An “Object” in the sense of OOP, should a complicated, but not a complex, thing. Not exactly the experience reported by most code reviewers I have met so far. (By the way, these days the word “complication” is still associated to watches, albeit meaning something entirely different.)
The Kubernetes-fueled microservices craze has everyone rewriting complicated monoliths into complex cloud-native apps. As my partner in crime Graham once famously wrote in his opus “OOP The Easy Way,” microservices is nothing but a new way to say object-orientation. Loosely-coupled entities communicating with each other with messages, anyone?
Simple entities sending messages to each other. Like living cells using mRNA to transfer protein pattern information from the DNA to the ribosome. Uncomplicated, minimalistic entities, used to build larger, more complex systems. Have we forgotten about that? Do we need to learn this over and over?
Software developers have a love / hate relationship with complicatedness, and an almost instant disdain for (if not outright ignorance of) complexity. Complicated systems are great to brag about on Reddit; maintainers also cry about them in private.
A “best practice” has one and only one basic job: to help engineers translate complicated into complex. Most software-related disasters are caused by a simple fact: because of deadlines, managers, tooling, or just plain ignorance, software developers have a tendency to build complicated, instead of complex, systems.
Let us write and run complex, not complicated, systems. We cannot get away from complexity; that is our job as engineers. But we can drop the complicated bit, and minimalism will follow.
Instead of running a 500 MB Docker container with Linux, Apache, PHP, and the full source code of that monolith written in 2002, let us instead run a 5 MB container built
FROM scratch running a microservice written with Go.
Instead of writing mobile apps with yet another hyped layer of abstraction, use the lower-level language recommended by the platform vendor, giving you direct access to the native APIs of the device, and a tighter control of the memory and CPU consumption of your app.
Instead of using yet another programming language several dozen abstraction layers away from the actual platform, let us go back down a bit, thanks to languages like Go, Rust, D, Crystal, or Elixir. Thanks to projects like LLVM, many high-level programming languages do not need need a runtime layer anymore, can be cross-compiled, and offer blazingly fast performance.
Instead of Emacs, let us try Joe’s Own Editor.
And after having launched it, let us write our own operating system with it.