How to avoid fragile code

How to avoid fragile code

[[165073]]

The most common problem with legacy code is fragility. It is extremely painful for teams to modify a brittle codebase. In our 10 years of developing products at ThoughtWorks, we have learned some hard lessons as we try to keep our large codebase scalable year after year. In this article, I want to share the lessons we learned from the most challenging times. Disclaimer: I write these thoughts, but I don't think we have solved all the problems. We still share the pain of legacy code, and like other teams, we work hard every day to make it better.

Update everything, keep updating

You should always be eager to update your dependencies and frameworks. Well, maybe it's a common understanding now. But 10 years ago, few people thought this way. Some teams understand that upgrading is the right thing to do, I just doubt whether they really prioritize it. It always needs to be taken seriously and not put off until the end, turning into technical debt. Here are the reasons:

  • If a task is a pain, do it often. One of the most obvious reasons to always upgrade is that it can be hard. There are often unexpected, broken dependencies. The amount of work is often unknown. Do it often, and it stops being a problem. But there are more important reasons than simply avoiding pain.

  • Another driver for upgrading dependencies is fixing security vulnerabilities. One of the biggest differences between developing software now and 10 years ago is that there seems to be a constant flow of vulnerability reports to our repositories, frameworks, and applications. Fixing vulnerabilities almost always involves upgrading some dependencies. In order to fix vulnerabilities quickly, upgrades must be easy to perform.

  • Teams that don't regularly upgrade their operations often label it as technical debt. Although the industry is more willing to talk about technical debt than it was 10 years ago, convincing project managers to pay off technical debt is still a very difficult conversation. If your team is in "upgrade everything all the time mode", you don't need to have a conversation about upgrading technical debt.

About Unit Testing

The main pain point of legacy code is how long it takes to make changes. If you plan to keep your code running for a long time, you need to ensure that future programmers who modify it are completely happy. There is one way to take advantage: an extremely fast and thorough unit test suite.

The cycle of adding new features, including any code refactoring, can be roughly described as: write a failing test; write code; show green; done. If you do this, you will always execute a large number of unit tests, sometimes a specific set of tests, sometimes the entire suite. If the tests are not fast, the development cycle will not be easy. The experience of writing code should not be: make a few changes, and then have to sit and wait 10 or 20 minutes to run the tests. Too bad.

Making sure your test suite runs fast isn't just about your design and code. Sure, you can do a lot to speed up your tests, like avoiding files, databases, sockets, huge object graphs, etc. But there's another important trick, picking frameworks and languages ​​that help speed up your tests. If you find yourself changing your framework to make your tests faster, then you need to consider a different framework. Yes, when I was developing a traditional multi-page application, I wouldn't be developing it in Rails the next time.

You also need to consider the size of your application. When a code base reaches a certain size, you need to plan a split plan. This is also the only way for you to fully understand a piece of code. Finding the entry point for splitting a project is different from academic work. You need to invest a lot of time to tossing code, studying various places, redesigning, and refactoring. Having a fast test suite to quickly verify your work will make this work several orders of magnitude easier.

Actually, "several orders of magnitude" is more of an exaggeration. If you need to shard a large codebase and have a painfully slow unit test suite, well, you're probably stuck. We're learning this the hard way. So do your best to make sure your unit tests are fast and run as a single thread on your development machine.

Branching by abstraction should not be the norm

Long-running products have experienced many technical leaders. Some types of technical leaders, as soon as they take over, complain about the shortcomings of the existing products and want to develop new products immediately. This is correct. Trendy technology is not always bad. For a long-standing code base, it needs new vitality to generate enough energy to eliminate the incompetent parts. I want to mention two important points.

New technical leaders should not dismiss any technology before working with the team for two to three months. There are too many scenarios to understand. New technical leaders need to learn to think from the perspective of the team and the code base. The team and technical leader need to build trust and rhythm. Staying for a short time is for better decisions.

Leveraging branching by abstraction is the classic way to replace new technologies (aside from the absurdity of long-lived branches):

  • Put an abstraction in front of component X.

  • Component Y is introduced as a replacement for X.

  • The abstraction intelligently routes to X or Y.

  • X is gradually being abandoned.

  • X is removed; perhaps the abstraction is removed as well.

There have been many times where I have not seen this process through to completion because removing the last 20% of the old components was too hard. You can't imagine how painful it is to do this in multiple ways year after year. It slows down everything and is demoralizing. Branch by abstraction is an excellent pattern and the only way I have approached this kind of component replacement. However, it requires full commitment from the team to retire the old components within a certain time frame.

Technical Debt Will Kill You

Just because we talk a lot about technical debt here doesn't guarantee that it will be paid off. One thing is for sure, letting technical debt pile up will only make it unpayable. It's easy to say, "Let it sit for now. Let's do some other urgent thing first, it's been noted, we'll come back to it." At the same time, it may be a wise decision. However, those so-called urgent things will never end. The urgent list will only get longer and longer.

The situation will get worse. In my experience, when the technical debt backlog grows too frequently, the team will tend to give up paying it back, the team will be frustrated, the developers will not achieve flow, and the business will not get new value. I have done some thinking about how to avoid insurmountable technical debt.

A good development team will not use technical debt as an excuse over and over again. When the team realizes that the same technical debt is recurring, it must move forward and quickly integrate it into daily work.

My colleague Badri suggests that the team must agree on a shared responsibility for technical debt. No one person has the right to make the codebase worse and have the entire team pay for it later.

More importantly, technical leaders and product leaders need to trust each other. Neither side should play the "I have the final say" game. Good technical leaders understand the priorities of the business, and good product managers value the value that can be delivered. Both sides need to discuss risks, costs, and benefits. If you can't deliver, your technical debt becomes a business problem, which is not good for everyone.

Clearly, there is a lot of work that a team has to do to write code that lives on for the long term: write code for the people who read it, don't be too smart, and always think about your future colleagues. I'd love to hear your thoughts.

<<:  Talking about execution ability from Zhihu

>>:  Google Android may adopt Apple's Swift programming language: avoiding the Java pitfall?

Recommend

9 Tips to Improve YouTube Video Marketing Rankings

YouTube is often a powerful tool used by sellers ...

6 truths about Taobao short videos!

Double Eleven is coming soon, and Taobao is makin...

Microsoft copied more OS X gestures in Windows 10

According to a report by The Verge, a Windows 10 ...

Wild Milk Jelly iPad Illustration Class 2020 [HD Quality]

Wild Milk Jelly iPad Illustration Class 2020 [HD ...

"How to choose a good project for SEO entrepreneurship? 》

The following is a transcript of Mr. Hu Yong’s sp...

Tips for writing Douyin scripts

TikTok short video sales have become a new force ...

How to design a good consumer-oriented App product

This article is a product sharing article, mainly...

Spodoptera exigua: What I hate most is people calling me a “caterpillar”!

When the larvae of the spiral moth sprout, you ca...