In this article I present ten tricks in ascending order to you with which you can clean up your code and protect yourself from Legacy Code in the future. The goal is to have Clean Code and with that effective and sustainable software development. That’s good for you, for the team and everyone who deals with your software.
1. PHPStan – In the beginning there was the test
“Never touch a running system” – this piece of wisdom has caused us considerable problems. As did agile software development, which only has the narrow differentiation between features, bug fixes and tasks. A clean up is not part of the plan. That is most of all down to the risk associated with it.
Here, PHPStan helps us with two important factors: First of all, potential errors are detected reliably in the existing system using level 1 and 2. Should you be in the green here, you can attempt a light refactoring. With this I mainly mean a consistent code standard and the correct formatting of the code. PHPStan on level 2 is the basis for starting this kind of work. What’s brilliant about this static code analysis is the strong performance concerning speed. Additionally, a positive aspect is that no environment needs to be created for this. Which means it is immediately ready for use.
2. Code Standard – the basis for the team and Clean Code
There are known code standards, such as the PSR series. The best known and most widely used standard is the PSR-2-Code standard. The essential goal of using a code standard is to introduce a consistent style for the whole team. That defines for example how brackets are used, whether there is a break after the If-statement and of course whether spaces or tabs are being used. That sounds pretty basic at first but is in fact the first step that brings teams together and creates a certain passion for code.
This way people start to engage with the quality of the software and stop simply accepting the given thing and continuing it without care. Especially when it comes to legacy applications and at new beginnings it makes sense to introduce one’s own set of rules for developing, which is based on the PSR-2 standard. This way you can exclude certain rules or turn them into a warning. At the beginning this seems like a lot is being asked for. This is a chance to slowly acquaint with the situation as a team.
A PHP code standard can be executed with a command from the terminal and can be applied this way to files, folders and recursively to the src-folder. Here, the errors will be shown and usually can be fixed with the PHP code beautifier. That bears a very low risk – especially, if a static analysis with PHPStan – at least at level 1 – is done at the same time.
3. “Else”-part to the top – Clean Code is logical and readable
One clear goal is to continuously improve the code. Refactoring is necessary on a regular basis for new and existing code. So, it is not simply enough to bring bad code into the right format. Therefore, the question arises what to tackle next. Clearly, we don’t have PHPUnit tests running and neither the know-how nor the necessary experience to get this powerful and awesome tool to work just like that. And a renaming of method names, classes and really strong refactoring a very risky in this context.
Nobody is familiar with the entirety of the whole code and more and more questions surface. Who wrote what why and is it still useful anyways?
If-Else-Statements are a good place to start in this case. Those usually contain a big amount of duplicate lines of code and often only enable specific variables in a default state and deal with the exceptions. Exactly in this context it makes sense to bring the Else-part to the top. That way the code becomes more readable and everyone can see what is going on. Here, switch-statements and unnecessary if-else-constructs are to be reduced. Those increase the complexity of the code and make it extremely complicated. That means that in those cases debugging and every other types of work gets very complicated. Therefore, refactoring can be effective.
4. Refactor to method – the basis for PHPUnit tests
PHPUnit tests are important and could of course be introduced in the previous step already. Personally, I prefer cleaning up the biggest chaos beforehand. It is here that I develop an understanding of the application, which is then helpful for the test. The best-case-scenario is doing it in the same step. In order to work with unit-tests in this step it all needs to happen as quickly as possible. Real legacy code applications usually have long methods that operate many more things than they should. Also, there will be many dependencies, which can be opened there and then.
However, especially the if-else-statements from step 3 can be a good basis to finally start testing as you have clear conditions and real cases. With this there are three possible ways of application: At the beginning of each method parameters are being validated and you exit with a simple exception or a “return false”. This is a simple test, which unfortunately has no big potential to find bugs. The same usually constitutes the end of a method. The return value is dealt with accordingly.
In current PHP versions this can be solved a lot more elegantly by using type hints. However, the real potential for software development lies in the middle part. As you can depict real use cases in a business logic, you can create the basis for code refactoring. That goes a long way. Let me underline again at this point: all relevant and important lines of code must be covered by good testing as these hold the highest potential for cleaning up.
5. Names and conventions – the quality of software is a team effort
“Later equals never” – this quote from Uncle Bob still sums it up best. To adjust names of classes and methods later in the process is not a simple matter – despite the good support of PHPStorm for refactoring. methods can be referenced by a multitude of different touch points. And of course, also very often in PHPUnit tests. Therefore, it is crucial to make some clear decisions before creating a new class and the separate methods and to plan the development.
It might take some time to find a good name, which really describes the method. At this point conversing with the team can make a real difference. A joint planning brings new aspects to light and enables innovation as early as in this phase of the project. Also, knowledge is being shared among the developers this way and the project becomes more transparent. That prevents the dreaded “siloed knowledge” and allows developers to work more efficiently. The joint approach at this stage always doubles as a little internal education-workshop, in which knowledge is broadened and recessed.
6. Nobody moves, nobody gets hurt – Build pipelines also works without Docker
The necessary steps for a launch are known and the same. Unfortunately, they are also quite complex. That is precisely why people love to use Build Pipelines with Docker these days. Here, complete applications and servers are being deployed instead of files. However, this demands the right infrastructure as well as know-how. But all of that also works without a Docker. In the PHP-universe many successful tools exist.
“Deployer” for example is one of those. It also offers numerous recipes for known applications such as Symfony, TYPO3, Sulu, Magneto and many others. The technology the open source tool is based on is relatively simple. For a new release a folder with the new version serial is created. In this the necessary installation steps are executed and a symlink to the “current” folder is created. Also, there are universal shared folders, which contain files the application administers. Changes to the data base are the problem. In this case you can work directly with a migration. However, in case of a rollback this can lead to problems, nonetheless. But nobody should be scared off by that. To the contrary. Only by going into this direction can you even approach such problems, which would occur anyways.
It must be the goal to show and version the installation process as a unique software. This way the process becomes transparent and can of course be optimized. This way it becomes possible to enable releases with one command and important resources can work again and are spared from staring at loading bars. Automated processes are faster and can be executed at any time “just like that”. That way the development can progress. If you, however, have a manual rollout every other week, everything moves slowly and likely no passion or fun can be derived from the project.
7. Dependencies demand a lot of time and maintenance
Being dependent isn’t a good thing. That is true for life and software development. Today, unfortunately, too often libraries are being installed instead of – for example – formatting a date oneself. Of course, open source projects from GitHub are good and important. Even just the official Google API- packages in many of the programming languages are simply great. However, you should still handle them with caution, as every package needs to be updated constantly. That’s effort in itself. Bugfixes and security patches need to be added regularly. And that’s where the problems start – everyone who regularly works with Composer knows what I mean: As soon as you don’t attend to the projects for a while, you’re likely in trouble.
And it’s not just updates that need to be done, but also adjustments. And that can lead to a worst-case-scenario with big projects: you are barred from an update because some vendor-project isn’t cooperating. If you consider the amount of lines of code that end up on your to-do-list like that, you realize that the cost and use stand in no relation here. One big goal of the current software development is to precisely minimize such amounts of coding when refactoring. That can be understood easily when looking at the Symfony Flex approach. In the current version 5 it was an important goal to become slimmer. And that is also true for one’s own projects as well.
8. Type Casting for real types and Dependency Injection
The whole PHP community is happy about types. A big and important step in the current PHP7 version. For that alone skipping version 6 and the connected delay were worth it. By putting a type to the variables, the IDE, PHPStan and many other tools can point out errors to us even during the development. That helps to avoid them right away. By that we save a lot of time and can code more efficiently. Another great help is the dependency injection, which is a fixed part of Symfony and has also now been added to TYPO3. Here, we can also add the type as an annotation to the property and establish the dependency simply as a parameter of “injection” in the Constructor. That is quite convenient, professional and contemporary. We gain many advantages during PHPUnit tests. Generally, you can say that the consequent use of types is the one thing that enables innovation in software development. If you look at what TypeScript made possible for Angular, React, and VueJs, you quickly struggle to image a life without types and you don’t want to either.
9. Exception Handling instead of return false – clean is smart
The exception handling is currently being neglected in legacy applications. If you have a look at the logfiles of the applications, you’ll likely arrive at the conclusion that nobody has ever taken a look at these before. PHP is very error-tolerant – that has good and bad aspects. Good is that it constitutes a low bar for beginners and the relatively easy setup inspires many developers around the world to take first steps and build some webpages. However, at some point everyone reaches the point for self-improvement.
For this exception handling is a good first basis. But, even though a “try-catch” block is easy to code and provides a lot more information, usually people resort to a simple “return false” or even “@”. That means you either don’t have logging or no information. And that simply is a big problem, as you ruin a lot for yourself. But don’t fret, once you start checking your software with PHPStan and start relying on types, you have moved another step forward. And it also is easy to do.
10. Code reviews are important, plus help everyone and the team progress
Never Code Alone is so much more than a good T-Shirt quote, as software quality and – by the way also security – are a team effort. On the one hand it is clear that a small group has a hard time cleaning up a huge amount of code that is being produced with errors by a big group on a daily basis. Problems simply can only be solved when you work on the source and don’t just tinker with the symptoms. Working as a team helps with this as well as code reviews done by a second pair of human eyes.
Code reviews have to be introduced carefully. They mustn’t be seen as criticism or hurdle and mustn’t introduce unnecessary hierarchies to the team. The dialogue should be had on eye-level. In the beginning potentially with everyone together. Once everything is established and a common language was developed, Reviews can be done a-simultaneously and alone as well. It is important to use this chance and improve code and not simply react with “you could have done it this way” or “next time you had better…”. The code needs to be improved right away.
Conclusion: Clean Code in PHP projects
Clean Code vs laziness vs budget. The customer doesn’t pay for it and doesn’t want it either. It is really hard to fight for sustainable solutions. You can also observe this when it comes to topics such as climate change and your own health. But you can also see that with complex projects developments slows down when it comes to this and many aspects have to be disregarded. This way you are held back and it is impossible to work efficiently and effectively. Innovation and personal growth simply doesn’t happen. That is harmful for everyone and everything. Especially, as it can be avoided easily. Specifically, the static code-analysis is an easily applicable and reliable tool. When you invest time in software development, which would take longer in legacy code, the ROI is quickly achieved, and the money doesn’t have to be found anywhere either. legacy-code-applications simply are expensive. They demand a lot of communication, resources when it comes to developers and seldom are being deployed. That simply is unprofessional, and nobody is motivated to invest more or put more work into them. Therefore, you simply need to start with code refactoring and the get rid of the chaos. First steps can be taken quickly and are worth it. Once the know-how is established in the team it pretty much runs itself.