We are continually trying to improve our code base, and not just by adding new features, but by going back to our core code and increasing the quality. We do this not only to reduce our technical debt but also because it makes the code more legible, it gives us a chance to review the code base and can yield performance benefits.
Here are just a few of the ways we have been using to improve our code base:
1. Multiple static analyzers
We use a few different static analyzers to comb through our code base and help us find improvements including: PMD, FindBugs, CheckStyle and the built-in analyzers for NetBeans and IntelliJ IDEA. The analyzers all have different rules and we found some rules more useful than others so only look at rules we think will provide substantial benefits and start improving the code from there.
2. Using new Java constructs
In April 2017 we moved the majority of our modules to Java 8 from Java 6, which brought along opportunities for us to update our code base to use some newer constructs. For example, not only can we use lambdas now but also the java.nio classes which can replace some of the old java.io functionality and try-with-resources statements.
3. Refactoring out complexity
Complex methods and classes can actually cause performance penalties if the JVM cannot break them down and optimize them. To combat this we have been shortening long methods into multiple smaller methods, getting rid of return values on methods where the values were never used, and generally refactoring code so that it is simpler to understand.
4. Stricter Compliance
Ambiguous instructions can lead to disastrous results (especially in cooking but that might just be me) so we have been looking to make our code easier to understand. To do this we have been adding parameterised values to our collections so that the needed types are explicit and also making collections un-modifiable when we do not want certain actions performed on them like add, remove or clear.
Furthermore, we have been making access weaker for classes and methods not in the official API so that only the minimum level of access needed is used. e.g. if a method can be private other than protected or protected instead of public then it will be.
5. Removing unused code
There is a certain sense of accomplishment that can only be felt by getting rid of unused items and code. Methods, classes and variables that were found to be unused have been taken out. Old scripts that were once so useful have been removed along with redundant throws clauses.
6. Reducing the amount of dependencies
Additional dependencies can make it more difficult to get your software up and running if you need them and can mean unnecessary space is taken up on your machine if you don’t. To fix this issue we have been creating our own implementations of the external dependencies we use. For example, we now no longer need the Rhino dependency to handle JavaScript and BouncyCastle is no longer required to open AES 256 revision PDFs.
7. Keep the code base clean
Once you have identified areas of improvement and implemented the changes you need to try and make sure the issues don’t crop up again. One way we do this is by letting our teammates know through either code reviews or messages about improvements made. Then when they create new code they will know what to avoid or improve.
Also as I mentioned before we use static analyzers to help us find improvements. You can also use them as a second pair of eyes to spot issues that we may have initially missed when coding. We use these analyzers in combination with Maven so that our code gets analysed when built/tested and it will flag up errors if issues are found. Once found they can be fixed which helps you keep on top of your code quality.
Side note – We recommend only turning on the static analysis rules you want to check for once you have fixed all the cases and only a couple at a time or you will be overrun by errors.
That’s just a few ways we are currently improving the code base for now but we have a lot more ideas in mind.