Ruby, Rack, Rails, Sinatra, Sammy, CouchDB, mysql
This is scrum board application. It assumes that you know a little bit about scrum. It provides product backlogs, sprint backlogs (boards), stories and tasks. Tasks have hours, stories have story points and you can generate a burndown of hours for a board. User(s) can be assigned to tasks.
Why Rails and Sinatra, mysql and CouchDB?
The original version was strictly Ruby on Rails with mysql. Rather than do a total rewrite, we opted to keep what we could intact. Since users, companies and payments receive little benefit from being in a non-relational store, we decided to leave them as they were. And, we wanted to try Sinatra. We didn’t want to port ActiveMerchant, which we use for payment processing in our hosted version.
Users and account owners are in Rails. When signing up, you create a new account, with you as the owner. Users can only be invited by an account owner. These are stored in mysql and accessed via ActiveRecord in the usual way.
All board actions are written in Sinatra. They generate the board pages when they are first loaded using erb. There is an json api used for CRUD’ing stories and tasks on the boards. In a couple of cases, the api returns html. We did this where the complexity of sending and generating the html from json was too complex.
With Rack::Cascade, all requests are first sent to the Sinatra application, and if none match, the request then goes to Rails. This setup also allows access to the Rails models from the Sinatra. It comes in handy in couple of places where you need user info.
Sammy provides nice and mostly RESTful routes on the front-end. It interacts with the json api, and renders js templates.
Each board is a document in CouchDB. Tasks, stories, and users who can access the board are all stored in arrays in the board. Each of those items in turn contain their own data. The goal was to be able to pull a complete board in a single request.
Every time a board changes, we first make a copy of the board to a new document, then update the head revision of that board. The head version is what is used for board show. This allows us to see a snapshot of the board at any point in time.
When a burndown is generated it’s stored in the board since the values for that board instance are never going to change. This is also true for the story point and hours calculations. They are only performed once, ever.
Product backlogs documents don’t contain boards. They store the ids of their boards. Since product backlogs maintain history in the same way boards do, when a board changes from the product backlog page (eg. moving a story from the product backlog to a board), the board will be copied, and then have its head updated. The product backlog will also be copied, and have its updated. The copied version needs to get the id of the copied version of the board’s id so when browsing history on a product backlog, they match up.
There are maps in the couch folder that roll up the data for various things – burndown data, pulling individual tasks or stories, etc…
There are 3 places views are found. In the usual Rails app/views folder. There is no overlap with these.
In the app/sinatra/views folder. These are used by erb to generate the boards on page load.
Since one set is js and the other ruby, the files can’t be shared. They could all be moved into erb or all into js. The former necessitates recreating rjs in Sinatra, while the latter requires the end user’s machine to do some heavy lifting to generate the initial board pages.
Test quality and coverage needs to be improved. Using Rack::Test, it’s difficult to divorce controller tests from view tests. There isn’t a way to get at the controller to see what it’s doing without checking the view to see what happened. And, class_eval seems a little bit kludgy.
Sammy is v0.2, it could be upgraded to v0.4. As part of this, the templating could be moved over to mustache.js.
The couchdb gem are using for loading design documents is a few versions behind.
Get rid of Rails entirely. There isn’t a need for it in this version. It would be nice to see a CouchDB-backed authlogic gem for handling user authentication.
Get rid of subdomains. They aren’t needed for this version.
Loading the application with ruby config.ru works, but doesn’t seem right.
A way to reload the code while developing. Rack::Reloader and shotgun both claim to reload the code, but they do not. Code changes are not applied until the next restart.