Tuesday, November 9, 2010

SCRUM for one

Intro



As you may already know Scrum is a methodology for iterative and incremental software development that can improve both your product development cycle and its results. I first heard about it about one year ago, in Jessica Kahn's talk for the spring 2009 edition of the well deservedly famous iPhone Application Programming course that Stanford publishes in iTunesU, and since then I have applied it to all my software projects with very satisfying results. However, I had to do several adaptations because Scrum is really meant for a group of people and I develop software by myself.

Please be my guest and get to know how I apply Scrum for one.

What you need to know about Scrum



The main idea behind Scrum, the one that pushed me to adopt it, is that, instead of developing all the features of your product at once, so it becomes the Perfect Thing™ that you have in mind, you go through development sprints and at the end of each one you have ready-to-use product, that you could (more or less) ship.

The sprints can range from one week long, because less is meaningless for iteration, to a month, because more pushes you into too complicated features that render your product into an un-compilable state forever.

The features that you implement in each sprint come from a list, called backlog, that is the result of the design phase plus the constant input from the stake holders, as represented by the Product Owner and agreed with the Scrum Master (i.e. project manager).

Each spring is preceded by a meeting that is used for deciding the goals for the next sprint and followed by another one to review the accomplishments and the lessons learned. Also, in order to gather everybody's status the team holds the daily scrum meeting that shouldn't last more than 15 min.

The adaptation for one



As an indy you might be tempted to avoid implementing some of the features of the methodology. Rightly so. The most obvious one would be the meetings, but I don't recommend you to do so. Don't get me wrong. I am not suggesting that you present your slides with the desired functions of the product to yourself. However, if you are a GTD practitioner, the sprint review fits nicely in the weekly review, especially if you do sprint cycles that last a whole number of weeks. Also it is very helpful to dedicate 5 minutes a day, when you start your product development tasks, to refresh your current status. And finally you have the Scrum planning meeting.

After having done your initial design, that you have reflected into a mind-map. You dump all this features into a backlog. While as a GTD defender I reject to prioritize my actions with the ABC system because of its dynamic nature, I believe that it makes a lot of sense for features. You can classify your features in Must have, Desired features and Nice to have. So after the sprint review that happens during the weekly review, you should dedicate some time to plan what you will do in your next sprint cycle. That is the sprint kick off.

By now, you are probably thinking that this is a lot of management and not too much programming progress. So let me also talk a little bit about how I work on the features (and bug fixing) that are included in the sprint. I usually do one week sprints and manage all these changes using Git. I use a branch that is called NextVersion that holds all the changes that I plan to include in the next version of the product. From this branch I create a branch for each sprint. And from the sprint branch, I create a branch for each of the features. Once a feature is implemented and tested, I merge it to the sprint branch. And if the sprint is considered successful and I like what I have implemented, I merge the sprint branch into the NextVersion.

Conclusion



You might think "So what? I already try to do that." But as put by Diego Piacentini (Amazon) in the November 3rd talk for Stanford's ETL these are good intentions and what you really need is a process. Hope this process matches your needs. It works for me, indeed.


As always your comments are more than welcome. Let me know if you like this kind of content and share your experiences if you like.

Monday, November 8, 2010

Automatic version number from Git

Intro



I wrote this piece a while ago in my notebook, that I keep in TiddlyWiki, but listening to Jose's great series on Git in 85%Cocoa (in Spanish), I decided to share it with you in this blogger site that I had created some time ago and never really used. If you like it, I will try to publish more.

I use git for the version control of my projects and although it isn't news that Xcode 4 will come with Git integration, while Xcode 3.2 is still the required version for submitting apps to the App Store, I do want to enjoy the benefits of automatic version number generation in my projects. If you do to, hope this helps. Daniel Jailcut and Markus Zarra had previous versions that helped me to write this (Thanks guys!). Read those too.

iPhone and Mac OS X version numbers are stored in the plist of the project. There are two variables in that file that control the version number of an application:
  • CFBundleShortVersionString specifies the release version number of the bundle, which identifies a released iteration of the application. The release version number is a string comprised of three period-separated integers. The first integer represents major revisions to the application, such as revisions that implement new features or major changes. The second integer denotes revisions that implement less prominent features. The third integer represents maintenance releases. This is the marketing version.

  • CFBundleVersion identifies an iteration (released or unreleased) of the application. This is the build number.


I would like to create a script to be integrated as an XCode target that does automatic updating of this two fields of the info.plist file.

