On the Importance of PerfectionPosted: May 23, 2011
Our systems are not perfect; code gets checked in every once in a while that is not optimal – it may go against the system’s architectural grain, or it could be cleaner, more efficient, more forward-looking.
But, checking this code in is done thoughtfully – we know when we take shortcuts in our system and we do so when we know that a new system is coming, just not soon enough for our rapid release requirements.
When we set out to write our new data access layer, we wrote it three times, twice throwing away the entire system because we found anti-patterns emerging in the code. We did these iterations very quickly, in order to discover the best set of patterns for our particular set of needs. We did not check in any code until complete scenarios could be implemented end-to-end without code duplication, without dependency loops, without the code starting to smell. The current working system still isn’t perfect, but its imperfections are understood and represent conscious tradeoffs.
In contrast, many systems we’ve seen in the past do not represent such tradeoffs – they were not designed as frameworks on which higher-level systems could be built. Such systems work, but constantly accrete complexity until they collapse under their own weight: New changes are hard to make and cause regressions, unit tests are difficult to write and require pulling in multiple dependencies.
As a Software-as-a-Service company, we strive to move fast so that we can deliver new features to our customers, but at the same time we hold ourselves to many of the standards that a company that releases public APIs must hold itself to. We do this because we believe, and have learned from decades of combined experience, that doing so not only makes us happier as engineers, it makes us more successful as a company. It does this by giving our code a much longer lifespan, by making tests quicker to write and quicker to run, by enabling new engineers to ramp up more quickly.
While it can take many years to get an intuitive feel for whether code is going to scale with increased system complexity, there are some simple methods that can be used: Code must adhere strictly to package and class design best practices. In addition, our class designs are judged using something called “SOLID.” more on this in the next blog post.