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:
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):
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?
YouTube is often a powerful tool used by sellers ...
Double Eleven is coming soon, and Taobao is makin...
With the advent of the smartphone era, in additio...
According to a report by The Verge, a Windows 10 ...
The e-commerce industry is indeed the hottest ind...
Apple announced today that the App Store broke a ...
The growth rate of China's medical technology...
Wild Milk Jelly iPad Illustration Class 2020 [HD ...
The following is a transcript of Mr. Hu Yong’s sp...
The word "China" refers to both China a...
Among the world's three major mobile operatin...
TikTok short video sales have become a new force ...
This article is a product sharing article, mainly...
When the larvae of the spiral moth sprout, you ca...