The comments for this post are over on Hacker News.
It’s been over a decade since Joel Spolsky wrote the Joel Test: 12 Steps to Better Code. The man was ahead of his time. Sure, things like version control are a no-brainer for any competent shop out there. With a plethora of great tools out there, most teams have a bug database and have reasonably up-to-date schedules. Heck, most software companies out there do pretty well on Joel’s 12 steps. But those 12 steps are no longer enough.
I’ve become somewhat of a process nut, which is weird. Usually I’ve got my finger over the big red deploy button before anyone else. But that’s not process, that’s deploying. I like to hear how other companies work. I see the most trivial roadblocks frustrate some developers. Many companies, both big and small, pay too little attention to process. It hurts morale, it contributes to unnecessary work, and it will eventually lead to a product falling apart.
This is my attempt to codify what I think are 12 great supplemental steps to Joel’s first 12. Like Joel’s, you should give a binary answer to each question: “yes” or “no.”
Here we go:
- Do you only deploy from one branch?
- Do you have a bootstrap script?
- Do all employees deploy code on their first day?
- Does each bug get a failing test?
- Is your bus factor greater than n/2, where n is the number of engineers?
- Can you spin up ad-hoc development and staging environments with one command?
- Does your team work around features, and not around sprints?
- Does all work get done on a branch?
- Do you actively remove deprecated code?
- Do bugs only exist in one place?
- Do you discourage the use of IDEs?
- Are discrepancies in process addressed before more code is written?
1. Do you only deploy from one branch?
In git parlance, master is usually seen as the “trunk” of a repository. That should be the only thing you deploy from. This is an idea stolen from Zach Holman and the guys over at GitHub. They call it GitHub Flow.
If feels wrong at first. Shouldn’t I have a separate “release”, “bugfix” and “master” branches? Yes, if merging is a pain or of version control stinks. But it doesn’t any more. Git is fast. Creating a new branch is mindless. Everything comes from master and everything returns to it.
If you are asking yourself the question, “which branch needs to be deployed?”, you are suffering from this problem. Thinking about what is the “correct” branch is just one more thing to mess up. Make it mindless, deploy from master. Just make sure master always works. See #8 for more on this.
2. Do you have a bootstrap script?
Getting a new developer’s machine up and running with the essentials should be painless. Of course, she’ll need a lot of things. Libraries, dependencies, helper scripts, etc. Thankfully, you can automate all of that. For a project like LayerVault, our bootstrap script installs git, homebrew, rvm, rails and a few other dependencies. One command and a fresh laptop is up and running with the latest code.
But the bootstrap script will inevitably get out of sync. Make sure it’s checked into source control somewhere. Keep tabs on it. Make it a hazing ritual for new hires to go in and update any discrepancies. Sure, it will be painful, but 75% of a bootstrap script is better than none at all.
3. Do all employees deploy code on their first day?
This is really just echoing Joel’s 2nd and 3rd points, but putting them in 2011 parlance. All employees should deploy code on their first day, even if they are not engineers. This forces you, the developer, to do 2 things: make sure the code can be deployed at a moment’s notice (see #1) and make sure the deploy process is simple.
It should be one command. And it should be so simple my mother could do it. If you’re a developer-centric company, it’s important to instill a sense of exactly how things work. A salesperson doesn’t have to go out and read The Art of Computer Programming, but it helps them be involved and get a better idea of how the nuts and bolts work.
4. Does each bug get a failing test?
Allow me to laud Cucumber for a little bit. I love it. It’s the best. Our wedding date is next June. It has already saved my buttocks and helped me sleep at night. Its straightforward non-syntax makes tests readable, straight-forward and highly reusable.
And in a blue-sky scenario, project managers write the Cucumber tests and us developers execute on them. Testing will not ensure that your product is good or that people will use it. It will, however, keep you from making the same mistake twice.
When a new bug comes in for LayerVault, we always write up tests around that bug and any others that could be similar. From there, it’s just Red-Green-Refactor. This is not new hat, but not many of us actively test. Get to it. Look into Cucumber or similar options.
5. Is your bus factor greater than n/2, where n is the number of engineers?
“Hey, do you know how the signup process works?”
“No, but Charlie does. Talk to him.”
“Charlie’s out for the next week.”
“Well, I guess you’ll have to wait a week.”
That stinks. That really, really stinks. While not every developer can know how every tiny component works, an extreme consolidation of knowledge is bad for business. Not only are you losing the time that Charlie is spending in Acapulco, but you have one or more developers blocked merely because of his absence.
The bus factor is a good way of describing this: How many developers would have to get hit by a bus before it would be better to rewrite the whole thing from scratch? Morbid, I know.
Cutting down on the bus factor is two-fold. Usually it’s split between the senior folks and the junior folks, like myself. The senior guys with knowledge of the systems need to actively educate the junior guys. It also helps if they are willing to make things incrementally better, rather than just keeping the status quo. The junior guys need to not immediately throw their hands up as soon as something flies over their heads. Anyone not working to increase the bus factor is likely a poison to the team.
6. Can you spin up ad-hoc development and staging environments with one command?
This is a doozy. I’m not sure if anyone really does it. Yet.
In the not-too-distant future, I will have a tool or a service that will do the following:
- Fire up a virtual machine
- Load my application onto that machine with a specific branch
- Connect to a production slave database
This will be done in one command. If I enter
test my_new_branch into my console, I get back a URL to my new machine. This makes QA scale. It eliminates a shortage of any staging servers that may occur. It allows individual features to be quickly and comprehensively tested against production data (assuming your new feature isn’t going to do any writes). Think of it as Heroku for testing.
If you’re reading this and wondering how to make $1mil on a web service, build this. I will be your first customer.
7. Does your team work around features, and not around sprints?
In the perfect developer’s world, deadlines don’t exist. Features are released when they are done, not when the sprint is over. While we like to live in a land of candy canes and unicorns, I don’t think sprints are conducive to an environment where deploys can happen whenever.
The problem with sprints is that the acceptable quality of work decreases as the release date approaches. The closer you get to your deadline, the more you and others are willing to say something is “good enough.” We should all be shipping early and often, but selling too many half-baked cookies will put your bakery out of business.
If you’re following the Master is Truth methodology, each feature can get its own branch. Before merging back into master, you should always merge an updated master into your feature branch. Solve any conflicts there and then run your tests. In code:
git commit -a -m "Finishing up feature x" # on branch my_feature git checkout master git pull origin master git checkout my_feature git merge master # Run my tests git checkout master git merge my_feature
This leads right into…
8. Does all work get done on a branch?
If you the entire team is working off of one branch, say
sprint37_release, each feature or bugfix becomes codependent on each every other feature in the worst way possible. Obviously, conflicts will always conflict. But conflicts can be resolved. What can’t be resolved is: we are moments away from our Big Fortnightly Deploy and we need to pull Feature X.
All of the devs scramble to pull out Feature X before the fabricated deadline. In their haste, they rip out wall sockets and forget to put things back the way they found them. Or the way they found them isn’t the way it needs to be right now. Feature X gets pulled, but a dozen bugs get introduced.
After going through this a few times, I’ve realized that all work no matter how small should always occur outside of the branch being deployed (in my case it’s
master). Pulling work out is trivial because it never makes it in. If it does, a simple revert of the merge usually does the trick.
git checkout -b until your fingers bleed.
9. Do you actively remove deprecated code?
We’ve all done it before. “I changed the conditional to have a dead case, but I’ll just leave the dead case there for posterity’s sake.” “Maybe I’ll just comment out these lines and call it good.” You can only proceed like this for so long before the cruft sinks the ship it clings to.
Deprecated code and useless code lingering around doesn’t provide the niceties we think it does. It doesn’t serve as a note for the next person reading it; rather, it furthers confusion. “Why did he leave this line in here?”
Actively removing dead code–and having tests to make sure you didn’t remove something important–makes for healthy projects. If you remove something that breaks something else further down the chain,
git reset --hard HEAD.
10. Do bugs only exist in one place?
Joel’s step “Do you have a bug database?” gets you halfway. A bug database is great for keeping track of bugs. But it’s important you only have one, and that everything to be fixed (even hotfixes) flow through it.
To take a note from the Getting Things Done methodology, you should always minimize the number of inboxes you have. Have plenty of ways to collect bugs (email, ZenDesk, SMS, Twitter), but make sure they all get filtered into one system. Doing hotfixes as favors via email or verbal agreement gets out of hand quickly. Just like you want your code to remain DRY, so should your bug reports.
As a developer, insist that tickets get written even for small teams. I’m a big fan of GitHub Issues, since it allows us to spawn issues and track them from the initial bug report to a deployed solution.
11. Do you discourage the use of IDEs?
IDEs can be unsharpened tools that lead to accidents. Not all IDEs are bad, and not everyone that uses one should stop. But their use should be curtailed. There are two in particular that need to go away: IntelliJ Idea and Eclipse. These products are the result of hundreds of people too afraid to say “no.”
There is also danger in the safety that an IDE gives. If a team leans too hard on an IDE for code organization, the code then becomes beholden to the IDE. It’s a damn shame when a project cannot be built outside of its IDE. Deployment is a pain and often a colossal hackery. The code suddenly has a new and very serious dependency that becomes very difficult to rectify.
Of course, IDEs are a preferred way to debug a piece of code. Some of them are clearly better than others, like Xcode and the Chrome Debugger. I personally try to use this lightest-weight IDEs when I must use one. After all, the good IDE is just a macro-machine for common tasks. If possible, discourage them.
12. Are discrepancies in process addressed before more code is written?
If you start falling down on any of these steps, fix them first before going back to committing new lines of code. Not following these steps leads to frustration. Frustration leads to anger. Anger leads to hate. Hate leads to shitty projects.
Keep your ear to the ground and know when your team is falling down. If the tests are failing, fix them. If your bootstrap script isn’t bootstrapping, fix it. Don’t let the problems accumulate. Ignoring all of these steps is a good way to work quickly, release quickly and release garbage.
Please add your comments and discussion to the Hacker News thread.