Dieser Artikel ist auch auf Deutsch verfügbar

A little anecdote

I remember a workshop in which my coworkers at the time and I were asked to build our perfect project startup out of Lego bricks. I can’t really remember what I built back then, but one of my coworkers built a deep, brown grave. When he was asked why he thought it was the perfect project for him, he answered: “If there aren’t a few bodies buried here and there, then I’m not needed.” So, I join a new project and first stumble into a six-foot-deep grave to feel around on the dark ground and see where the bodies are buried? A gruesome idea! For my coworker, this was the perfect way to start a software project.

What is legacy code?

As software developers, we are often confronted with code and software legacies in projects that are actually terrifying. By legacy code, I mean code with some quality defects that make the code very difficult to maintain and expand. Examples of quality defects, especially when it comes to technical debt, include missing or fragile tests, high complexity, strong coupling between components, meaningless names, and missing documentation. In worst case scenarios, the entire software system is a big ball of mud that makes it impossible to even guess what the originally designed architecture and structure was. To make matters worse, the software often uses outdated libraries, which are very difficult to update due to the strong interdependencies and lack of testing. This creates a breeding ground for security gaps and software vulnerabilities. Maintenance costs also increase immensely. Expansions are time-consuming and error-prone.

But we also need to consider another aspect: Legacy systems are not just inherited (technical) debt. They are usually also the result of tremendous expertise and sophisticated process flows poured into software over the years. They are often the core systems of a company that generate major revenues. Dylan Beattie expresses this circumstance very aptly with his definition of legacy code: “Code that’s too scary to update and too profitable to delete.” When you look at it this way, the big ball of mud is actually precious humus that provides rich returns.

How does legacy code come about?

There are many reasons why code becomes increasingly difficult to maintain over the years. It is almost natural that adding new functionality increases complexity, which in turn raises the level of clutter. This is especially true when a project needs to be completed quickly. Ivar Jacobson coined the term “software entropy” for this phenomenon back in 1992. I find an illustration by Carola Lilienthal from her book “Langlebige Software-Architekturen” (Durable software architectures) very impressive.

Fig. 1: Relationship between maintenance costs and technical debt, loosely based on Carola Lilienthal
Fig. 1: Relationship between maintenance costs and technical debt, loosely based on Carola Lilienthal

This illustration makes it very clear that active, continuous efforts are needed to keep technical debt low over a longer period. In addition to maintenance and expansion, the underlying architecture must also be actively adapted and improved on a regular basis. If this is not done, development costs will explode sooner or later. Lack of experience and time constraints accelerate the process of entropy. Good design, code reviews, and frequent refactoring are good measures to offset this phenomenon.

Technical debt is only indirectly visible to users and management. The lack of awareness means that necessary adjustments to the architecture and structure of the code as well as updates to the libraries are often not sufficiently prioritized.

In this article, however, I would like to focus on some human aspects that may exacerbate the problem. Mind you, these aspects also offer great potential for how we can handle legacy code better in the future. It’s about the personalities of developers as well as their preferences and motivations. It’s also about some prejudices and stereotypes that sometimes get in the way of legacy upgrades.

Nobody wants to deal with legacy code, right?

Actually, some people do! Contrary to many prejudices and the common stereotypes for software developers (besides the fact that people generally just think of male developers when that profession is mentioned), there are some people who don’t like to implement on greenfield sites. These people don’t always want to work with the latest technologies and don’t find it satisfying to build 80 percent solutions. My coworker could have used a green Lego base as a symbol for the perfect project start, if that’s something he would have wanted to.

To illustrate these differences, Andrea Goulet and M. Scott Ford have developed a model for different developer personalities in the form of a four-field matrix.

Fig. 2: Four-field matrix for various application areas for different personalities of software developers according to M. Scott Ford
Fig. 2: Four-field matrix for various application areas for different personalities of software developers according to M. Scott Ford

They divide the field of software developers into two dimensions: On the horizontal axis, they differentiate between hackers and crafters. In other words, they differentiate between personalities who want to do something very quickly versus those who want to do something meticulously. Vertically, they distinguish between makers, who want to create something new, and menders, whose passion is to improve existing software, adapt structures, and identify errors. People with crafter and mender preferences are assigned to the software remodeler quadrant. These people would be exceptionally suited to working with legacy code. Based on this insight, Andrea Goulet and M. Scott Ford founded a company a few years ago that specializes in upgrading legacy systems.

Of course, this is a very simplistic model for a much more complex world. But let’s take a closer look at typical situations from our day-to-day work: We are often inclined to simply categorize developers by technology and pick appropriate projects accordingly: “Do you do frontend or backend? Java or Python?” Implicitly, we assume that these are the most important and biggest differentiators. But we forget that technologies are merely acquired knowledge that can quickly become outdated or be expanded. My inner core values and personality traits, on the other hand, are largely stable in adulthood. In a job interview, we should ask this question: “Are you a mender or a maker? Do you feel more comfortable in the rapid response team or do you prefer restructuring the software system?” Even job advertisements often do not specify which character traits are preferred.

Based on the way we think of the term legacy code today, hardly any developer would proclaim “I like legacy code!”. In all likelihood, the menders, the people tasked with fixing the code, are probably more horrified when they are confronted with legacy code. Nobody wants complicated and outdated software. But while some people prefer to run away from it and suggest redevelopment, others are motivated to clean up and improve code.

