Este documento resume um método de desenvolvimento de software orientado a testes (TDD) em 3 passos: 1) Fazer perguntas para esclarecer os requisitos, 2) Documentar especificações e tarefas, 3) Implementar em incrementos pequenos guiados por testes. O método é demonstrado através da construção passo-a-passo de uma API para gerenciamento de fotos de inspeções utilizando Ruby on Rails.
2. SOBRE
RACHID CALAZANS
▸Software Engineer at Tidy
▸Viciado em testes, fissurado em arquiteturas de software e
em qualidade de código
▸Github: /rachidcalazans
▸Medium: /@rachidcalazans
▸Podcast: http://2devs.simplecast.fm
▸Twitter: /rachidcalazans
3. DIFICULDADES
JÁ PASSOU POR ALGUMA?
▸Com Prazo?
▸Com solicitações mal escrita ou pouca informação?
▸Em saber como iniciar alguma Task?
▸Em aplicar testes na hora de implementar?
▸Em entregar um resultado meia boca ou insatisfatório?
4. SOLUÇÃO
O QUE PODEMOS FAZER?
▸Se organizar
▸Entender o que foi solicitado
▸Utilizar metodologia TDD (Desenvolvimento Orientado por Testes)
▸Entregar resultado final com qualidade
5. DOMINANDO FLUXO
OK, MAS COMO?
▸Utilizando uma metodologia de fluxo de desenvolvimento
▸Em apenas 3 Passos
▸Todo desenvolvedor deve realizar
▸Servirá sempre. Utilizando testes ou não
7. PASSO 1
PERGUNTAS CHAVES
▸1- Já estruturou o que será necessário fazer?
▸2- Qual camada(s) será necessário desenvolver?
▸Implementação de tela
▸Consumo da API
▸Criação de novo endpoint da API
▸3- Onde será preciso focar primeiro?
8. PASSO 1 - JÁ ESTRUTUROU O QUE SERÁ NECESSÁRIO FAZER?
RESPOSTA #1 - ESTRUTURAÇÃO
▸Sempre estruturar o que é necessário ANTES de botar a
mão no código.
▸Criar documentos auxiliares
▸Documentos ajudará a analisar o que foi solicitado
▸Documentos também ajudará a esclarecer se está tudo
dentro dos requerimentos
▸Ter um mapa de passo-a-passo do que irá realizar
9. PASSO 1 - QUAL CAMADA(S) SERÁ NECESSÁRIO DESENVOLVER?
RESPOSTA #2 - CAMADAS
▸Independente de qual for a camada, inicie priorizando pelo
topo (resultado final)
▸Realize um Fluxo de Desenvolvimento para cada Camada
10. PASSO 1 - ONDE SERÁ PRECISO FOCAR PRIMEIRO?
RESPOSTA #3 - FOCO
▸Na funcionalidade
▸Evite planejar toda a arquitetura que será utilizada
▸Foque no objetivo final
▸Foque na entrega que precisa ser realizada
11. PASSO 2
SPECS - TASKS - TICKETS
▸Extrair sempre o máximo as informações corretas
▸Montar seu DOCUMENTO auxiliar baseado nas
informações
▸Specs podem vir BEM estruturados ou NÃO
14. PASSO 2
EXTRAINDO INFORMAÇÕES
▸Uma Inspeção poderá ter muitas Fotos
▸Cada foto poderá ter uma descrição
▸Qual o formato do recebimento da foto (Url, Base64)?
▸Qual o formato de retorno da foto (Url, Base64)?
▸Como será o Endpoint?
▸Quais ações precisará ser feita?
▸Precisará criar apenas Foto?
▸Precisará enviar algum email ou confirmação?
▸Será recebido múltiplas fotos no endpoint?
15. PASSO 2
CRIAR DOCUMENTAÇÃO AUXILIAR
▸Vamos utilizar o Mapa Mental para documentar
▸Vamos Mapear:
▸Passo-a-passo
▸O que iremos utilizar
▸Estrutura
▸Adicionar nele toda a extração feita
17. PASSO 3
IMPLEMENTAÇÃO
▸Focar o resultado final
▸Utilizar TDD
▸Iniciar pelo Topo
▸Iniciar sem pensar muito a frente na Estrutura
▸Fazer em Baby steps (Passos de Bebê)
21. PASSO 3
require 'rails_helper'
describe 'Api::V1::Inspections::PhotosController' do
it 'It is working' do
expect(true).to be true
end
end
▸Criar primeiro o arquivo de teste para verificar se está tudo funcionando
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
23. PASSO 3
require 'rails_helper'
describe Api::V1::Inspections::PhotosController do
it 'It is working' do
expect(true).to be true
end
end
▸Atualizar o teste
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
25. PASSO 3
module Api
module V1
module Inspections
class PhotosController < ApplicationController
end
end
end
end
▸Criar PhotosController
* app/controllers/api/v1/inspections/photos_controller.rb
27. PASSO 3
require 'rails_helper'
describe Api::V1::Inspections::PhotosController, type: :controller do
describe 'POST /api/v1/inspections/:inspection_id/photos' do
before do
post :create, params: { inspection_id: 1 }
end
it 'Should create an inspection photo' do
expect(response.status).to be == 201
end
end
end
▸Adicionar primeiro endpoint
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
29. PASSO 3
module Api
module V1
module Inspections
class PhotosController < ApplicationController
def create
render json: {}, status: 201
end
end
end
end
end
▸Atualizar Controller - Adicionar o create método
* app/controllers/api/v1/inspections/photos_controller.rb
30. PASSO 3
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
namespace :inspections do
post ':inspection_id/photos', to: 'photos#create'
end
end
end
end
▸Editar Rotas
* config/routes.rb
32. PASSO 3
describe 'POST /api/v1/inspections/:inspection_id/photos' do
let(:json) { JSON.parse response.body }
before do
post :create, params: { inspection_id: 1 }
end
it 'Should create an inspection photo' do
expect(response.status).to be == 201
expected_response = {
'id' => 11,
'inspection_id' => 1,
'photo_url' => 'http://chid.com/inspection/photo_some_hash_64',
'caption' => nil,
}
expect(json).to match expected_response
end
end
▸Atualizar o Expect result no teste
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
36. PASSO 3
describe 'POST /api/v1/inspections/:inspection_id/photos' do
let(:json) { JSON.parse response.body }
before do
post :create, params: { inspection_id: 1, photo_base_64: 'some_hash_64' }
end
it 'Should create an inspection photo' do
expect(response.status).to be == 201
expected_response = {
'id' => 11,
'inspection_id' => 1,
'photo_url' => 'http://chid.com/inspection/photo_some_hash_64',
'caption' => nil,
}
expect(json).to match expected_response
end
end
▸Atualizar parâmetros de request
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
40. PASSO 3
class CreateInspection < ActiveRecord::Migration[5.2]
def change
create_table :inspections do |t|
t.string :description
t.timestamps null: false
end
end
end
▸Adicionar Banco de Dados - Inspection Migration
* db/migrate/20180922035522_create_inspection.rb
41. PASSO 3
class CreateInspectionPhoto < ActiveRecord::Migration[5.2]
def change
create_table :inspection_photos do |t|
t.references :inspection, foreign_key: true, null: false
t.string :photo_url, null: false
t.string :caption
t.timestamps null: false
end
end
end
▸InspectionPhoto Migration
* db/migrate/20180922035631_create_inspection_photo.rb
44. PASSO 3
describe 'POST /api/v1/inspections/:inspection_id/photos' do
let(:json) { JSON.parse response.body }
let(:inspection) { ::Inspection.create(description: 'Inspection 001') }
before do
post :create, params: { inspection_id: inspection.id, photo_base_64: 'some_hash_64' }
end
it 'Should create an inspection photo' do
expect(response.status).to be == 201
expected_response = {
'id' => 11,
'inspection_id' => inspection.id,
'photo_url' => 'http://chid.com/inspection/photo_some_hash_64',
'caption' => nil,
}
expect(json).to match expected_response
end
end
▸Atualizar Setup para utilizar Banco de Dados
* spec/controllers/api/v1/inspections/photos_controller_spec.rb
51. PASSO 3
O QUE TEMOS ATÉ AGORA?
▸Cobertura do código com os testes de Integração
▸Resultado final de acordo com o que foi solicitado
52. PASSO 3
IMPLEMENTAÇÃO ACABOU?
▸Agora que é a hora de:
▸ Começar a Refatorar para valer!
▸Arquiteturar o necessário para seu projeto
▸Nada!
▸Adicionar UseCases, Services, Presenters, Repositories etc
53. PASSO 3
IMPLEMENTAÇÃO - RESULTADO FINAL
▸Github repositório:
https://github.com/rachidcalazans/inspection_app_final.git