Let’s say you’ve written a piece of code with all the clean code principles and all the cool patterns in mind. You run the code, it works. Now, would you go through a reverse process and rate the quality of your work, find design flaws, potential bugs, and breaking points?
When writing code you have the option to stop as soon as the code does the specific job you have at the moment, or you can design the components to be standalone, less bug-prone, easy to understand, scalable, and testable. With the second approach, you will end up with an app that is adaptable to change, easy to maintain, and long-lasting. This will save you a lot of headaches and, even though it seems counter-intuitive, it’s faster to develop clean code than a mess of interconnected dependencies that will blow up someday.
All the principles and design patterns can be a little abstract, especially if you’re reading the formal definition for the first time without looking at meaningful examples. After designing a component, it’s important to take some time to look back at the code. Your best chance at doing a refactor is during the development process, afterward, it just gets tougher as time goes by.
Here’s a checklist to go through:
- The code is easily testable
This is one of the most effective ways to assess your code since it will point out design flaws instantly. Even if you don’t write tests, check if you need too many mock objects for your component. If you need half a platform, a web server, and a file system you are doing something wrong.
- A change has low impact on the code
Just imagine your client and all the possible future requirements that creative devil can think of. How will your system handle the potential changes? Will you need a new design from scratch?
Note that you can’t predict all the possible scenarios that can happen and you shouldn’t design a system that handles everything. However, you can have multiple standalone, single responsibility components that do not heavily depend on each other that you can add/remove/modify to fit the new design.
- Adding and removing components takes little effort
Suppose you want to add a caching mechanism. Every component that has nothing to do with the data management in your app should not be affected.
Afterwards, changing the cache implementation would ideally affect only the dependency injection section of the app where you decide what concrete implementation you want.
- SOLID principles not violated
- What are its breaking points?
Is it encapsulated just enough? Can someone easily extend its behavior, but not be able to break it? Can you find any bugs?
- Easy to understand
You will get back to this code at some point. You should be happy when you do, not in denial.
- Formatted code
It’s surprising how important this is! Nobody wants to read an unstructured mess.
- Well documented methods and classes, but no line comments
No redundant documentation, just brief specifications where needed.
Having line comments usually means having poor naming or a too-long method.
- Ask for a code review
Another set of eyes will reveal another set of problems.
- Finally, the test of time
Release it, see what happens 🙂
This is a checklist I’ve gathered through time and find useful when assessing a component I’ve just written.
What would you add? Am I missing something important?