Last night I had the following exchange on Twitter:
Having just jumped on board to a newish Django project here at work, I feel their pain. Although I don’t know the Django ecosystem as well as Rails, I do know that projects should contain a readme, and I shouldn’t have to:
- execute server runner
- install missing lib or package that it complained about
- goto: 1 until working
Every development project, no matter how complex, should have a repeatable, predictable (preferably scripted) new developer project bootstrap.
- New developers can get their machine(s) setup and commit/deploy on the first day
- Existing developers can easily upgrade to new machines without spending days getting it all setup again
- Light-duty hackers (support folks) can have a copy of the site running locally (super awesome for debugging and general playing around)
- Designers can tweak styling, implement new designs, etc. without needing to involve a developer
- Spinning up throwaway testing/dev servers becomes very easy (you can treat them like a dev box)
A repeatable, predictable project bootstrap should, minimally, consist of the following:
- A root-level README that explains exactly how to setup the project. This should
contain step-by-step tasks (start with
git clone ...)
- A script to install pre-requisites (likely one for OSX, Linux)
- A script to bootstrap their data storage (build the structure, load default users, etc.)
- A script to deploy to staging/production
Root level README
This is your project’s bible. It’s in the project because web pages, wikis, and spec docs all have a way of disappearing.
The README shouldn’t contain any marketing speak about the project. It also shouldn’t contain any architectural documents, the history of the company, or anything like that. It’s simply a list of steps that you need to perform to get the app up and running on your machine, depending on your operating system.
This is the first thing a new person on the project will read. As part of a new hire’s “orientation” you should create a task in your tracker to “Follow the README”. Sometimes, but not often, some change may have invalidated the README. Part of the new hire’s job will be to fix the process to reflect the new project state.
It should also be part of standard operating procedure to follow the README when setting up a new developer machine (as old ones are swapped out) and any bugs immediately addressed.
Like code comments, broken or out-of-date project bootstraps are worse than none at all.
The README should also include any relevant links to the project wiki, bug tracker, project management, chat rooms, etc.
It should be opinionated – if you’re on ruby pick rvm or rbenv. If you’re on Python/Django, have a virtual environment. OSX? Homebrew.
This is not a negotiation – some level of consistency and standardization is a good thing. Don’t get carried away: let developers choose their own text editor, browser, etc. but project-level standards are expected to be enforced.
My README template is (loosely):
- External Links (wiki, bug tracker, chat)
- Dev setup (assuming a fresh machine – so this may include installing git, homebrew)
- External dependencies and versioning (if applicable)
- Project conventions that deviate from the norm (if you use some weird test runner…)
Where at all possible – script script script! Yes, you could tell the developer the series of commands to create a new user in the database (I’ve seen raw SQL insert statements in a README before! Eeek!) but it’s far better to run ./setup_db.
Obviously a script introduces overhead but a good team, over time, instinctively seems to find a good balance of scriptability vs. maintenance.
A hallmark of a great engineering process/culture has new hires deploying on their first day. This is only possible if the deploy process is scripted. The README should say how to deploy to the various environment(s) and if there are any externalities to resolve (ssh keys).
Edit – May 4, 2012
Some folks have suggested Vagrant + Chef or Puppet as a solution to the problem. I haven’t used it at all, but it certainly looks promising. I’d love to build a Puppet-based config for my local machine (we use Puppet-based Moonshine on our servers, so I’m not entirely sure why I didn’t think of it) and I suspect that’s what I’ll try first.
My only hesitation is that I primarily use a MacBook Air and, although a perfectly capable development machine, running Ubuntu on VMWare is intolerably slow. Benchmarking is probably a task for another day.