Contexto
O objetivo deste artigo é descrever um bom workflow para ser usado ao desenvolver aplicações web. Eu sempre leio conselhos sobre boas práticas de workflow, mas eles nunca agregam nada juntos, por isso vou fazer isso agora.
Desenvolvimento Direcionado para UI
Iremos seguir um estilo de Desenvolvimento Direcionado para Comportamento. Mais pra frente, iremos fazer uma aplicação web, então decidimos focar no usuário: começaremos escrevendo o código para a UI. Em seguida, para a UI e o backend, e iremos escrever nossos testes/especificações primeiro.
Technos
Como tecnologia iremos usar:
- Node.js e seu framework Expess.JS devido à sua popularidade e para nos familarizarmos mais com eles.
- A linguagem será Coffeescript devido à sua legibilidade.
- Backbone será o framework UI.
- Mongoose será o ODM.
- Git o sistema de controle de versão.
- Jasmine é o framework BDD para UI e Vows é o framework BDD para o backend.
Caso de uso
O app no qual eu irei aplicar o workflow será o Ponyo, um simples aplicativo que não faz nada além de criar e procurar por “categorias”. Para ilustrar o workflow, iremos adicionar um novo recurso: permitir a remoção de categorias.


Workflow
Aqui estão todos os passos que precisamos para fazer os desenvolvimentos corretos. É claro que na maior parte do tempo a pressão nos faz utilizar atalhos, mas é bom manter a maneira correta em mente. Mais para frente, esse workflow completo poderia ajudar a pensar sobre o que poderia ser otimizado/automatizado:
- Criar um branch
- Escrever especificações UI + commit
- Escrever especificações de código UI + commit
- Escrever código UI + commit
- Escrever especificações de recursos de backend + commit
- Escrever testes de recursos de backend + commit
- Escrever código de recursos de backend + commit
- Executar todos os testes
- Testar seu app manualmente
- Rebase branch
- Juntar branch + push
- Refatorar se necessário
Detalhes
1. Criar um branch
Primeiramente, não preocupe outros programadores com nossos commits, então vamos criar um branch chamado feature-delete-category.
Com Git
git branch feature-delete-category
git checkout feature-delete-category
2. Escrever especificações UI
Estamos fazendo Desenvolvimento Direcionado a UI, então primeiramente escreva as especificações de código do lado do cliente. Então, verifique com o seu browser (aqui está a URL: http://localhost:3000/tests/) que a entrada Jasmine falha.
Com Jasmine
1 describe 'Category deletion', ->
2 it 'When I display newly created category', ->
3 expect(false).toBeTruthy()
4 it 'And I click on delete category button from a category page', ->
5 expect(false).toBeTruthy()
6 it 'Then it brings me back to category list', ->
7 expect(false).toBeTruthy()
8 it 'And deleted activity is no more in the list', ->
9 expect(false).toBeTruthy()
Com Git, commit
git commit tests/categories.coffee -m "Add specs for category deletion."
3. Escrever especificações de código UI
Agora que você sabe o que quer fazer, você pode escrever testes correspondentes e verificar que eles falham.

Com Jasmine
01 describe 'Category deletion', ->
02 it 'When I display newly created category', ->
03 runs ->
04 $("#category-jasmine").click()
05 waits(500) # Waits to be sure that everything is done before testing
06 it 'And I click on delete category button from a category page', ->
07 runs ->
08 $("#delete-category-button").click()
09 waits(500) # Waits to be sure that everything is done before testing
10 it 'Then it brings me back to category list', ->
11 runs ->
12 expect($("#category-list").length).not.toEqual 0
13 it 'And deleted activity is no more in the list', ->
14 runs ->
15 expect($("#category-jamsine").length).toEqual 0
Com Git, commit
git commit tests/categories.coffee -m "Add tests for category deletion."
4. Escrever código UI
Agora iremos escrever o código UI, é necessário saber o que esperamos do servidor. Adicionamos um botão ao template exibindo uma categoria, então codificamos o comportamento do botão. Depois, verificamos se nossos testes ainda falham (o backend não suporta requisições para exclusão). Finalmente, fazemos o commit.
Modifique o template com Eco
1 <p>
2 <a id="delete-category-button" href="#home">
3 Delete category<br />
4 </a>
5 </p>
Escreva o comportamento com Backbone
01 categoryViewTemplate = require('../templates/category_view')
02 Category = require('../models/category').Category
03
04 class exports.CategoryView extends Backbone.View
05 id: 'category-view'
06
07 constructor: ->
08 super()
09
10 render: (category) ->
11 $("#nav-content").html null
12 $.get "/categories/#{category}/", (data) =>
13 $("#nav-content").html categoryViewTemplate(category: data)
14 @model = new Category data
15 @deleteButton = $("#delete-category-button")
16 @deleteButton.click(@onDeleteButtonClicked)
17
18 onDeleteButtonClicked : (event) =>
19 event.preventDefault()
20 @model.destroy
21 success: ->
22 app.routers.main.navigate("home", true)
23 error: ->
24 alert "An error occured, category was probably not deleted."
25 app.routers.main.navigate("home", true)
Com Git, commit
git commit public/ -m "Add deletion button to UI"
5. Escrever especificações de recursos de backend
Agora sabemos que precisamos de um recurso para deletar uma categoria, então vamos escrever nossa especificação de recurso de exclusão de categoria e commit.
Com Vows
01 .addBatch
02 'DELETE /categories/category-02/':
03 topic: () ->
04 apiTest.del 'categories/category-02/', @callback
05
06 'response should be with a 200 OK': (error, response, body) ->
07 assert.ok false
08 'GET /categories/category-02/':
09 topic: () ->
10 apiTest.get 'categories/category-02/', @callback
11 'response should be with a 404 Not Found': (error, response, body) ->
12 assert.ok false
13 'DELETE /categories/category-02/':
14 topic: () ->
15 apiTest.del 'categories/category-02/', @callback
16 'response should be with a 404 Not Found': (error, response, body) ->
17 assert.ok false
Com Git
git commit test/ -m "Add backend resources specs"
6. Escrever especificações de testes de backend
Agora escreveremos nosso código de teste, apenas checamos que os códigos HTTP retornados são os esperados e que uma vez que a categoria é deletada, ela não pode ser mais alcançada. Então, fazemos o commit.
Com Vows
01 .addBatch
02 'DELETE /categories/category-02/':
03 topic: () ->
04 apiTest.del 'categories/category-02/', @callback
05
06 'response should be with a 200 OK': assertStatus 200
07 'GET /categories/category-02/':
08 topic: () ->
09 apiTest.get 'categories/category-02/', @callback
10 'response should be with a 404 Not Found': assertStatus 404
11 'DELETE /categories/category-02/':
12 topic: () ->
13 apiTest.del 'categories/category-02/', @callback
14 'response should be with a 404 Not Found': assertStatus 404
Com Git
git commit test/ -m "Add backend resources specs code"
7. Escrever código de recurso backend
Agora escrevemos o código: adicionamos uma nova rota que irá linkar para um novo recurso dedicado à exclusão de categoria. Então, fazemos o commit.
Com Express
1 app.del "/categories/:category/", routers.deleteCategory
Com Express e Mongoose
01 exports.deleteCategory = (req, res) ->
02 categoryProvider = new CategoryProvider
03
04 categoryProvider.getCategory req.params.category, (err, docs) ->
05 if err
06 console.error(err.stack)
07 res.json 'An error occured', 500
08 else if docs.length > 0
09 docs[0].remove (err) ->
10 if err
11 console.error(err.stack)
12 res.json 'An error occured', 500
13 else
14 return res.json success: true
15 else
16 res.json 'I dont have that', 404
Com Git
git commit test/ -m "Add category deletion resource"
8. Executar todos os testes
Executamos todos nossos testes backend e UI no browser e estamos satisfeitos de ver que todos eles funcionam.
Com Vows
vows --spec test/resources.coffee
9. Testar seu app manualmente
Depois de ter lançado todos os seus testes, teste sua aplicação como um usuário normal. O BDD é ótimo, mas nunca irá substituir o teste manual, normalmente deixamos passar alguma coisa que não é revelada pelos nossos testes.
A exclusão de categorias é possível
10. Rebase branch
Queremos adicionar nossos commits como fizemos na última versão do branch master, então usamos o comando rebase.
Com Git
git rebase master
11. Merge branch
Então podemos juntar nossos recursos no master trunk. Um push no branch master irá validar que nosso trabalho terminou!
Com Git
git checkout master
git merge feature-delete-category
git push
git branch -d feature-delete-category
12. Refatorar se necessário
O Desenvolvimento Direcionado para UI tem a boa vantagem de não permitir que você desenvolva recursos inúteis, mas ele não permite pensar na melhor maneira de desenvolver seu backend. Então você provavelmente precisará de alguma refatoração. Felizmente, com seus testes, a refatoração será mais fácil e segura. Além disso, padrões que você vir quando desenvolver sua UI, te levam a pensar sobre qual refatoração corresponde melhor às suas necessidades.
?
Artigo publicado originalmente por Frank Rousseau em https://gelnior.wordpress.com/2011/12/27/web-application-development-workflow-with-node-js/ sob a licença Creative Commons by-2.0.







