Cards and Columns;

A Kanban Process for Bugzilla




Derek Ries 
WebDev Intern - Summer 2013

Overview


  • One main project this summer, Kanbanzilla
  • What the project is
  • What it's for, with some background info
  • How it was built

Kanbanzilla


  • An internal tool that provides a Kanban board to triage bugs in Bugzilla.
  • Integrated so that changes made to the board are reflected in Bugzilla and vice versa.

What is Kanban?

  • Scheduling system for JIT Production
  • Work-in-progress limited pull system
  • Set of steps in the development process
  • Work is pulled into subsequent steps 
  • Doesn't prescribe doing anything radically different

Implemented as a Board


Kanban Origins


  • Roughly translates into "signboard" or "signal card" in Japanese.
  • Originally a scheduling system developed by Taiichi Ohno for Toyota factories.

Building Cars or software?


  • Obviously a different process
  • But the underlying idea of managing a production pipeline is the same

Core Principles


  1. Visualize
  2. Limit WIP
  3. Manage Flow
  4. Make Policies Explicit
  5. Implement Feedback Loops
  6. Improve Collaboratively, evolve experimentally

What about Bugzilla?

  • Bug Tracking System
  • Need something done? File a bug.
  • Lots of bugs to manage and we need to resolve them

Problem?

Well, there aren't many kanban applications out there. 

  • yodiz
  • kanbanize
  • kanban-tool
  • trello
  • leankit
  • targetprocess
  • breeze
  • swift-kanban
  • GreenHopper / Jira
  • Kanbannery
  • I Lied, there's a lot

Real Problem

  • Using any one of these tools requires updating data in two places and keeping them in sync
  • Change the board, go change Bugzilla.
  • Change Bugzilla, go change the board.
  • Don't like that, we want a board that just works.

Back to Kanbanzilla

  • On its' own, Bugzilla maps fairly well to a Kanban process.
  • Boards could be composed of existing Bugzilla components
  • Statuses could become the columns on the board.
    • Unconfirmed, New, Assigned, Ready, Resolved, Verified, Reopened
  • But there were a few intermediary steps that were desired.

Kanbanzilla Columns

  • Map to one or more statuses
  • Or have no status mapping and instead become a "virtual" column that was backed by some whiteboard data
  • Verified serves as an archive of sorts



DEMO

Building Kanbanzilla


  • Initially intended as an entirely client-side application.
  • Built with Angularjs and Flask
 

The Server

  • Thin layer on top of Bugzilla REST API
  • Creating and sharing boards
  • Auth

username=me@mozilla.com&password=lolnope 


userid=1234&cookie=mGjlksad94 

Why Use Angular?

  • Most experienced with
  • Doing things the angular way produces an application that is flexible, and easily reasoned about.
  • Support for testing
  • Community

Angular Features

  • Two-way data-binding.
  • Directives (web components)
  • Filters
  • Services
  • Dependency Injection
  • Extends HTML

The Angular Way

  • Not jQuery
  • Instead of reaching into the DOM to make the UI reflect the model, focus on manipulating data, and let data-binding and directives render that data for you.
  • When we do need to touch the DOM, this can be encapsulated as a directive, a web component of sorts.

Directives


 <calendar></calendar>

 angular.module('myApp')    .directive('calendar', function () {        return {            restrict: 'E', // or 'A', or 'C'            scope: {},            templateUrl: 'views/calendar.tpl.html',            link: function (scope, elem, attrs) {                 // directive functionality            }        }    });

Make your HTML an app-specific DSL

views/board.html

 <input type="text"
            id="board-search"
            class="input-medium search-query"
            placeholder="Search..."
            grow-when-clicked="300"
            ng-model="query">
 <div class="board-dropzone unselectable" auto-fill-height>   <div class="board-dropzone-inner" fancy-scroll-horizontally>      <kbcolumn ng-repeat="column in board.columns"                display-title="{{column.name}}"                ng-model="column"                sort-options="sortableOptions"                query="query">      </kbcolumn>   </div> </div>


Some Things I've Learned About Angular After Making Several Applications


  • Performance
  • Use promises for a lot of features in angular
  • Truly Re-usable Components


Performance


  • Angular makes it really easy to start getting things working
  • BUT, larger apps require some consideration when using those "easy" features.

Throttling / Debouncing

 <input ng-model="query"> <ul>   <li ng-repeat="item in items | filter:query"></li> </ul>
  • Frequent model changes and re-rendering.
  • If we have a lot of data, then typing gets sluggish.
  • Probably want to type more than one character anyway.

Debouncing

  • != Throttling
  • Coalesce several signals into one
  • Can ignore the signals until some completion delay has elapsed, then trigger the update/signal

debounced, at_begin false
   throttling
throttled, no_trailing false

Debouncing As A Directive


 <input ng-model="query" debounce-model-update="400">

"Why does ng-repeat suck?'


  • Stop trying to render all 10,000 items at once
  • Not just a performance problem, also a UX problem
  • Try pagination or infinite scrolling to render only a subset of the collection at any one time.

Take Advantage of Promises

 getDataForUser('me', function (err, result) { ... });

 var dataPromise = getDataForUser('me');

  • Treat these promises as objects now, to pass around, and aggregate
  • Angular comes with a lot of functionality for promises.
    • Route resolve property
    • Interceptors

Route Resolve Property

Typical Before

App Routes

 $routeProvider   .when('/board/:id', {      templateUrl: 'views/board.html',      controller: 'BoardCtrl'   });
BoardCtrl
 angular.module('myApp')   .controller('BoardCtrl',     ['Board','$routeParams', function (Board, $routeParams) {     Board.getBoardData($routeParams.id).success(function (result) {       $scope.boardData = result.data     });}]);

Route Resolve Property

After

 $routeProvider   .when('/board/:id', {     templateUrl: 'views/board.html',     controller: 'BoardCtrl',     resolve: {         board: ['Boards', '$route', function (Boards, $route) {              Boards.get($route.current.params.id);         })     }
 angular.module('myApp')   .controller('BoardCtrl', ['board', function (board) {       // board is injected into the controller as the result        // of the resolved promise   }]);

Current Status


  • Have 1.5 weeks left in my internship
  • Kanbanzilla is being deployed
  • Optimizations like the debounce stuff not included yet.

Future Work


  • Upgrade to Angular 1.2
    • Animations
    • Simplify Code and some perf stuff
  • UI Changes
  • Sort order of bugs
  • Custom Columns
  • Apply filters to queries when creating boards, more than just component selection

 Thanks 


Christopher Lonnen
Peter Bengtsson
Jake Maul



Questions?

Cards and Columns;

By influenztial

Cards and Columns;

  • 4,832