My post is inspired by an article of Miško Hevery, who works for Google and coaches Googlers to maintain the high level of automated testing culture. The article contains concentrated Miško’s experience and gives clear advice how to write testable code. I think, every software engineer should have it in the “must read” list.
I read the article a couple of years ago and found its ideas very useful in terms of personal growth as a developer. Of course, many points were well-known to me, however I found several tips that explained me in detail what is wrong with certain code practices that I just felt as a bad coding style, but could not verbalize it.
In the PIM project we heavily use Guice – a Google framework that wires everything together using dependency injection. The article recommends Guice as the best tool to resolve dependency issues. So, recently I read it again having a good understanding of Guice and found a couple of new points that I missed the first time. Now I agree – Guice forces programmers to write a lot more testable code.
Base Principles
The article considers four code flaws that more or less exist in each project. Miško explains why each of them is a real flaw. How to detect and how to fix them. There a lot of clear examples of flawed code and how it could be fixed.
All the fixes are based just on several fundamental principles:
- The Law of Demeter – loose coupling between components
- Declaring all dependencies in the API instead of using hidden dependencies like global state
- Principle of single responsibility
Code flaws
Flaw: Constructor does Real Work (something more than field assignment )
- Drawbacks:
- Hard to test
- Violates the Single Responsibility Principle
- Solution:
- Don’t look for things, ask for them
- Do not create collaborators in your constructor
Flaw: Digging into Collaborators (using objects like “context”, “holder”, etc.)
- Drawbacks:
- Hidden dependencies
- Brittle code
- Hard to test
- Solution:
- Don’t look for things, ask for them
- Only talk to your immediate friends
- Ask for the most specific object you really need
Flaw: Brittle Global State & Singletons
- Drawbacks:
- Unnecessary coupling
- Spooky Action at a Distance
- Brittle Applications (and Tests)
- Dishonest API
- Solution:
- Dependency Injection is your Friend
Flaw: Class Does Too Much
- Drawbacks:
- Hard to debug
- Hard to test
- Hard to understand
- Non-extensible system
- Solution:
- Split large class into several ones
- Add new functionality to a large class as a new class
I hope after reading the article you will easily avoid all the flaws and make your life happier.
Bye!