Us developers are fighting complexity all day long. Without pouring energy into keeping a system entropy low, any system will tend to get more disorganized and complex.

Low complexity is necessary to improve, maintain and enhance any system, hence we are trapped in an uncomfortable trade-off.

From one side we want to improve a system, add features, fix bugs, add integration. From the other side we wish to work with systems that are not complex yet and where is easy to make changes.

Embrance complexity

As often is the case, instead of fight an enemy, we are better off understanding it deeply and exploit it when is necessary or convenient.

In the successful project that I happen to follow, there is always a common pattern that I find useful to apply.

Complexity is at the same time vigorously fought and embraced with patience.

In those projects there are parts of the codebase where we keep think about re-structuring and re-factoring our code, we always try to keep the interfaces as small as possible and even trying to make then smaller. In those part we are almost afraid of if and conditions. Moreover everything is well documented and explained. We even explain what was tried and why it didn’t work.

While on other part of the project we just don’t care about complexity, when a problem arise usually the solution is to just add another if to check that yet another condition is checked.

Complexity as lubricant

The tricky part is to understand where complexity should be fought and where it should be embraced.

The more fundamental and algorithm heavy is the code, the less complexity we try to introduce. Indeed there is already the “inherent complexity” of the problem. This means force precise boundaries in the system.

We need to know extremely well the shape of our input, as well we need to understand very precisely what side effect our software will bring to the whole system.

On the other side, the more boring and tedious is the code, the more we can get away with adding some “incidental complexity”. One more if to check another condition is not going to make the code impossible to follow, maybe more tedious but not impossible.

These parts of the systems are usually the ones that prepare and shape the data for the more engineered part.

Indeed it helps me to consider complexity as a lubricant, motor oil, that is cheap, ugly, nasty and necessary to make the well engineered motor works without hiccups.

A reasonable compromise

If we could build a completely well engineered system, that would be ideal, unfortunately is too expensive for the majority of the cases. Hence we need to find a compromise.

The quicker the complexity of a part of the system increase given more features, the better is to have such part well engineered.

If adding a new features or fixing an incorrect behaviour on a nasty corner case means adding several checks to several condition in very different parts of the project, it means that the complexity is not scaling linearly in that part of the codebase, and probably, that part, should be re-engineered.



If handling another corner case, means to simply add one if then the complexity is scaling linearly and we can be cheaper on such part.

Follow Me Follow @siscia_