tl;dr

If you’re refactoring something – do it iteratively.


Recently I was refactoring some code, it was time to pay off some debt. We have modular monolith and it appeared that one module was clearly a part of another, they just ping-ponged themselves all the time.

I was convinced that it was trivial. Communication from and to the module is done entirely via the module’s API. So it’s enough to move all files from the obsolete module to the other one and done. Right?

Well, it was true in 95%. The remaining 5% was doubled entities, repositories, and some DTOs. It needed more care as I had to choose and replace one version with another. 

It wasn’t too bad, it was like maybe 10 classes or so. But doing it at the same time AND having like 80 other files moved or edited in some way made it hard.

Well, this was not the first time when I saw that I cannot eat an elephant with a single bite. But I can in a couple!

I reverted all the changes (twice) and started from the beginning. At first, I replaced all API-API communication with using repositories, etc directly. Made a pull request, merged, done. One bite at a time.

The next ones were about choosing a doubled entity, merging functionalities, replacing a repository, etc. I did that 3 times. 3 more bites.

The final pull request was about moving the rest, entities, and others that weren’t doubled in any way and just needed a new home. The elephant is no more!

I think I didn’t learn anything new, but I remembered some lessons nonetheless:

  • start small
  • many small pull requests are always better than one huge
  • start with the hardest part, find pain points and remove them, then the rest is just a piece of cake

I cannot express enough how important was to have great continuous integration tools. Without PhpStan I wouldn’t spot obvious errors. Without PHPUnit tests, I’d be doomed. Without Behat tests I wouldn’t spot a huge bug that would be nearly impossible to spot later. And Deptrac. This tool allowed me to iteratively move classes, and use them between modules thanks to exceptions, etc. 

This is a story for another time though.