All posts by adam

Branching and Releasing

Captures ideas around branching and releasing strategy.

Branch to release model

I have used branch to release for many years for small, to moderately sized teams, though I think it can be applied to many team sizes and complexity of project. This setup has worked for me in 99% (leaving 1% off in case I forgot somewhere it didn’t make sense) of my projects. I will use git as my jargon, but can be applied to many different VCS’.

Some assumptions about this approach are:

  • You write automated tests.
  • You take huge projects and dice them up into small, testable chunks.
  • You only commit to master if it is ready to go live.
  • You communicate with your committers.
  • You know what you are changing.

Arguments against it:

  • Sometimes I want to commit something without it being ready
    • Your problem is too big then. Dice it up.
    • You are writing too much code for one commit.
    • You need to take the time to write tests.
    • Implement parallel dev or having feature go “in the dark” / be configurable.
  • Others won’t write tests or break my code.
    • Communicate more.
    • Do code reviews.
    • Weed out the offenders.
    • Fix your culture, not put in more process.
T      0.1.0
         |
         |
B      0.1                               0.2
        /           /
       |           |
M --*--*--*--*--*--*--*--*--*--*

In this diagram you are committing to master (M), and the second commit you branch (B) 0.1. That gets deployed, tested, and approved. You then tag (T) as 0.1.0 and release that. You start to dev more on master and even branch 0.2 to prep another release. Bug is found in production against 0.1.0. If bug still exists in M, you fix the bug (BF) there with tests and cherry-pick (CP) the commit to 0.1 and have it flow down the same stream resulting in 0.1.1 tag like:

             0.1.1
T      0.1.0       /
         |   /
         |  | +-------------------+
B      0.1-CP-+     0.2                                     |
        /           /             |
       |           |              |
M --*--*--*--*--*--*--*--*--*--*--BF

If the bug doesn’t exist in M, you fix in 0.1 with tests, commit, wash, rinse, repeat.

             0.1.1
T      0.1.0       /
         |   /
         |  |
B      0.1--BF      0.2
        /           /
       |           |
M --*--*--*--*--*--*--*--*--*--*

If cherry-pick cannot be applied cleanly, you fix in both, with tests, tag and release. This should be a lot less likely if you are dicing up the problem into small chunks and committing small changes.

             0.1.1
T      0.1.0       /
         |   /
         |  |
B      0.1--BF      0.2
        /           /
       |           |
M --*--*--*--*--*--*--*--*--*--BF

Code Standards

Commit Messages

Commit messages should follow Ryan Davis’ (possibly some of my own flair) standard of:

  • {!,+,-} Commit message. TICKET_NUMBER
    • ! == Big change / feature
    • + == Small change / feature
    • – == Bug fix
    • Commit message should be accurate to what is happening. If it says “Removing whitespace.”, there shouldn’t be anything but whitespace removal, even if it is just code “cleanup” E.g. options.each { |k,v| params[k]=v } => params.merge(options).
    • TICKET_NUMBER == ticket number that is associated with the commit

The goal of this is to programmatically generate our changelog for each release so we can do something like $ rake generate:changelog. This will then be used to create the release description so that downstreamers will know what we are doing / to expect.

Commit messages should be in the imperative: “Fix bug” not “Fixes, Fixed bug”

http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

Formatting

  • Code should be only <= 80 characters wide. This helps:
    • Keep the code readable
    • Helps people with various editors / font sizes.
    • Keeps you from chaining too many methods together E.g. Foo.this(param).another(/hi/, ‘mom’).thing.what(the, heck).is.going.to(happen, if, this, keeps).going
    • Helps you see patterns for refactoring / DRYing your code.
  • Make your code as human readable as possible (Think 6months from now when you have to edit it again). This is especially true for local variable names, loop var names, function names (bad example: def do_the_rest_of_the_stinkin_query), etc.
  • NEVER add trailing whitespace. Its just extra bytes / annoyance for absolutely no reason. Please remove all trailing whitespace before committing. Set your editor to not add whitespace accordingly.

Language-Specific Guidelines

Code Reviewing

There are many lists out there to help us start to think about how to properly review someone’s code. This assumes those lists are understood and hopes to focus it a little more to what we should do at YP specifically. The goal is to drive to quality across the board as an organization.

  • All code being checked in should be reviewed. Grab your neighbor real quick and go over the change. If it takes too long to explain, you probably are committing too much at once. This assists in cross pollination.
  • All code being checked in should have a corresponding TICKET_NUMBER. This can feel pedantic, but assists greatly with DRYing up communication, documentation, deployments, and all of testing.
  • Reviewer should feel free to be critical and should ask questions until the what, why, and how are answered.
  • All code should have unit testing and reviewer should scrutinize the testing as well to see if it is sufficient or porous. Think of use cases, edge cases, etc.
  • Once review is complete, the ticket should have the reviewers name attached to it in the “Reviewed By” section.

Effective Meetings

Helpful explanation of why this exists: http://www.paulgraham.com/makersschedule.html and http://dilbert.com/strips/comic/1992-08-26/

This encapsulates what successful meetings should be and what kind of meetings we should attend.

  • Meetings should always have an agenda
  • That agenda should be no longer than 10 points
  • Its okay to have 15 min meetings.
  • Meetings should be avoided at all costs when they can be. E.g. Someone calls a meeting to get status from you on a given thing. Just answer the status question before the meeting and save everyone time. Better yet, have that information always available in an automatic way.
  • Meetings should be rejected if there is > 10 people involved.
  • Meetings should never happen over lunch.
  • If you don’t know what the meeting is for or if it is profitable, reject it.

The goal is to drive at focus, accuracy, and maximizing people’s time. This assumes then:

  • People will get “out of their chair” and get stuff done proactively.
  • People will communicate outside of meetings.
  • Don’t wait for a meeting to get something done. Do it now!
  • If you need an answer, go ask that person, if they don’t know, ask who knows, if they don’t know who knows, keep asking others until you figure it out.