After two and a half days discussing features, estimating them as a team and preparing a decent backlog, it was time to decide how to publish it. The idea of e-mailing a spreadsheet around and trying to figure out what has been modified terrrorized me. I’d like to have it an a central place where everybody could edit it and the (properly versioned) changes would be immediately available.
Whilst Google Docs could have been a nice alternative, it’d take me some time (maybe forever) to convince the managerial ranks to endorse it. Time to look for an answer closer to our company’s chest, like some internal system for managing issues related to a project, with a coupled VCS, user-based access and… Oh, wait! We already had Trac-Wiki set on our project!
With an embedded VCS enabled on the wiki, the only missing feature was being capable of properly rendering backlog tables on it. The built-in wiki syntax wasn’t enough to create a functional table, however it had a WikiProcessor extension mechanism which let me use other markups. As maintaining the backlog in pure HTML would be a pain, the alternative was to experiment a very flexible markup called Textile.
After researching a bit of textile syntax and trying some examples, the following snippet plus a tweak at the theme style sheet rendered something near to a backlog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
{{{ #!textile table(backlog). |_. ID |_. Name |_. Weight | |/2. SW01 | Feature 1 | XXX | |\2. (acceptance criteria 1) | |/2. SW02 | Feature 2 | XXX | |\2. (acceptance criteria 2) | }}} /* CSS required */ table.backlog { border-collapse: collapse; width: 100%; } table.backlog th { border: 1px solid black; padding: 0.5em; font-weight: bold; background-color: #ccc; } table.backlog td { border: 1px solid black; padding: 0.5em; font-size: 12px; } |
| ID | Name | Weight |
|---|
| SW01 | Feature 1 | m |
| (acceptance criteria 1) |
| SW02 | Feature 2 | n |
| (acceptance criteria 2) |
The acceptance criteria on a separate row was kind of lame, so lets try to join it with the story name.
|
|
{{{ #!textile table(backlog). |_. ID |_. Name |_. Weight | | SW01 | %Feature 1% (acceptance criteria 1) | m | | SW02 | %Feature 2% (acceptance criteria 2) | n | }}} /* CSS required */ table.backlog td > span:first-child { display: block; font-weight: bold; } |
| ID | Name | Weight |
|---|
| SW01 | Feature 1 (acceptance criteria 1) | m |
| SW02 | Feature 2 (acceptance criteria 2) | n |
Much better! Now, what about appending dependencies to each story? Even better, why not referencing them as links to the story itself?
|
|
{{{ #!textile table(backlog). |_. ID |_. Name |_. Weight |_. Deps | | SW01 | %(#SW01)Feature 1% (acceptance criteria 1) | m | | | SW02 | %(#SW02)Feature 2% (acceptance criteria 2) | n | | | SW03 | %Feature 3% (acceptance criteria 3) | o | "SW01":#SW01 | | SW04 | %Feature 4% (acceptance criteria 4) | p | | | SW05 | %Feature 5% (acceptance criteria 5) | q | "SW01":#SW01, "SW02":#SW02 | | SW06 | %Feature 6% (acceptance criteria 6) | r | | }}} |
| ID | Name | Weight | Deps |
|---|
| SW01 | Feature 1 (acceptance criteria 1) | m | |
| SW02 | Feature 2 (acceptance criteria 2) | n | |
| SW03 | Feature 3 (acceptance criteria 3) | o | SW01 |
| SW04 | Feature 4 (acceptance criteria 4) | p | |
| SW05 | Feature 5 (acceptance criteria 5) | q | SW01, SW02 |
| SW06 | Feature 6 (acceptance criteria 6) | r | |
The hack, used to prevent column spanning, may not be required in Trac as it is in my wordpress processor.
To finish a fancy and useful backlog we can add two classes to visualize the separation of stories per sprint. Those without a background color are still in the project’s pipeline.
|
|
{{{ #!textile table(backlog). |_. ID |_. Name |_. Weight |_. Deps | (odd). | SW01 | %(#SW01)Feature 1% (acceptance criteria 1) | m | | (odd). | SW02 | %(#SW02)Feature 2% (acceptance criteria 2) | n | | (even). | SW03 | %Feature 3% (acceptance criteria 3) | o | "SW01":#SW01 | (even). | SW04 | %Feature 4% (acceptance criteria 4) | p | | (odd). | SW05 | %Feature 5% (acceptance criteria 5) | q | "SW01":#SW01, "SW02":#SW02 | | SW06 | %Feature 6% (acceptance criteria 6) | r | | }}} /* CSS required */ table.backlog tr.odd { background-color: #ddd } table.backlog tr.even { background-color: #ffa } |
| ID | Name | Weight | Deps |
|---|
| SW01 | Feature 1 (acceptance criteria 1) | m | |
| SW02 | Feature 2 (acceptance criteria 2) | n | |
| SW03 | Feature 3 (acceptance criteria 3) | o | SW01 |
| SW04 | Feature 4 (acceptance criteria 4) | p | |
| SW05 | Feature 5 (acceptance criteria 5) | q | SW01, SW02 |
| SW06 | Feature 6 (acceptance criteria 6) | r | |
With this template and relatively simple syntax, it seems easier to create, delete and move stories around. Modifications can be figured out at Trac’s page history and things get associated by the hyperlinks. Good bye, nasty spreadsheets!
Other advantage is that if you don’t use Trac for your projects, the only thing you need is a textile processor to get it done. You may auto-generate it from build-scripts, use another bug-tracker or integrate into WordPress (as I did it here).
A downside in this alternative is the need to specify custom CSS rules outside of textile content. I had to hack it into WordPress current theme’s style sheet and into Trac’s too. Look at the complete excerpt below.
|
|
table.backlog { border-collapse: collapse; width: 100%; } table.backlog th { border: 1px solid black; padding: 0.5em; font-weight: bold; background-color: #ccc; } table.backlog td { border: 1px solid black; padding: 0.5em; font-size: 12px; } table.backlog td > span:first-child { display: block; font-weight: bold; } table.backlog tr.odd { background-color: #ddd } table.backlog tr.even { background-color: #ffa } |
References
UPDATE: better colors and avoid selecting spans after the first one.