A photo by me on Unsplash
Making sure your project is nice and tidy will eliminate a world of problems which you do not have to solve.
We as developers have the tendency to solve (and create) problems even when there is none. Most of the times though, you are so overwhelmed by the problems within the project that you quickly learn to ignore them and accept the status quo. In my opinion, this has the tendency to downgrade you as a developer and make you accept things that are below your standards. Something rubs me the wrong way when the code has a bunch of these things that you have to keep up with daily. It basically goes against the things you believe in, and against the things you stand for.
This is a story of how I eliminated a lot of problems within a legacy project and what I learned from it.
Recently, I have been working on a project that is around for several years. It is an inherited project and more than one team has worked on it at the same time. A lot of developers have come and gone during its lifetime. It looks like every new developer added his/her own view of how the things should be handled there. Even though there are some guidelines and a lot of documentation (mostly outdated), things looked largely out of place and out of any standard.
With all of this in mind the project was in a state where the simplest deploy to the DEV environment took around 30 minutes. Not that bad as I have had even worse. Tools like SonarQube which should help you with analyzing your code are basically impossible to add. Developer experience is also very very bad. Linting was there, but the rules were largely overwriting each other. Formatting code was not that easy. Webpack configuration is so complex, etc... You can imagine that a project like this is hard to maintain and hard to update. All of this being said, it is clear that there is a lot of technical debt.
Apart from all of these problems, there was this notion of legacy and inheritance that I had to live with for some time. Around 90% of the code was not really used for the use cases I tried to cover. So, I had to deal with a lot of cognitive complexity for no apparent reason. After forking the repository to be used only for the team I am on, the cleanup was basically inevitable.
I won't go into the details of what exactly I did as it was just folders/files deletion. Instead, I will just give you raw numbers of before/after and the approach I took to make sure the app will still be running after I delete a bunch of code.
The approach I took consisted of three iteration phases. The first iteration deleted big groups of folders which are clearly not used. The second iteration deleted all the files that are clearly not used. The third iteration (which I decided to skip due to lack of time) would delete all the unnecessary helper functions and anything else that is unused within the files that are left. This approach was largely influenced by Peter Kofler (aka Code Cop), thank you for the support Peter. Of course, I had some simple (manual) UI tests setup which I can do in approximately 20 seconds to confirm I did not break anything. After each deletion I had performed these tests as well as some NPM scripts before committing the code and building on the DEV system.
Don't be afraid to break things. The project is in such a bad state and everything seems to be hanging by a thread that whatever I do, I can not make it worse.
Just do it. I wanted to do this cleanup weeks after I joined. As soon as I got the hang of what this project is about and what it consists of it was clear to me that we need to simplify a lot of things.
Remove code iteratively(folders, files, methods). I know now how I would go about a similar thing. There is no point in trying to do one small thing and see whether that won't break anything. Tear down whole buildings of code and see whether your application still works.
Deploy often. This one saved me a couple of times. After each folder (or a group of files) deletion I reran my UI tests and some NPM scripts. Once those pass, I just committed the code and triggered the CI/CD pipelines to make sure nothing is messed up between the local and the DEV environment. A couple of times I was able to catch errors on the DEV system and revert back my changes or modify them for the next build. Thank GOD that GIT exists... 🙏
Fix the broken windows. This one is a more philosophical one. You know that story, if you have one broken window on your factory and you do not fix it for some time, it is just a matter of time before all your windows will be broken. You could use another metaphor. For example, if you do not fix the hole in your boat, soon you will have more. Your boat will start to sink quicker and quicker. This comes back to what I said in the intro about downgrading yourself and lowering your coding standards. Long story short, do NOT allow that.
In hindsight, this removal of unused code did not fix all the problems with this legacy project. However, it removed a lot of them. Moreover, it opened up other possibilities for improvement (updating dependencies, adding TypeScript, adding new ES features, etc...). I hope this short story showed you why you should not get into a similar situation on your projects. In my opinion, developers should always strive to keep the quality of the code they work with every day. There will always be deadlines and other priorities, but your job as a developer is to advocate and do the dirty work of making sure your project is maintainable.
I do not like to brag, but I think that lowering the CI/CD pipeline by half is a major achievement. All of that just by removing the stuff that is not needed. No other speed optimizations have been done yet.
Another thing I am taking from this whole cleanup is the way to quickly evaluate what is the state of the project (legacy wise). Look at the CI/CD times and check what is outside of your control, and what are the things that are just too slow. Check how many TODO comments there are in the whole repo. Another metric you can check is how many lint warnings, or how many console warnings/errors there are (both in NODE and in the browser). The last thing I would check is how many outdated dependencies there are and how old are they. 📃
Have you ever had to do the similar thing? What was your approach? I would love to hear your experiences. Shoot me an email below.
Dejan Kostevski is a self-taught Web Developer. His mission is to explain things in a simple but understandable way. During the years he has helped several Junior Developers kick start their careers, land an internship or a job or just in general get over the coding hurdle that they encountered.