Someone will need to maintain your code
Most of the effort in the software business goes into the maintenance of code that already exists
Most developers are generally not satisfied with being stuck in a job where they need to handle only support. The idea of a fresh new solution that needs to be created and formed is exceptionally tempting – and many developers will leave a job to get away from the support.
To prevent a high staff turnover, it’s vital that developers need to write sustainable, maintainable and understandable code.
Write code as if the person that will maintain your code is a murdering psychopath.
Many contractors and businesses are focused on delivery – if the application is not in production and working, then it’s not finished. For this reason unit tests, naming conventions and clean code is often sacrificed for early delivery.
Maintainable code and code smells
Uncle Bob famously compared writing code to a chef preparing a meal. He would sometimes need to multitask and check that everything will be ready in time, the food will be hot and that the presentation is perfect – and most of all, clean up as they go along. When they present the final dish at the end, the kitchen behind them is clean. In the same way, developers need to clean as they go.
When maintaining code, developers always need to leave code in better condition.
When bug tracking, it often happens that you look at a piece of code and think “What in heaven’s name…?”. This is what we call a code smell – and often technical debt. It is in the interest of the developer to clean up as he goes along – and a code smell should be the starting point to do a little refactoring or cleaning.
A code smell is a surface indication that usually corresponds to a deeper problem in the system.
Code will only be maintainable if we constantly take a little time to make it cleaner when we touch it. Note that the aim is not over-engineering, but sometimes even renaming a method or property will allow the code to be more readable.
Patterns & practices
When optimising for maintainability, developers need to focus on following good practices and design patterns.
These include a standard for naming conventions of methods and properties. Here are some pointers:
- Follow SOLID principles – more info here
- Do not abbreviate methods or property names
- Don’t repeat yourself – don’t write the same code more than once.
- Simplify the code base – code that’s not there cannot break
- Be clear in your naming conventions – for example,
Validate()is not a clear method. What is it validating? How can we rename this to be clearer?
Separation of concerns
Oftentimes a piece of code starts expanding past what it was originally designed for. This is normal, but it’s recommended that once this is noticed, refactoring needs to take place. Here are some thoughts on the separation of concerns and refactoring:
- Keep your methods small – only a couple of lines if possible. This will make it clear what the methods are doing. When you find that a method becomes too large, it is often a sign that it breaks the single responsibility principle. Extract these into smaller methods
- Avoid reuse of tables in a database with different elements that are not of the same type – for example, when you have a table with containers, don’t reuse the table for moulds, inventory and car parts. Even though it might look like the fields reuse would be a good idea, it can become unmaintainable in the long run.
- When building user interfaces, keep different concepts in different places. For example, don’t add cars, houses, chickens and users in the same list and allow for editing these. From a usability level, users need to get used to where to find users, livestock or assets.
Though there are many opinions about dependency injection, it’s worth noting that interfaces with implementation assists in decoupling software and allowing developers to swap out the implementation of classes, without any massive code changes.
As dependency injection is linked to inversion of control (SOLID principles), it’s a good practice to do in a project, especially if unit tests would be required.
When a change request is actioned, everyone needs to know that the changes will not affect other parts of the system. This is especially important where a client has a complex calculations engine such as insurance policy premium calculations – this should not fail, as this could mean the difference between profitability and legal action.
With a plethora of unit test solutions that can seamlessly integrate into any codebase, it’s becoming easier to write tests to make sure that processes and business rules will be followed, and throw an exception if any error occurs.
Integrating unit tests into continuous integration can also help developers to pick up issues long before it reaches production.
Solutions grow over time. More functionality is often required and needs to be added.
Having well structured, clean code with unit test coverage can assist in picking up issues long before they could happen.
Maintaining code requires consistency, and therefore it’s a prerequisite to have best practices in place. The expectations and standards need to be clearly defined so that all parties are aware of what is expected.
Simply be effective.