A redditor asked the following question:

Question#

I am a scrum master for a feature team working with a fairly large SaaS software system. The majority of the system is written in an old framework as a monolith, and we are continiously migrating the system towards microservices in a more modern stack. The business logic in the old part of the system is extremely complicated, and since we lack both documentation and unit tests for that part of the code, there is basically nothing telling how it is supposed to work.

I have been talking with our product owner, and been trying to explain that when we migrate this functionality we need to figure out how to cover all of this business logic with requirements and acceptance criteria to be able to implement the functionality properly in a way we understand how it actually works, and use the acceptance criteria to cover the most important cases with unit and integration tests. However, I get pushback from the product owner who does not think this is their job, but rather wishes to push the specifics towards architects and developers to figure out what different cases there are based on the legacy code (basically by reverse engineering), and base the new implementation on that, while being there as a support if questions arises.

What would be your stance in this situation?

My answer#

I think it’s the whole team’s job, but mainly the developers’, because it’s a technical problem to solve. As far as I know, there is no documentation and no tests. So we can assume that the best documentation you have is the source code of the old system. You need to learn how the system works while trying to make some changes.

There are a few approaches. I have a few quick ideas at the moment, and there are probably more good solutions out there:

  • Write high-level tests in the old system, then refactor it by creating a module in the old system that can be extracted into a new system. After extracting the new service, improve the quality, upgrade libraries, language, so on.
  • Start writing a new system that runs in parallel with the old one. Implement a use case in a new system, start using it in production, but still use the output of the old system. Validate your assumptions and ideas using production data before you switch. This method also requires changes to the old system.
  • Build a new system that will proxy all requests to the old system. Gradually start moving all the required features to the new system. Compare the results of the two systems using production data before you switch. You can also consider sharing databases for some time or using CDC.

There is a great book about refactoring patterns from a monolith to microservices: “Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith” by Sam Newman. It starts with the chapter on why you should do it 😉 I highly recommend it.