How to Deliver Code Every Day
- 6 minutes read - 1136 wordsI recently calculated that I merge 0.8 pull requests every day into my team repo. “How to Deliver Code Every 0.8 Days” didn’t sing, so let’s say I merge about one PR every day, delivering one or more features to production. I like this velocity, and in this post, I’ll explain how you can achieve it yourself.
My ideal day goes like this:
- Morning: start a ticket
- Early morning/early afternoon: open a PR
- Early afternoon: respond to comments and merge PR
- Afternoon: deliver work to a QA environment
- Late afternoon: deploy to production
Here are the ideas that comprise this workflow.
Be Fast
Be fast at writing code. This means fast, accurate, and correct typing, copying and pasting, creating files, renaming files, etc.
Be fast at committing code. This means aliases so you’re never typing full commands, and confidence branching, renaming, rebasing, etc.
Be fast at creating artifacts. Marked up screenshots, logs, text files, etc.
Make your processes fast. This is the subject of another blog post, but the short version is don’t tolerate slow shells, slow editors, slow test suites, servers that don’t hot-reload or crash for bad reasons.
But wait! When I become a genius-level programmer, can’t I hunt and peck and mouse and still be efficient? I’ve found such programmers to be rare. Whenever I see a famous programmer at work, I realize that among other attributes, they’re very fast at the basics.
We all have limitations. Maximize your speed within yours.
Break Up The Work Into Small Pieces
To deliver every day, you must break work into small pieces.
If all your tickets have names like “Create the dashboard”, you aren’t delivering any of them in a day. Learn to break them up into small standalone pieces of work.
Here’s a Given/When/Then story I might extract from such a ticket:
Given I'm viewing the dashboard
And I haven't completed one expense report
Then I see a link "view expense report (1)"
A world must exist– application, database, concepts of a user who can be ’logged in’ and have expense reports– to have a chance of delivering this in a day. It at least exposes the complexity that was there all along.
Write Tests to (Maybe) Go Faster Now and (Probably) Go Faster Later
Writing tests may make you a little slower right now. When you’re good at it, you’ll get faster, maybe as fast as someone not writing tests. But yes, it takes more time to do two tasks than one. Isn’t that bad?
Once you have that first test, you can iterate and experiment. Even if it’s a brand new feature, by testing it you’ll be more likely to refactor and ship something of higher quality from the start.
That’s right now. But what about “later”? Most of software development is “later”– refining things that exist. And then, having good tests will make you much faster. When I add a feature to well-tested application, I don’t have to “click around and try things” before delivering the work.
Open Great Pull Requests
Good PRs get approved quickly.
I’ve written about good PRs before. In a code review culture, I think good PRs are essential. They smooth your path now, and they tell stories later about what you were trying to build.
Learn from previous PRs. If you keep getting the same kind of comment, learn how to preempt that criticism. Maybe you change your style, or resolve a misunderstanding. Maybe you aren’t extracting that class now because you know from an offline conversation that it’s all going to be scrapped soon anyway. Share that knowledge!
Minimize overhead on your PRs. All the fancy Github features– assignees, labels, projects, milestones– try to avoid them. They’re Process™, and Process™ is friction.
Set Up Continuous Integration
You can’t deploy in a day if you’re babysitting multiple deployments. Set up CI so that deployment happens automatically.
Open a PR? Tests run in under a few minutes, and review app deploys in under a few minutes. Merge a PR? Deploy to production. Notifications when things go wrong, and maybe when they go right. Although, on a high-functioning team, that will be mostly noise.
Test Your Work Yourself
When you deliver a feature, test it yourself so that you know it works. Don’t rely on the fact that it worked in development. Follow the ticket description and change the words so that they match what you’ve built. Be a QA engineer– don’t test on the same data you test everything on, submit the form without all the fields, and think about how you could break the feature.
Embrace Failure
If you want to deliver fast, you’re going to fail: embrace it.
“If you’re not embarrassed by the first version of your product, you’ve launched too late.” Our field is awash with advice like this, but in practice, we can all be too cautious.
If you want to ship every day, you have to accept that sometimes you’re going to break things. When this happens, how you respond matters more than anything else. Can you:
- Roll back?
- Understand and communicate the severity of the bug?
- Fix it at a speed appropriate to the severity?
- Write tests so that it doesn’t happen again?
- Have a sense of humor, accepting your fallibility? (still working on this one)
Learn to accept failure.
Random Speed Boosts
Embrace pairing. If somebody wants your input on a feature, do it now, not tomorrow. Get them unblocked, then finish your work. Teams where pairing requests are de-prioritized do not ship every day.
Resist trivial changes. Stumbled into a utility file and noticed one function
among a group of const
? It probably doesn’t matter. Keep the changes small so your work is more consumable.
Resist Git branching strategies. I prefer feature branches and main
. Resist having a dev
, staging
, and main
, or long-running branches. Complex merge strategies, while sometimes unavoidable, slow teams down, cause mistakes, and increase time to onboard new members.
Require one code review at most. What are two people going to say that one won’t, most of the time? Blocking a merge with required code reviews sounds wise until you have a hotfix that keeps your business running, and then that rule gets removed.
No waiting. No “waiting until tomorrow” or “It’s Friday, let’s wait until Monday” to deploy. If your deploys are so slow that deploying an hour before the end of the day is a risk, that’s a separate problem. If you’re afraid of a Friday deploy, your system is too brittle, or you don’t have foolproof rollback procedures, or you don’t have people you trust on call to resolve it. Each of these is a problem that you can fix.
Another technique: asking “What would finishing this today look like?”
Best of luck getting to your own personal 0.8 daily releases.