The Human Cost of Messy Code

Adrian Booth
Palatinate Tech
Published in
7 min readJan 7, 2018

--

A common misconception we have as developers is that the consequences of bad code are contained to only our department. We are the ones who have to wrestle with the beast; we are the ones who suffer when our innocent little change appears to break a whole swathe of integration tests. The rest of the business is ignorant of the horrible mess that’s brewing deep inside our legacy systems. They get a wonderful feature, unbeknownst to the dark reality lying beneath it all. In truth, this isn’t really the case.

I‘ve recently been reading through “Becoming a Better Programmer: A Handbook for People Who Care About Code” by Pete Goodliffe. One chapter that stood out was his descriptive (and tragically hilarious) chapter on “A Tale of Two Systems”, where he walks through the development of two projects he’d worked on in the past; one with a careful, considerate and thoughtful approach to the design of the code, both from an architectural standpoint and on a micro level. The other was your typical legacy system, that had grown “organically” in a company where delays were intolerable (“The Messy Metropolis”). No single person had stood up and imposed a sane design on the code, because why bother? The code was already a mess, and developer turnover was high. The incentive was there to please managers and ship feature after feature, not to take some time out to reflect on missing abstractions and potentially shared functionality.

The Messy Metropolis, as he refers to it, had a number of problems with it.

Lack of Cohesion

There was no clear pattern for where system components belonged. To track down a piece of functionality, a developer would be performing the equivalent of surgery on an alien life form. Where’s the heart? Is this a brain? How critical is this organ? Both functionality and data were sprayed all over the code, with no unifying approach to tie them together.

The lack of cohesion in the code turned out to be reflective of the lack of cohesion within the team itself. Goodliffe explains that there had been “personality struggles in the original team, and so a few key programmers had begun to build their own little software empires”. Logic that should have been performed at the core was being placed in satellite modules that were difficult to reason about in the context of the whole application. An important lesson that Goodliffe teaches is that the health of the working relationships in the team will directly impact the health of the software.

Code problems at the micro level

Neglect at the high level of the code will typically seep into lines at the micro level. In the Messy Metropolis there was no consistent naming, no common coding standards and a whole concoction of various coding styles that would send any linter into a tail spin. Goodliffe complains that “There was not even a common build system; duct tape, shell scripts, and Perl glue nestled alongside makefiles and Visual Studio project files. Compiling this monster was considered a rite of passage!”

The main lesson here was that a lack of thought into the high level design of the software can lead to an incomprehensible mess at the low level. Much like a city that undergoes no planning, with badly planned roads causing a build up in traffic, a messy and inconsistent architecture begets a messy and inconsistent code base.

Problems outside the code

My favourite part in this chapter was the least obvious, but probably the most important. As I said in the beginning, it’s easy to reason about the effects of a bad design when it comes to the code. We work with code every day, and we know the pain of wrestling with code that isn’t on our side. We understand the toil and hardship of reasoning about a system that has no reasoning behind it. But the most overlooked aspect of all this is the impact on relationships with other people; mainly stakeholders.

In the Messy Metropolis, staff turnover was high. Developers came onto the project stunned by the horrid complexity and inability to get simple things done. The low morale and high stress levels induced by the rigid codebase caused a continuous revolving door of developers, which compounded the problem even more.

Slow development cycles were the norm, with features taking an unpredictable length of time. Stakeholders were often left waiting, with no clues as to when something would be ready. The inability to estimate sensibly meant the business couldn’t plan effectively. This brewed tension between the Tech team and the company management. The Sales and Marketing team lost trust in the developers. Credibility was lost from the Product team, who were waiting on a feature to allow customers to select their latest range of online offers. The costs of a toxic codebase are not just felt in the development team, they’re felt company wide.

Lynne Tye has performed interesting surveys of software developers, and asked the question “What do developers want from a job?”. Work flexibility scored highly, with “Work/Life Balance, Remote-Ok and Flexible Work Arrangements” being amongst the most valued. But unrelated to those was a “High-Quality Code Base”. It’s clear why a codebase of low quality can significantly impact a developers’ satisfaction with the job. A tense relationship with stakeholders, a low sense of morale at being incapable of delivering simple features in a timely manner. Given how much it costs to actually hire new developers, companies should be aiming to keep their staff turnover as low as possible. A high quality code base can reduce a lot of the hidden costs of hiring.

On to Design Town

Goodliffe contrasts his experience with the Messy Metropolis with a project he calls “Design Town”.

“Decisions about some of the basic housekeeping concerns were made early to ensure that the code would grow easily and cohesively: the top-level file structure, how we’d name things, a “house” presentation style with common coding idioms, the choice of unit test framework, and the supporting infrastructure.”

Having a well thought out design and architecture allowed the team to progress forward with no road blocks. Functionality was easily traceable, and adding new features was as simple as “slotting in” the required lines of code to get something working.

A template was formed which required little cognitive effort on behalf of the developers, and allowed progress to run smoothly. The codebase was uniform and consistent. It had structure and elegance. It had beauty and aesthetics. There were no alien lifeforms mutating across the code; every line made sense in its’ context and, like a family of functionality, had a sense of belonging.

Estimating how long a feature would take proved trivial, as adding similar features in the codebase took approximately the same amount of time. Relationships with stakeholders flourished, and developers remained within the company for a long duration. Why leave when they’re blessed with such a wonderful codebase to work in.

After reading through this chapter I started to think of the systems I’ve worked on at Palatinate Tech, and which category they fall into. Our current project, Neptune, matches Design Town to a tee. On-boarding a new developer involves a seamless integration, with a fully Dockerized development environment. Clone the repo, run a single command and you’re good to go.

Explaining the overall architecture is child’s play, and after 30 minutes of running through the code a developer can start adding value right away. There’s no funny business, or tricky corners to navigate in the code. A pattern is established, with a consistent high level architecture to accompany a uniform styling at the micro level. Rubocop, ESlint and Golint enforce a disciplined sense of order to the codebase, erasing any styling inconsistencies that might slip in.

Adding a new feature usually involves slotting in very similar code to its’ appropriate place and making a pull request. Due to its’ consistency, it’s very easy to spot when something is out of place, or when a line of code is added to a file it doesn’t belong to.

Admittedly I only learned the importance of these lessons recently. I always knew “clean code” was what we should strive for, but I never properly thought through the implications of having messy code, other than it’s harder to work with. I’m just as guilty of “cowboy coding”, as the dopamine rush from getting a feature out is often too tempting to resist. I’m learning that the best developers place their focus on the less glamorous side of software development. They take on the role of a janitor, cleaning up the mess and refactoring where necessary. Maintainability first, features second. Deadlines be damned.

The human cost of software riddled with code sins and design warts has large implications for a business that could last for years. Paying a cost up front to ensure that doesn’t happen is a price worth paying.

--

--