Git commit numbers are non sequential. Actually, they are hashes of the committed content. It is necessary to have a sequential number for the build number if you want to use this method both for iPhone and Mac OS X projects. In particular, both the App Store and the Sparkle framework (and probably the Mac OS X, although I haven't tried yet) require this sequential number in order to work properly.

Solution



The sequential number that is required can be maintained in a file that is not controlled by Git, so that branching or reverting changes does not change back the number. The build phase script will update the value automatically every time a build is successful. If this happens every time the project is built, successfully or not, the number would grow very fast although the numbers between successful builds are not needed.

When branches are used, which is one of the strengths of Git, a higher build number can be assigned to a patch of a current version than to the yet to release newest version. In order to add some sequence even in those cases, I will precede the sequential build number with the marketing version (1.0.0, 1.1.2, or 2.0.0 for example). In this way it is clear that 1.1.0.139 is not newer than 2.0.0.127, although the build number is.

The marketing version will only be modified if any commit has been tagged, containing the marketing version number.

In order to obtain a clean git status, build_number should be added to the .gitignore file.

Additionally the file with the build number could be copied to another file number that is tracked with Git, so that reverting to a previous commit contains information about the build number that was used at the time of the commit.

Implementation



I have created a perl script that does this using the PerlObjCBridge to read and write the plist, reads the build number from the file, and pipes to communicate with git to use describe --tags (that provides the last tag assigned).

The script is:
#!/usr/bin/perl
# gitversion.pl
#
# Created by Jorge D. Ortiz Fuentes on 09/11/09.
# Copyright 2009 PoWWaU. All rights reserved.

use Foundation;
use File::Copy;

# Script customizable variables
$git="/usr/local/git/bin/git";

$script_action = $ENV{'ACTION'};
$info_plist = $ENV{'INFOPLIST_FILE'};
#$project_dir = $ENV{'PROJECT_DIR'};
#$project_name = $ENV{'PROJECT_NAME'};
#$src_root = $ENV{'SRC_ROOT'};

if (script_action == "build") {

print "Working with project properties: $info_plist\n";
unless (-e "$info_plist.old") {
copy($info_plist, "$info_plist.old") or die "Copy failed: $!";
}

# Read the info.plist file
$project_plist = NSMutableDictionary->dictionaryWithContentsOfFile_($info_plist);

if (!$project_plist or !$$project_plist) {
die "One of the following failed: $plist - $$plist\n";
} else {
# Obtain the last tag to set the marketing version (CF
if (open(GIT_TAG, "$git describe --tags HEAD |")) {
$marketing_version = ;
chomp($marketing_version);
close(GIT_TAG);
print "Marketing version: |$marketing_version|\n";
$project_plist->setObject_forKey_(NSString->stringWithCString_($marketing_version), 'CFBundleShortVersionString');
} else {
print "Failed to obtain git describe: $!.\n";
print "Not updating CFBundleShortVersionString\n";
}

# Obtain the CFBundleVersion (or build number)
# For non sequential numbers use: git rev-parse --short HEAD.
open(GIT_BUILD, "build_number") || die "Failed to obtain git rev-parse: $!.";
$build_number = <git_build>;
chomp($build_number);
close(GIT_BUILD);
$bundle_version="$marketing_version.$build_number";
print "Build version: |$bundle_version|\n";
$project_plist->setObject_forKey_(NSString->stringWithCString_($bundle_version), 'CFBundleVersion');

# Write the updated plist.
$project_plist->writeToFile_atomically_($info_plist, "1");
}
} else {
print "Doing NOTHING. ACTION isn't 'build'";
exit(1);
}


Integration



Setting the information into the info.plist



  1. Create a new build phase for the current target that consists in running an script.

  2. Add the following script to that build phase:


  3. run_script="gitversion.pl"

    echo "Running a custom build phase script: $run_script"
    "$PROJECT_DIR/Scripts/$run_script"
    script_exit_status=$?
    echo "Finished running custom build phase script: $run_script (exit status = $script_exit_status)"
    exit "$script_exit_status"

  4. Copy the perl script into a new project directory named Scripts with the name gitversion.pl.

  5. Add the script file to the project ensuring that it is NOT added to any of the targets of the project.

  6. Move the build phase to the beginning in order to ensure that the info.plist is modified before copying it to the bundle.


Incrementing the build number



  1. The first time the project is created, initialize a file with the build number set to 1 in the main folder of the project.

    echo "1" > build_number

  2. Create a new build phase that consists on running a script.

  3. Add the following script to that build phase:

    echo "Incrementing sequential build number."
    # copy the previous build number for book keeping in Git
    cp build_number build_number.prev
    # and increment it
    bn=$(cat build_number)
    (( bn=$bn+1 ))
    echo $bn > build_number
    echo "Build number updated to $bn. Finished."

  4. This phase must be the last one for the target.



Additionally if I want to avoid incrementing the build number for non-successful builds, there is a setting in the build section of the Xcode preferences to "Continue building after errors" that can be disabled.