Software remodeling is not an easy task, especially if it has been neglected for a long time. Working with large legacy systems requires a prudent and structured approach, along with profound aptitude and a lot of experience. It goes without saying that major upgrades also usually take a long time. This is likely not the job for which you were prepared during your studies. So, if this type of work lays such a solid foundation for continuous development, why is it so unpopular in our development world?

Where is the appreciation?

I already explained that there is much more to software development than just developing new features. This is especially true if the software needs to meet the challenges of the market for a few years at a reasonable cost (see Figure 1). In a comprehensive study of 334 IT decision-makers on the topic of legacy upgrading, 57% of the surveyed companies rated upgrading their essential business legacy systems as important or very important. Nonetheless, this type of work still receives very little attention and appreciation in projects beyond adding new features. I have often tried to work through the list of bugs and technical debts in the backlog as unobtrusively as possible, as they were never prioritized enough to make it into the sprint backlog. I can’t stand to see how my daily work creates more and more technical debt.

As a software developer, it is off-putting to openly position yourself as a mender. When your main task is to maintain systems, it’s safe to assume that you will get less attention and appreciation from managers. But the same holds true for job interviews. Many developers rightly fear that their chances are diminished if they are unfamiliar with the latest technologies or if they have worked with a narrower range of technologies due to long project durations. As Stefan Tilkov stated in the publication of the aforementioned study on legacy upgrading: “New employees are often reluctant to get involved in a proprietary environment that has been abandoned, because they fear it will ruin their CV.” On the other hand, there are also younger people nowadays who want to do “meaningful” things and contribute to the success of the company. Technologies are not an end in themselves. They are a means to appropriately implement a business model. That’s why we need to stop looking at the latest trends and technologies with the sole purpose of being able to show them off like trophies on our CVs.

The popular image of the software developer as a maker also ensures that people with mender qualities consider themselves to be deficient, perhaps even unqualified. The stereotypes misguide people to deny their mender qualities. Even the way developers are offered projects reveals which projects are considered to be cool and exciting versus the ones that are more likely to be pitied. Software remodeling also usually plays a subordinate role at development conferences.

I really like the term “software remodeler” in Andrea Goulet and M. Scott Ford’s model because, in my humble opinion, it represents a neutral position between the other three roles. Despite all the intrinsic motivation, without extrinsic incentives, we run the risk of losing some of the menders we urgently need.

Make targeted use of diversity!

When you are staffing a development team, it is also worth paying attention to people’s inner drives to ensure a suitable ratio of menders and makers in the team. If staffing is done properly, there is a good chance that a self-organized development team will appropriately prioritize adding new features while simultaneously reducing technical debt. Of course, every developer can also be assigned to activities outside their comfort zone from time to time. However, if it becomes the rule, we are wasting valuable potential.

The following variation of the four-field matrix introduced above can help you assemble the right team for the respective project.

Fig. 3: Correlation between the personalities of software developers and success factors
Fig. 3: Correlation between the personalities of software developers and success factors

The illustration establishes a link between the familiar personalities of software developers and four attributes that can have a major impact on the success of a software product. Is speed a key success factor for the project? Then you need developers who can quickly come up with effective and pragmatic solutions. Other contexts require a far more risk-averse development style. Projects that are designed for longevity and high quality benefit from developers who develop solutions meticulously and persistently. People who describe themselves as crafters often find it difficult to work efficiently under time constraints, while hacker personalities often struggle to stay on task beyond the 80 percent solution. Does the project revolve around tapping into new customer segments with innovations, or is it aimed at improving well-established features and meeting the stability requirements of existing customers with a reliable product? There are certainly no black and white answers here. Most of the time, our products require all four attributes with different prioritizations. The only way we can cover all areas is with a diverse team. All the personalities in the team can learn from the different work styles and find the right balance for the respective product through appropriate discourse.

The evolution of software products adds another aspect: Generally, the priority levels of the four success factors for a software product shift over time. In the beginning, it is typically about bringing a new product to market as quickly as possible in order to obtain early feedback and test the business idea. I learned a long time ago that it is not a good idea in this phase to have too many people in the team who are passionate about software remodeling. Speed and the courage to fail are more important here than elaborate architectures. Once the product is on the market, it is important to expand the range of features in order to attract customers. But even in this phase it is necessary not to lose sight of quality, which is why it’s advisable to add mender personalities to the team. Even if our software is facing a major upgrade project a few years later, it certainly makes sense to simultaneously continue to provide the customer base with enhancements and innovations. The balanced mix makes all the difference here. And it makes perfect sense to adapt the team configuration to changing priorities.

Teams that successfully launched a new software product often fail a few months after the market launch. Rapid repairs and enhancements lead to a rapid increase in maintenance costs. An attempt to get the problem under control with the same team often results in a completely new development, not because it is the most sensible decision at this point, but because starting over lines up with the inclinations and skills of the developers.

Therefore, a well-balanced team consisting of the right amount of makers, crafters, menders, and hackers at the respective evolutionary point of the software development is a make-or-break aspect of ensuring the longevity of the software.

Conclusion

With the right team configuration and sufficient appreciation for code quality and architectural evolution, valuable legacy systems can be successfully upgraded. At the same time, the emergence of a terrifying big ball of mud can be avoided.

So, put on your mud pants and go!