Archive for April, 2011

*This blog post tells about how we improved a VCS workflow to another one that suited our and the consumer needs. It was a great result: we minimized the chances of occurring one of the worst problems for a developer in a project: big integration while we maintained an ‘almost releasable branch’ all the time

In the last months we’ve been working on a project with a mixed development team (Plataformatec’s team and the customer’s team). We, of course, used a version control system (specifically git) and we set up a nice git branching model for our team. As agilists, we know that we should not use anything that requires a lot of bureaucracy (things like opening a ticket to integrate a branch into the trunk).

Using nvie guide as base, we developed a git workflow. First of all, we had three main branches:

  • production: contains the code that is currently on production. We also have a production server that contains, obviously, the production code up and running.
  • staging: contains the code that is being tested before going to production (we used this branch to deploy to a production-like environment that worked as a final test until production, this environment is also called staging)
  • master: contains the already accepted features. To consider a feature as “accepted” we deployed to another environment (called “dev”) and asked a QA analyst to test it. Once approved we merged the commits. This “dev” environment is used for this kind of approval and also for general purposes like when we say: “take a look at this new awesome feature we’re developing”.

For each feature that we developed, we created a git branch (almost all of them we pushed it to the remote server to facilitate code review and to deploy to the “dev” environment). Everyday, we ran git rebase master, to update our branch code (except for features developed by more than one developer). Once the feature is complete, we rebased master into it, and merge it using –no-ff (to create a merge commit). For the branches that more than one developer worked on, we usually talked and set up a “rebase period” where one does the rebase, forces the push (because you changed your local tree so git does not accept it as a non forced push) and updates the remote branch.

Close to the production deploy, we merged (always using –no-ff) master branch into staging branch and deploy to staging. Once approved, we merged to production, and created a tag telling the current version of the application and then we do the deploy. When we deployed to production we also removed the merged branches from the remote repository.

One of the great advantages of this schema is: Master is always “almost” ready for a release. Yeah, some features really deserves to be validated right before the deploy, because another feature can break them, but we kept the master as an “always releasable stable” branch (and also we used a continuous integration tool in order to enforce all tests passing). Another great advantage is: as we updated our code everyday, it was very unusual for us to face big integration scenarios.

For the “dev” environment deploy we also set up a capistrano task that asks which branch we want to deploy to be possible to deploy something from any branch.

This workflow has worked really well for us and maybe it is useful to you (maybe for you to adapt it to something that works better for you as we did with the workflow suggested on nvie).

To summarize, this is our git workflow in commands (supposing that we are on master branch):

git checkout -b my-awesome-feature
# (... you do some code and some commits and you go home to have some sleep or maybe play some starcraft 2 ...)

#(arrived at the office on the next day)
git rebase master

#(... continue working and commiting and sleeping (or maybe playing some starcraft 2 ...)
git rebase master

# (... some commits ... and voila ... you've finished...)
git push origin my-awesome-feature
cap dev deploy

# (...YAY! QA analyst just approved it ...)
git pull origin master
git rebase master

# (run the tests to ensure all of them pass)
git checkout master
git pull --rebase origin master
git merge --no-ff my-awesome-branch
git push origin master

#(... it is time to validate on staging)
git checkout staging
git pull origin staging
git merge --no-ff master
git push origin staging
cap staging deploy

#(... QA analysts validate the staging ...)
git checkout production
git merge --no-ff staging
git tag -a v1.4.2 -m "Releasing on 13th February"
git push origin production
git push --tags origin production
cap production deploy

Well, this is how we improved a git workflow based in another one. As almost everything, there is no bullet proof for it, but we found interesting to share this experience with you as it was a success (every developer on the team enjoyed it). But please, we would like to receive some feedback about it :-). Have you used something similar in your team? Do you have any ideas on how we can improve it?

It is common in Rails 3.0 applications that you want to provide default views for a group of controllers. Let’s say you have a bunch of controllers inside the Admin namespace and you would like each action to fallback to a default template. So if you are rendering the index action for Admin::PostsController and “app/views/admin/posts/index.html.*” is not available, it should then render “app/views/admin/defaults/index.html”.

There are several ways to implement this feature at the controller level. It mainly relies on trying to render the original template and then rescue ActionView::MissingTemplate. If this error is rescued, you then render the default one. However, there is a considerable performance overhead in this approach as it needs to pass through the rendering and template lookup stack twice.

Luckily, since Rails 3.0, we have a new abstraction called resolvers that holds the logic to find a template. I explain comprehensively how resolvers work and their API in my book Crafting Rails Applications. So here I would just show the basics to get this functionality working.
First, we need to define a DefaultResolver, it could be done inside the lib directory:

class MyResolver < ::ActionView::FileSystemResolver
  def initialize
    super("app/views")
  end
 
  def find_templates(name, prefix, partial, details)
    super(name, "admin/defaults", partial, details)
  end
end

Our new resolver simply inherits from ActionView::FileSystemResolver and does two changes: Overrides the initialize method so the view path defaults to “app/views” inside our application and overrides find_templates. The find_templates method receives the template name, a prefix (i.e. the controller path), a boolean marking if the template is a partial or not and a hash of details. In the example above, we simply ignore the prefix given and hardcode it to “admin/defaults”.

Now, assuming that all controllers inside the Admin namespace inherit from an Admin::ApplicationController, we can add default views to all of them by adding the following line:

class Admin::ApplicationController < ActionController::Base
  append_view_path MyResolver.new
end

And we are done! The view_paths holds a list of paths and/or resolvers that the controller will look for templates until one is found. If none is found, an ActionView::MissingTemplate is raised. Since we used append_view_paths, our resolver was added after the “app/views” path, used by default in all controllers.

As you may have guessed, resolvers are a powerful abstraction that allows you to retrieve templates from anywhere, including the database, which is the example given in Crafting Rails Applications.

Finally, template inheritance was a feature recently added to Rails master (upcoming Rails 3.1), so you won’t need to create your custom resolver as above. There is a good wrap up about this feature in Rails Edge.