How to get rid of legacy code
Posted: Nov 24, 2014
Most of the developers don't like to work with legacy code even when it was created by them. A good developer should grow. If you take a look at code which you wrote last year and you don't want to improve it, it is a sign that you didn't grow since that code was written. Is it good? If you want to be better, the answer is “No”.
I read a lot of articles describing how to work with legacy code, how to maintain it with tests and how to refactor it with different approaches. Some of the articles have been helping me a lot.
Let me give you my thoughts about this subject. It isn't about OOP or patterns, it is simpler.
When you have an old project, there are a few ways how you can deal with it.
Give up your current job
Sometimes people does that and it is ok. If you don't want to work on the project anymore, this decision will be good for you and the company you work for. But, maybe you don't have enough skills and experience to make it better, therefore you want to give up?!
Rewrite everything from scratch
It may work if the project isn't big. Otherwise, your boss might disagree with you and eventually you will have to continue working with the code you have now.
Even while rewriting a project from scratch, you cannot guarantee that it will be written well. It will be better, but after some amount of time, you will want to rewrite it from scratch again. Your boss won't allow you to do that again and again. Projects should make profit.
Refactor legacy code
You may spend a few hours per day on refactoring while working on new features. You may even apply some good approaches. It may work. If you choose this way, it is a good sign for your boss, because you want to be better and you want the project to be better. If you think about this way, you are an experienced developer. But, to be honest, this way is a difficult one when you work in a team. You do your best to improve code base of the project, but some teammates may not share your initiative or they aren't enough experienced to help you with that. As a result you refactor and improve one part of code, meantime some developers bring "dirty" into another part of code. It disappoints you, you aren't satisfied with your work. Eventually, you start thinking about giving up your current job, because, it cannot continue forever. If it isn't true for you and eventually your team helps you with this initiative, you are very lucky. But, most of the teams aren't like that. There are developers without good experience who bring shit into code.
No, I didn't forget about the code review. The code review is a good part of the development process, but you cannot control everything.
Each of us brings shit into a project due to limited time to fix a bug or deadline or misunderstanding of requirements or taking new approaches/libraries we aren't familiar with.
The process for this way will look similar to cleaning a house. You've cleaned the bath and now you need to clean the kitchen, you've cleaned the bedrooms, you need to clean hallways. You think: "ok, I can relax now", but noway, you have to start again, because your bathroom is already dirty.
Life is a spiral. Refactoring of code is the cleaning of a house.
Split your project on libraries/gems/whatever
This option is outcome from the previous one. Usually, when we create a project, there are a lot of typical things like some special flow to validate forms or handle errors from DB/external APIs. You may even code them as an internal library including a few classes. Once you have something like that, you need to start thinking of creating an external library. It may be a Ruby gem or a Node.js package or a Jquery plugin, it should not be an open-source library. You can launch your own repository for libraries. Maintenance of such libraries will take time or even extracting them from a project will take time, but the benefits are very strong for me:
- your libraries will have public API and it will be stable (you have to make sure it is). It means you can encapsulate all your shit into a library, but your public API will look good. Once you have time you can rewrite it from scratch, but your API should stay the same.
- Since it is a library you will have versions of it and history of changes. It will be very easy to spot when somebody adds shit into it.
- Those libraries can be reused in other projects.
- Your project will have only business rules, it means you can refactor code with less pain, because most of the code base will be in external libraries.
- Shit will be closed in specific libraries and it won't spread among the whole project.
I started using this approach. Because, I tried to refactor our code, but it was very difficult. Some people leave the company, new people join and you need again and again explain what you want to do with the code base and how. It will look like endless fight with teammates. Btw, you should not create those libraries on your own. Your teammates can help you with that (at least some of them). You may create a library to handle errors, some developer may create a library to deal with validation and so on. Even less experienced developers will do their best there. Because, it will be their "child". They want to proud of their work. Actually, it will help them to grow.
For the project I work on I've created 3 gems (2 them are open-source) and we got better code in our project. It isn't perfect, but it is better. Those gems brought standards to the project, it is another very strong benefit. If you have a library to validate data, you won't copy-past some stupid code (typical mistake of developers without experience) and change it for your case, you will try to reuse what you have or change the library to make it more flexible and work for your case. Libraries must be unleashed from a project.
Ask your developers which logic they want to extract from the project into a library and give them time. The result should be good.
Spit your project on services
It will be very easy to do after finishing the previous recommendation. SOA (Service oriented architecture) is a right way for evolution of a project, but to come up to such architecture you need time as well. This option includes all benefits from the previous one, but it has one additional strong benefit, it is an ability to exchange language for a service if a chosen language doesn't work anymore. If Ruby doesn't much your requirements, you can rewrite the service on Go. You can have dozen of services written on different languages.
Don't give up, if you see legacy code, choose a way to refactor it and work on it. Legacy code is a good challenge, you will be able to see mistakes of other developers and learn from them even if it is your code. Never say that your code is perfect, don't be satisfied with it (ok, you can, but it should not be longer than 10-15 mins :)).