Web application development workflow with Node.js

Context

The aim of the article is to describe a good workflow to use when developing web applications. I always read advice on good workflow practices but they are never aggregated together, that’s why I do it right now.

UI Driven Development

We are going to follow a Behavior Driven Development style. Moreover we are making a web application, so we decide to focus on user: we will start by writing code for the UI. Then for UI and backend, we will write our specs/tests first.

Technos

As technology we are going to use :

Node.js and its framework Expess.JS because of their popularity and to get more familiar with it.

Jasmine is the BDD framework for UI and Vows is the BDD Framework for backend.

Use case

The application on which I will apply the workflow is Ponyo, a simple app that actually does nothing apart of allowing to create and browse “categories”. To illustrate the workflow we are going to add a new feature : allow category deletion.

Category list

Category display

Workflow

Here are all steps we need to do proper developments. Of course most of the time pressure push us to do shortcuts, but it is good to keep the good way in mind. Moreover this complete workflow could help to think about what could be optimized/automatized:

Make a branch

Write UI specs + commit

Write UI specs code + commit

Write UI code + commit

Write backend resource specs + commit

Write backend resource tests + commit

Write backend resource code + commit

Run all tests

Test your app manually

Rebase branch

Merge branch + push

Refactor if needed

Details

1. Make a branch

First of all, don’t bother other programmers right now with our commits, so let’s create a branch called feature-delete-category.

2. Write UI Specs

We are doing UI Driven Development, so first write client side code specs. Then, check with your browser (here the URL is http://localhost:3000/tests/) that the Jasmine entries fail.

With Jasmine

describe 'Category deletion', ->
it 'When I display newly created category', ->
expect(false).toBeTruthy()
it 'And I click on delete category button from a category page', ->
expect(false).toBeTruthy()
it 'Then it brings me back to category list', ->
expect(false).toBeTruthy()
it 'And deleted activity is no more in the list', ->
expect(false).toBeTruthy()

3. Write UI specs code

Now that you know what you want to do, you can write corresponding tests and checks that they fail.

With Jasmine

describe 'Category deletion', ->
it 'When I display newly created category', ->
runs ->
$("#category-jasmine").click()
waits(500) # Waits to be sure that everything is done before testing
it 'And I click on delete category button from a category page', ->
runs ->
$("#delete-category-button").click()
waits(500) # Waits to be sure that everything is done before testing
it 'Then it brings me back to category list', ->
runs ->
expect($("#category-list").length).not.toEqual 0
it 'And deleted activity is no more in the list', ->
runs ->
expect($("#category-jamsine").length).toEqual 0

4. Write UI code

Now we are going to write the UI code, it is needed to know what we expect from server. We add a button to the template displaying a category, then we code the button behavior. After that we check that our tests still fail (backend does not support request for deletion). Finally we commit.

12. Refactor if needed

UI Driven development has the nice advantage to not let you develop unuseful resources but it does not let you think as good as possible the way to develop your backend. So you will probably need some refactoring. Fortunately, with your tests refactoring will be easier and safer. Moreover patterns you see when you develop UI first push you to think about refactoring that match better to your needs.

NB: Feel free to comment and criticize this article so I could improve it and correct what is wrong.

Generally you don’t want to commit the results of compilation into a revision control system, just the source. In this case that means committing the .coffee but not the .js. The .js can change due to changes in the CoffeeScript compiler, and diffing it isn’t meaningful.

Great post! I would like to suggest to use “git merge –no-ff feature_branch_name” at the very end. If you do that, you will later be able to see that this bunch of commits has been developed in a feature branch.

Somehow I like this better than just having one big plain chain of fast forwarded merges.