In Removing Static - There and Back Again post we tried looked at anti-patterns in legacy code from a new point of view. It can be static in your code, it can be active record pattern you needed for fast bootstrapping of your idea, it can be moving from the code in controllers to command bus.
They can be coupled in your code in hundreds of classes. That's a big problem, you might think, but it's only single pattern.
For pattern, refactoring is not important what I believe is the best or is considered general best practice (if such weak thing can even exist). I'm kicking myself in the nuts now, but I feel I have to write it.
No external consultant or blog post can give you a qualified answer on what to do with a code he or she saw for a few days. I mean, they can give you tip and qualified feedback, because they saw dozens of similar code bases, but in the end, it's up to you to do the experiment and verify it on your code base.
The best thing in the code is decided by the team, that works with the code every day.
Let's look at our use case inspired by the problems of the people around me. Imagine you have an active record pattern all over your code base. In 1 000 places, so it's easier to work with it:
<?php $product = Product::find(5); $product->name = 'Train Ticket'; $product->save();
This pattern helped you to grow your minimal viable product, deliver features, enjoy growth and make money. It was very useful to you at a certain time in the past. The same way it was useful to live with parents when we went to school.
Your company grew every year for last 5 years, with growing code bases and new modules you have more bugs with weak typing and you've decided to move to Doctrine and separate Entity and Repository.
The why is clear and the decision to change the codebase has been made. Now how do you refactor your 1000 places that use active record?
Before answering, keep in mind, that you have to explain these options to your boss (CEO, product owner...) because he or she cares about following in this order:
Well, your boss will probably not ask the last question, but I've added it just for the sake of our programming perception of the relationship of code and business.
How could the pitch for rewrite look like?
"The active record is coupled with everything, it's in controllers, in commands, and in services. Even if we change it in a single class, it will probably influence most of the rest code. After we rewrite adding features would be much easier, because we would not have to switch between the old and new code base. We know what we want and it would take less time in the end than any other solution."
Suddenly, your colleague comes. You don't like him, because he's too "smart", younger and has less experience than you (he's younger, how can he have more experience, right?) and he starts to argue:
"Rewrite from scratch is one of the things you should never do. Why? Because rewriting from scratch has a bad history of failures. Joel Spolsky, CEO, and co-founder of StackOverflow wrote Things You Should Never Do in 2000."
Joel hodling a ping pong paddles in black/white
Imagine you're the new CEO of your company. Would you go for rewrite after hearing this?
In my experience, every developer has to fuck-up one project by rewriting from scratch, to obtain this knowledge, so no article can help you if you're not there yet. Still, it's fun to read about failures of others.
Your ballsy colleague continues his pitch: It's much better to refactor as part of our coding. Only if we need it. If there is a new feature that affects, e.g. product object, we should refactor product to repository and entity. That way we can keep delivering features, we'll always have one code base that works and we don't have to split our attention for a month or potentially years.
Let's get to the questions that are in the position of CEO. The goal of the CEO is to keep the project running, make it grow in all fronts together. He or she will assess both options:
The CEO: "So we have to basically pay programmers to create the same set of features as we had before, but it will cost us 2 months of work whole team? And in the end, we'll have exactly the same set of features, but the code will be nicer for you to work with?"
The CEO: "If I understand this correctly, you say that our application will slowly transform into a new one, we can still add features, it will only take slightly longer. In the end, it might take 12-14 months, but we'll get there? And during those 12-14 months, you'll have to work with 2 approaches in the same code-base?"
"Well, both solutions are expensive and slow, but I slightly prefer..."
We forgot one big problem that both approaches suffer from.
The best way to assess code quality is to let junior to work with it and count WTFs. The less the better (WTFs, not juniors). Juniors are like kids, honest and creative by nature. They don't know what they shouldn't tell and shouldn't do, so they find solutions much quicker than most of the older people... or people that work with the code base for a very long time and suffer from conformity bias. That's why I enjoy meeting "less skilled" people because I can learn from them much more than from "the experts".
If the company growth is the main reason to refactor the code, so must expect to more PHP developers joining the project. Next new programmer coming to this code...
<?php // in one place $product = Product::find(5); $product->name = 'Train Ticket'; $product->save(); // in some other place $product = $this->productRepository->get(5); $product->changeName('Train Ticket'); $this->productRepository->save($product);
...would be probably confused:
And so on.
All this leads to moving focus from deep work and actually creating features to talking about meta-programming. You talk and answer and explain, but nothing in the code changes.
I've started to code new Lekarna.cz in 2015 on Nette from scratch (exactly!). First 5 months I was all alone, then a new programmer joined me. He started to code in the same quality as the previous code, I didn't have to teach him almost anything. I was curious:
I was so happy! Once I can write readable code, second the code doesn't depend on my expertise and I don't have to waste both our times in meta-programming and explaining what code should explain.
The code can be designed to either confuse people or to lead them. It's a matter of thoughtful decision to make code understandable first, then it's pretty easy.
How can we keep the attention focused, code understandable and also make CEO happy?
Do not focus on the code or on its size - that all is now just an implementation detail. Use the code that you and your colleagues build. Go for patterns:
-$product = Product::find(5); +$product = $this->productRepository->get(5); -$product->name = 'Train Ticket'; +$product->changeName('Train Ticket'); -$product->save(); +$this->productRepository->save($product);
There are many ways already:
Learn this minds set and tool kit - they will give you the power to move massive code bases with just a couple hours of preparation. Next time you'll be thinking of "rewrite vs. gradual refactoring", remember pattern refactoring. There probably already is an easier way behind the corner that will make happy both your and your CEO.
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!