Counterintuitive Steps to Moving Faster in Engineering: Slow Down to Move Fast
At Yonomi, we have to work fast to make sure our clients are supported and our products are improving. But, that isn’t unique to our business or our work model. Choosing between close enough and almost perfect is never an easy decision, but you can make it more confidently with few simple mantras. I’ve been writing software professionally for around 21 years. I’ve spent the last 11 working primarily for startups. With the right foundation, any team can feel secure in their ability to iterate quickly.
The Real Intention Behind “Move Fast and Break Things”
The business always wants to know when work will be done. Engineers don’t always have an answer. The business wants to know how to move faster. Engineers want to spend more time building things of value. One expression I’ve heard a lot (especially in the startup world) is “Move Fast and Break Things”. This mantra is widely credited to tech giant Facebook, who has since taken a step back and revised the expression: “Move Fast With Stable Infra[structure]”. As Facebook scaled to staggering degrees there was more and more at stake when things broke, and the nonchalant attitude toward making mistakes was unable to scale alongside of everything else.
For Facebook, the goal behind the “Move Fast and Break Things” culture was about encouraging engineers to take advantage of small bursts of time, like hackathons, to build working prototypes that could later be turned into greater products. Engineers could work fearlessly because they launched products quickly and treated everything like an experiment. In my own experiences, moving fast has been more about iterating quickly. In theory, the faster we can identify our mistakes, the faster we can learn from them and build a more superior and disruptive product with greater momentum than our competitors. In practice, moving fast too easily becomes a justification to avoid mindfulness of our work as engineers.
Iterating quickly and finding flaws early is a wonderful goal, but there are some lessons that many engineers and businesses alike are instinctively inclined to ignore. In so doing we create an environment where the mantra might as well be “Move Fast and Break Things”. Here are a few simple mantras I’ve picked up over the years that will ensure you can move fast and break things while honoring the intention behind this noble goal.
Don’t be Mean to Your Future Self
A friend and coworker of mine used to say, “don’t be mean to your future self” ,whenever we were tempted to take a shortcut. It’s one thing to have a healthy focus on the minimum requirements for a feature to avoid scope creep or premature optimization. It’s another issue completely if those decisions make your code harder for you (or others) to maintain when you have to come back to it.
Before you merge your code (or approve a pull request), ask yourself the following questions:
Is this code easy to read? Will it be obvious what this code does and how it works if I don’t see it for a year and have to come back to it? Even if you’re a genius and can read the most complex code the way Cipher could read The Matrix, some day you’ll probably have a junior engineer who has to work on your code. Would you like to spend all day explaining it then, or just write it in a way that’s understandable to others now?
Are all “TODO” comments resolved and removed from code? Tip: If they are too big to resolve now and not strictly required to complete your work, consider removing them from the code and putting them in your backlog so they can be prioritized alongside all of the other future work.
Does this code meet your definition of done? (If you don’t have a definition of “done”, you can get started with the checklist at the end of this article.)
If you answered “yes” to all of these questions, then you are probably on the right track. If not, you’re setting yourself (or your eventual replacement) up for a hard time. That’s not good engineering. That’s just mean. Don’t be mean.
Be a Scout (a.k.a. Don’t Let Perfection be the Enemy of Progress)
If you have a codebase that’s experienced more than its share of abuse over the years, it can be a daunting task to clean up all of the messes that have been left behind. The good news is that it’s rarely necessary to fix everything at once. All you have to do is be a good scout.
I love spending time outdoors with my kids. One saying they frequently hear from me is “I don’t expect you to leave it perfect, but I do expect you to leave it in better shape than you found it”. In code, just like in nature, it’s very rare that you’ll come upon anything so pristine and untouched that there’s nothing you could do to improve it.
I can’t think of a time when I’ve used a campsite or trail and didn’t find a wrapper, a piece of broken glass, or a loose stone threatening to twist an ankle. It’s equally rare to open up a PR where something can’t be tweaked for the better. It could be as trivial as making the code adhere to a style guide so it’s easier to read, or a serious refactor to optimize performance or testability.
No tests? Write a test that proves that the method you’ve just changed works as expected.
Seeing the same code copied and pasted in two or more areas? Refactor it into a method to make the code more reusable.
Did you get stuck on a bit of complex code where it was hard to read and intuitively understand what was being accomplished? Refactor! Rename variables and methods or functions with longer, more descriptive names.
Look for opportunities like these and make small improvements with every code merge. Use a tool like CodeClimate to measure your progress. Soon you’ll start to see clear evidence of your effort, both in your code reports and in how much easier it is for you to make modifications for future projects. Bonus points if your team adopts a practice where no merge is allowed to drop your code quality score or your test coverage percentage.
Know Your Definition of Done
One of my old CEO’s (and a current board member at Yonomi) once told me me that when engineering tells him that a project is 95% done, that means there’s only 95% left to go. I’ve come to believe this is often spot on. If you don’t have a definition of “done”, here are a few questions that can help you get started:
Is a health check on this service available? (Does this service provide a health check on dependencies and respond with a useful failed health check when dependencies fail?)
Is new or altered code is supported by comprehensive test coverage?
Is new or altered code is DRY, legible and idiomatic?
Is altered code is as good or better than you found it?
Are test coverage and code complexity scores improved or have they remained static?
How do you know it’s broken?
If you really want to move quickly without fear of breaking things, the first step is knowing when it’s broken. It is critical that tooling and environments have been put in place that allow you to monitor the status of your applications and provide enough detail to pinpoint problems quickly. Nobody likes to spend the day fruitlessly searching for that bug that ended up being a single line of untested code, or worse, an issue with a third party dependency that’s gone down without your knowledge.
Some of my favorite monitoring tools:
Good Tests Inform Good Design
Speaking of knowing when things are broken, a serious approach to testing is absolutely critical. Writing tests is a big topic in itself. For the time being, I’ll just say that every project needs an automated test suite. Your coverage should be high. Avoid brittle tests. I am also firmly in the test driven development camp. Starting with a test approach will make it easier to avoid code that is difficult or impossible to test properly.
Don’t be mean, be a scout, and know your definition of done. Committing to these principles won’t make your projects perfect, but it will make them more enjoyable to work on in the long term. You’ll thank yourself, and your coworkers will appreciate you as well. Most importantly, you’ll be able to move fast and, when you inevitably break things, you’ll be more likely to catch them quickly. The end result is a continuously improving AND stable product that engineers will enjoy working on and customers will love.
About the Author
Josh Kaiser is a Senior Software Engineer at Yonomi. He has a passion for creating beautiful, manageable, and practical code using tools and platforms that are sustainable and scalable. He has more than 20 years of engineering experience with software development, troubleshooting, and the administration of computer systems. He previously worked at Wink, Inc. and holds a degree from Colorado Technical University.
Are you building a service or app for your industry?
Check out our Guide to Building a Smart Home Service to learn more about what it takes to get started.