Yes, legacy code it can be a good thing to have, but you need to do something about it or you’ll pay the price.
Well, this is not new in our industry. A polite number could it be 50% of companies running a project today has a huge legacy system in some framework they’ve choose at some point in the past when the company was trying to validate an idea.
Legacy code as a good sign
If you have a legacy problem, in general, means you grew up. Your current situation reflects you need to do something about your systems or you will pay a high price patching it and creating more problems than solutions.
There’re many discussions saying you should start as a monolithic application and move to more complex solutions like micro-services; but this is not the focus of this post. For now, we’ll focus how to attack your legacy situation.
Don’t cover the sun with your hand
The first step to fix something is to recognize its a problem. This means you have to stop lying about it. If you’re not saying you have a legacy system that you need to fix, people will assume you have a healthy system and they’ll be coding on top of a problem.
Put time to improve your solution
No, the code you have is not perfect. You have a solution designed for the problem you identified some time ago and now that solution does not work as you need, this is why you have a legacy situation.
If you believe you’ll create code that can work over time, that means your business is not growing. All business changes over time, sometimes for internal factors and/or sometimes for external, and your solution should change or evolve with it
If you don’t evolve and react with your business changes, one of those two things will fail over time, or the business wont be a business some point in the future or your solution wont be a solution for that business in the future.
A few smells to identify you have a legacy problem
- any change is a hell because you have a domino effect (coupling issue)
- you cant scale one part of the system individually (coupling issue)
- parts of the system are duplicated all over the code (duplication)
- you’ve only one way to do something (monolithic)
- you need to mock/stub too many things to test a small part of the code (coupling)
any change is a hell because you have a domino effect
This is one of the most common problems. Anytime you want to change something you end modifying so many files that your five minutes change ends in days of works.
you cant scale part of the system individually
If I need to increase twice the number of the emails on my service I do not need to put two times my servers for the entire application, I only need to scale that service. If I need to improve my response time to my users, I need to improve cache, FE elements, etc.
I need to be able to scale small portions of my solution.
parts of the system are duplicated all over the code
This is tricky, and is tricky because the common idea of this problem is when we have the "same" code on more than one place, the copy-paste situation. If you have this problem you shouldn’t be called a "programmer", you should have a shame t-shirt with some legend about it.
This problem is when you have a library (gems on ruby, packages on npm) to "encapsulate" a solution but that library has too many things and you only use a very small portion of that library in one system and a different portion in another. The common problem you’ll have with is when you change things on this libraries and many systems will be affected, even when those systems does not use any of that change in particular.
you’ve only one way to do something
The common example is on monolithic apps where you only use one shared database, only one language, only one way to communicate different parts of your app.
You should be able to create solutions using any combination of tools, without any restrictions and always selecting the best tools to solve your problem.
you need to mock/stub too many things to test a small part of the code
One of the biggest problems to maintain a good testing coverage is how difficult is to create/maintain your test.
A key detail on this is if you need to mock/stub 99% of your system only to test an attribute in a model. Your code should be decoupled enoufht to mock/stub just a few thing to run your test. If this is not your case you need to improve your code to achieve it.
This is only an introduction to this topic and my goal on this lines is to create the necessary context for future posts to discuss solutions and a general approach to implement different solutions. Part of this future discussions involves decoupling techniques, monolithic / micro-service isolation, single responsibility, etc.