Clean Code and Code Smells are tightly intertwined: unclean leads to code smells more often than not, but they differ in their consequences and subjectivity. While some code smells relate to stylistic preferences, others detract from the long-term maintainability of a project.
In a survey of 85 professional developers, Yamashita and Moonen discovered that a large percentage of developers cared little about smells in their code, and a significant portion of these developers were unaware of the concept1. Those that were aware of the concept were asked to rank the significance of each smell/anti-pattern, with the following results:
The survey results illustrated that developers almost never intentionally refactored to remove bad code smells. In response, the “Clean Code” movement took up arms, drafting an approach to prevent such odors from coming into existence. Although the capitalized phrase evokes the sense of a rigid framework adopted by snobbish elites with large bumper stickers, clean code is actually a fluid concept that encompasses a wide range of practices and choices. A core belief is that, early on, projects tend to focus on platform technologies and state-of-the-art patterns instead of code quality, and that this leads to ever-increasing technical debt. This increases the chances of a bad fix being employed in the case of a bug, which may propagate more code smells.
Latte, Henning, & Wojcieszak propose that tool-chains and practices should be employed from the start to strictly enforce clena code. Their approach is based on four factors2:
- Clean code and code review
- Code style guides should be drafted, including, but not limited to, formatting, consistent use of language features, naming conventions, and use of meaningful names.
- In cases of non-compliance, code reviewers should openly discuss the issues, and refactor immediately.
- Test-Driven Development (TDD)
- This facilitates later refactoring, and keeps a short development loop.
- Static code analysis
- This includes tools for checking syntax, coding mistakes, and security vulnerabilities, which may be run externally or added to an Integrated Development Environment.
- Continuous Integration / Continuous Delivery (CI/CD)
- This automated quality enforcement forces developers to immediately refactor if a step in the pipeline fails, and provides various levels of feedback.
My Takeaways
As far as my personal coding habits go, I already incorporate a lot of static analysis tools into my editor, including automatic formatting, linters, style/naming suggestions, etc. In addition, My project teams utilize other tools in our build pipelines: CircleCI, GitHub Actions, and SonarCloud, to be specific. We also use OWASP ZAP to scan for security vulnerabilities before each deployment.
For my own sanity, I tend to refactor very often, since I’m a big fan of self-documenting code. This keeps my functions and classes quite short, but in the future I’d like adopt Test-Driven Development, instead of testing after the fact. This would force functions and classes to be short and poignant, and would likely reduce the total number of refactorizations.
I’d also like to focus more on avoiding complex conditionals. SonarCloud does good job of pointing these out, but I could prevent them from arising in the first place by focusing on small functions with single responsibilities..
References
- Yamashita, A., & Moonen, L. (2013). Do Developers Care about Code Smells? An Exploratory Survey.
- Latte, B., Henning, S., & Wojcieszak, M. (2019). Clean Code: On the Use of Practices and Tools to Produce Maintainable Code for Long-Living Software.