SlideShare a Scribd company logo
1 of 159
Refatoração em Larga
       Escala
     Danilo Sato - @dtsato
        ThoughtWorks
       www.dtsato.com
8 países


  0+ esc ritórios
2

                                          On & off shore

1600+ pessoas
                       $200m receita
                    US
8 países


  0+ esc ritórios
2

                                               On & off shore

1600+ pessoas
                           $200m receita
                        US
                   Estam os contratando!
                                                      s
                                   r ent-opportunitie
      http://thou ghtworks.com/cur
Por que mudamos
     código?
Por que mudamos
         código?
• Adicionar funcionalidade
Por que mudamos
         código?
• Adicionar funcionalidade
• Arrumar bugs
Por que mudamos
         código?
• Adicionar funcionalidade
• Arrumar bugs
• Melhorar o design
Por que mudamos
         código?
• Adicionar funcionalidade
• Arrumar bugs
• Melhorar o design
• Otimização
Por que mudamos
         código?
• Adicionar funcionalidade
• Arrumar bugs
• Melhorar o design
• Otimização
"Refatoração é uma técnica
 disciplinada para reestruturar
código, alterando sua estrutura
    interna sem alterar seu
   comportamento externo"
Refatoração

    Código
Refatoração

    Código
Refatoração

    Código




             Extr air Método
Refatoração

    Código
Refatoração

    Código
Refatoração

    Código




             Eliminar Duplicação
•   Extrair Método

•   Mover Método

•   Extrair Classe

•   Remover Mediador

•   Auto-Encapsular Atributo

•   Decompor Condicional

•   ...
Testes!
                  Código

Teste
Testes!
                  Código

Teste
Testes!
                     Código

Teste




                  Eliminar Duplicação
Outros tipos...

                 Código
Teste
Outros tipos...

              Código   Código
Teste
Outros tipos...

                  Código   Código
Teste   Teste
Outros tipos...

                  Código      Código
Teste   Teste




                      Se paração de
                     Respons abilidades
Outros tipos...

                 Código
Teste
Outros tipos...

Teste           Código
Outros tipos...

Teste           Código
Outros tipos...

Teste             Código




                Mudança no Design
Ainda mais...
“Big Picture”
“Big Picture”
“Big Picture”
“Big Picture”
“Big Picture”
Estratégia




Mecânica
Coding Kata!
Coding Kata!
Estratégia




Mecânica
CheckoutControllerTest   CheckoutController



                         Order        Cart
m/dtsato/refact oring-experiment
ht tp://github.co
                                                     -
                 mant.com/2011/0 9/01/refactoring
http://paulham
experiment




   CheckoutControllerTest            CheckoutController



                                     Order        Cart
public class CheckoutControllerTest {

    private   CheckoutController checkoutController;
    private   Cart cart = new Cart(); // could as easily be a mock
    private   Order order = new Order(); // could as easily be a mock
    private   ModelMap model = new ModelMap();

    @Before public void setup() {
        checkoutController = new CheckoutController(cart, order);
    }

    @Test public void checkout_should_add_an_upsell() {
        String result = checkoutController.goCheckout(model);
        assertThat(result, equalTo("checkout"));
        assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}"));
    }

    @Test public void place_order_in_checkout_should_make_an_order() {
        cart.addTo("dummy");
        String result = checkoutController.placeOrder(model);
        assertThat(result, equalTo("orderPlaced"));
        assertThat(model.toString(),
equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}"));
    }

}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
@Controller public class CheckoutController {
                                                   “Extrair Clas
                                                                 se”
    private final Cart cart;                       OrderControll
                                                                 er em
    private final Order order;                     placeOrder()
                                                                gerando get/s
                                                                              et
    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;
    private final OrderController orderController = new OrderController(this);

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return orderController.placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }

    public Order getOrder() { return order; }
    public Cart getCart() { return cart; }
}
@Controller public class CheckoutController {
                                                                     ⌘⌥N
    private final Cart cart;
                                                    “Inline” inic
    private final Order order;                                     ialização de
    private final OrderController orderController = orderController
                                                    new OrderController(this);

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return orderController.placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }

    public Order getOrder() { return order; }
    public Cart getCart() { return cart; }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return new OrderController(this).placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }

    public Order getOrder() { return order; }
    public Cart getCart() { return cart; }
}
public class OrderController {
    private final CheckoutController checkoutController;

    public OrderController(CheckoutController checkoutController) {
        this.checkoutController = checkoutController;
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        checkoutController.getOrder().place(checkoutController.getCart());
        model.addAttribute("order", checkoutController.getOrder());
        return "orderPlaced";
    }
}
⌘⌥F

                                            “Introduzir a
                                                          tributo” orde
                                            cart em Order               r e
                                                         Controller
public class OrderController {
    private final CheckoutController checkoutController;

    public OrderController(CheckoutController checkoutController) {
        this.checkoutController = checkoutController;
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        checkoutController.getOrder().place(checkoutController.getCart());
        model.addAttribute("order", checkoutController.getOrder());
        return "orderPlaced";
    }
}
public class OrderController {
    private final CheckoutController checkoutController;
    private final Order order;
    private final Cart cart;

    public OrderController(CheckoutController checkoutController) {
        this.checkoutController = checkoutController;
        order = this.checkoutController.getOrder();
        cart = this.checkoutController.getCart();
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }
}
⌘⌥P / ⌥    / ⌘Y
                                             “Introduzir p
                                                           arâmetro” ord
                                             e cart no con               er
public class OrderController {                             strutor de
                                            OrderControl
    private final CheckoutController checkoutController; ler e inic
                                                                    ializar
    private final Order order;
    private final Cart cart;

    public OrderController(CheckoutController checkoutController) {
        this.checkoutController = checkoutController;
        order = this.checkoutController.getOrder();
        cart = this.checkoutController.getCart();
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }
}
public class OrderController {
    private final CheckoutController checkoutController;
    private final Order order;
    private final Cart cart;

    public OrderController(CheckoutController checkoutController,
                            Order order, Cart cart) {
        this.checkoutController = checkoutController;
        this.order = order;
        this.cart = cart;
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }
}
⌘⌫
                                             “Remoção Segu
                                                           ra” do atribu
public class OrderController {               e parâmetro                 to
    private final CheckoutController checkoutController;
                                            checkoutContr
                                                          oller
    private final Order order;
    private final Cart cart;

    public OrderController(CheckoutController checkoutController,
                            Order order, Cart cart) {
        this.checkoutController = checkoutController;
        this.order = order;
        this.cart = cart;
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }
}
public class OrderController {
    private final Order order;
    private final Cart cart;

    public OrderController(Order order, Cart cart) {
        this.order = order;
        this.cart = cart;
    }

    @RequestMapping("/place/order")
    public String placeOrder(ModelMap model) {
        order.place(cart);
        model.addAttribute("order", order);
        return "orderPlaced";
    }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return new OrderController(order, cart).placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }

    public Order getOrder() { return order; }
    public Cart getCart() { return cart; }
}
@Controller public class CheckoutController {
                                                                     ⌘⌫
                                                   “Remoção Segu
    private final Cart cart;                                     ra” de getCar
                                                   e getOrder()                t()
    private final Order order;                                   em
                                                   CheckoutContr
                                                                 oller
    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return new OrderController(order, cart).placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }

    public Order getOrder() { return order; }
    public Cart getCart() { return cart; }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return new OrderController(order, cart).placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
⌘⌥N
@Controller public class CheckoutController {      “Inline” méto
                                                                 do placeOrder
                                                   mudar argumen               e
    private final Cart cart;                                     tos para usar
                                                   cart e order
    private final Order order;                                  no teste

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    @RequestMapping("/place/order") public String placeOrder(ModelMap model) {
        return new OrderController(order, cart).placeOrder(model);
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
public class CheckoutControllerTest {

    private   CheckoutController checkoutController;
    private   Cart cart = new Cart(); // could as easily be a mock
    private   Order order = new Order(); // could as easily be a mock
    private   ModelMap model = new ModelMap();

    @Before public void setup() {
        checkoutController = new CheckoutController(cart, order);
    }

    @Test public void checkout_should_add_an_upsell() {
        String result = checkoutController.goCheckout(model);
        assertThat(result, equalTo("checkout"));
        assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}"));
    }

    @Test public void place_order_in_checkout_should_make_an_order() {
        cart.addTo("dummy");
        String result = new OrderController(order, cart).placeOrder(model);
        assertThat(result, equalTo("orderPlaced"));
        assertThat(model.toString(),
equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}"));
    }

}
public class CheckoutControllerTest {
                                                                    ⌘⌥F
                                                    “  Introduzir at
    private   CheckoutController checkoutController;                  ributo”
    private                                           or be a ntro
              Cart cart = new Cart(); // could as easily derComock ller no
                                                                           teste,
    private                                           inicialia ando
              Order order = new Order(); // could as easily be z mock no
                                                                         setUp()
    private   ModelMap model = new ModelMap();

    @Before public void setup() {
        checkoutController = new CheckoutController(cart, order);
    }

    @Test public void checkout_should_add_an_upsell() {
        String result = checkoutController.goCheckout(model);
        assertThat(result, equalTo("checkout"));
        assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}"));
    }

    @Test public void place_order_in_checkout_should_make_an_order() {
        cart.addTo("dummy");
        String result = new OrderController(order, cart).placeOrder(model);
        assertThat(result, equalTo("orderPlaced"));
        assertThat(model.toString(),
equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}"));
    }

}
public class CheckoutControllerTest {

    private   CheckoutController checkoutController;
    private   Cart cart = new Cart(); // could as easily be a mock
    private   Order order = new Order(); // could as easily be a mock
    private   ModelMap model = new ModelMap();
    private   OrderController orderController;

   @Before public void setup() {
       checkoutController = new CheckoutController(cart, order);
       orderController = new OrderController(order, cart);
   }

   @Test public void checkout_should_add_an_upsell() {
       String result = checkoutController.goCheckout(model);
       assertThat(result, equalTo("checkout"));
       assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}"));
   }

    @Test public void place_order_in_checkout_should_make_an_order() {
        cart.addTo("dummy");
        String result = orderController.placeOrder(model);
        assertThat(result, equalTo("orderPlaced"));
        assertThat(model.toString(),
equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}"));
    }
}
@Controller public class CheckoutController {

    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
⌘⌫
                                                   “Remoção Segu
                                                                 ra” do atribu
                                                   e parâmetro o               to
@Controller public class CheckoutController {                    rder no
                                                   CheckoutContr
                                                                 oller
    private final Cart cart;
    private final Order order;

    @Autowired public CheckoutController(Cart cart, Order order) {
        this.cart = cart;
        this.order = order;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
@Controller public class CheckoutController {

    private final Cart cart;

    @Autowired public CheckoutController(Cart cart) {
        this.cart = cart;
    }

    @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) {
        // other stuff
        cart.addTo(findUpsell(cart));
        model.addAttribute("cart", cart);
        return "checkout";
    }

    String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; }
}
Estratégia




Mecânica
Identificar Objetivo
Identificar Objetivo
Identificar Objetivo
    Design “ativo”
Identificar Objetivo
            Design “ativo”




•   Design OO
Identificar Objetivo
              Design “ativo”




•   Design OO

•   Direção do Projeto
Identificar Objetivo
              Design “ativo”




•   Design OO

•   Direção do Projeto

•   Decisões Arquiteturais
Identificar Objetivo
    Design “passivo”
Identificar Objetivo
             Design “passivo”




•   Maus Cheiros
Identificar Objetivo
               Design “passivo”




•   Maus Cheiros

•   Métricas
Identificar Objetivo
               Design “passivo”




•   Maus Cheiros

•   Métricas

•   Visualizações
Traçar Estratégia
Traçar Estratégia


    ?            ?

?
Traçar Estratégia
Traçar Estratégia

• Isole o Impacto das Mudanças
Traçar Estratégia

• Isole o Impacto das Mudanças
• Baby Steps
Traçar Estratégia

• Isole o Impacto das Mudanças
• Baby Steps
• Mantenha os testes passando
Traçar Estratégia

•   Isole o Impacto das Mudanças
•   Baby Steps
•   Mantenha os testes passando
•   Ir para trás antes de ir para frente
CalendarSearchController
                           CalendarSearchController
          Test



         Event                      Event
r
                       dtsato/kata-ref actoring-calenda
http ://github.com/




  CalendarSearchController
                                    CalendarSearchController
            Test



           Event                             Event
def index(params)
  scope = Event

  case params[:timeframe]
  when 'tomorrow'
    scope = scope.between_day(DateTime.now + 1)
  when 'this_week'
    scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day)
  when 'custom'
    if params[:start_date].blank?
      params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y')
    end
    if params[:end_date].blank?
      params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y')
    end
    scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'),
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day)
  when 'hour'
    scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H:
%M'))
  when 'today'
    scope = scope.between_day(DateTime.now)
  end

  @events = scope.all
end
def index(params)
  scope = Event                      switch/case
  case params[:timeframe]
  when 'tomorrow'
    scope = scope.between_day(DateTime.now + 1)
  when 'this_week'
    scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day)
  when 'custom'
    if params[:start_date].blank?
      params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y')
    end
    if params[:end_date].blank?
      params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y')
    end
    scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'),
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day)
  when 'hour'
    scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H:
%M'))
  when 'today'
    scope = scope.between_day(DateTime.now)
  end

  @events = scope.all
end
def index(params)
  scope = Event

  case params[:timeframe]
  when 'tomorrow'
    scope = scope.between_day(DateTime.now + 1)
  when 'this_week'
                                                                string parsing
    scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day)
  when 'custom'
    if params[:start_date].blank?
      params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y')
    end
    if params[:end_date].blank?
      params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y')
    end
    scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'),
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day)
  when 'hour'
    scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H:
%M'))
  when 'today'
    scope = scope.between_day(DateTime.now)
  end

  @events = scope.all
end
def index(params)
  scope = Event

  case params[:timeframe]
  when 'tomorrow'
    scope = scope.between_day(DateTime.now + 1)
  when 'this_week'
    scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day)
  when 'custom'
    if params[:start_date].blank?
      params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y')
    end
    if params[:end_date].blank?
      params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y')
    end
    scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'),
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day)
  when 'hour'
    scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H:
%M'))
  when 'today'
    scope = scope.between_day(DateTime.now)
  end
                                                  vários named scopes
  @events = scope.all
end
class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] }
  }

 named_scope :between_hour_on_day, lambda { |start_hour|
   end_date = start_hour + 1.hour-1.second
   { :conditions => {:at => start_hour..end_date} }
 }

  named_scope :between_day, lambda { |date|
    start_date = date.at_beginning_of_day
    end_date = start_date.end_of_day
    { :conditions => {:at => start_date..end_date} }
  }
end
jeitos diferentes de
                                                  fazer a mesma
class Event < ActiveRecord::Base
                                                       coisa
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] }
  }

 named_scope :between_hour_on_day, lambda { |start_hour|
   end_date = start_hour + 1.hour-1.second
   { :conditions => {:at => start_hour..end_date} }
 }

  named_scope :between_day, lambda { |date|
    start_date = date.at_beginning_of_day
    end_date = start_date.end_of_day
    { :conditions => {:at => start_date..end_date} }
  }
end
class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] }
  }

 named_scope :between_hour_on_day, lambda { |start_hour|
   end_date = start_hour + 1.hour-1.second
   { :conditions => {:at => start_hour..end_date} }
 }
                                                        mais lógica
  named_scope :between_day, lambda { |date|
    start_date = date.at_beginning_of_day
    end_date = start_date.end_of_day
    { :conditions => {:at => start_date..end_date} }
  }
end
Objetivos

Ativo:

 • Isolar testes unitários do banco de dados
Passivo:

 • Tratar dos maus cheiros
O Plano

1. Centralizar a lógica de manipulação de datas

2. Unificar named scopes

3. Extrair lógica do Controller

4. Quebrar timeframe em vários pedaços
def index(params)
  case params[:timeframe]
  when 'tomorrow'
    date = DateTime.now + 1
    start_date = date.at_beginning_of_day
    end_date = start_date.end_of_day
  when 'this_week'
    start_date = DateTime.now
    end_date = (DateTime.now + 6 ).end_of_day
  when 'custom'
    start_date = params[:start_date].blank? ? DateTime.now.beginning_of_week :
DateTime.strptime(params[:start_date], '%m/%d/%Y')
    end_date = params[:end_date].blank? ? (DateTime.now.end_of_week - 2) :
DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day
  when 'hour'
    start_date = DateTime.strptime(params[:hour], '%m/%d/%Y %H:%M')
    end_date = start_date + 1.hour-1.second
  when 'today'
    date = DateTime.now
    start_date = date.at_beginning_of_day
    end_date = start_date.end_of_day
  end

  @events = Event.between_dates(start_date, end_date)
end
class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => {:at => start_date..end_date}}
  }
end
class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => {:at => start_date..end_date}}
  }
end


  lib/calendar_search_controller.rb |     27 +++++++++++++--------------
  lib/event.rb                      |     13 +------------
  spec/event_spec.rb                |     37 -------------------------------------
  3 files changed, 14 insertions(+), 63   deletions(-)
Antes
              .
 ............
                             ds
              0 .49367 secon
 Finished in           res
 13 examp les, 0 failu




class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => {:at => start_date..end_date}}
  }
end


  lib/calendar_search_controller.rb |     27 +++++++++++++--------------
  lib/event.rb                      |     13 +------------
  spec/event_spec.rb                |     37 -------------------------------------
  3 files changed, 14 insertions(+), 63   deletions(-)
Antes                                          Depois
                                                   .......
              .
 ............
                             ds                   Finished in
              0 .49367 secon                                  0.25355 seco
 Finished in           res                        7 examples,              nds
 13 examp les, 0 failu                                        0 failures




class Event < ActiveRecord::Base
  named_scope :between_dates, lambda { |start_date, end_date|
    {:conditions => {:at => start_date..end_date}}
  }
end


  lib/calendar_search_controller.rb |     27 +++++++++++++--------------
  lib/event.rb                      |     13 +------------
  spec/event_spec.rb                |     37 -------------------------------------
  3 files changed, 14 insertions(+), 63   deletions(-)
O Plano

1. Centralizar a lógica de manipulação de datas

2. Unificar named scopes

3. Extrair lógica do Controller

4. Quebrar timeframe em vários pedaços
class CalendarSearchController
  attr_reader :events

  def index(params)
    timeframe = TimeFrame.for(params[:timeframe], params[:start_date],
params[:end_date], params[:hour])
    @events = Event.between_dates(timeframe.start_date, timeframe.end_date)
  end
end

                       mudança nos testes:
it "should create time frame from params and retrieve events" do
  timeframe = TimeFrame.new(DateTime.now, DateTime.now)
  TimeFrame.should_receive(:for).with('today', 'start', 'end',
'hour').and_return(timeframe)

  events = [Event.new, Event.new]
  Event.should_receive(:between_dates).with(timeframe.start_date,
timeframe.end_date).and_return(events)

  @controller.index(:timeframe => 'today', :start_date => 'start', :end_date =>
'end', :hour => 'hour')

  @controller.events.should == events
end
describe "Acceptance tests" do
  around(:each) do |example|
    Event.transaction { example.run; raise ActiveRecord::Rollback }
  end

 before do
   @controller = CalendarSearchController.new
   @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
   DateTime.stub!(:now).and_return(@today)
 end

 it "should return today's events" do
   today_events = [Event.create(:at => @today), Event.create(:at => @today)]
   tomorrow = @today + 1

   tomorrow_events = [Event.create(:at => tomorrow), Event.create(:at => tomorrow)]

   @controller.index(:timeframe => 'today')
   @controller.events.should == today_events
 end

  it   "should return tomorrow's events" ...
  it   "should return this week's events" ...
  it   "should return events for specified date range" ...
  it   "should default date range to this business week" ...
  it   "returns events for a specified hour" ...
end
describe "Acceptance tests" do
  around(:each) do |example|                                    Depois
                                                    ......
    Event.transaction { example.run; raise ActiveRecord::Rollback }
  end
                                                     Finished in
                                                                 0.24538 seco
 before do                                           6 examples,              nds
                                                                 0 failures
   @controller = CalendarSearchController.new
   @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
   DateTime.stub!(:now).and_return(@today)
 end

 it "should return today's events" do
   today_events = [Event.create(:at => @today), Event.create(:at => @today)]
   tomorrow = @today + 1

   tomorrow_events = [Event.create(:at => tomorrow), Event.create(:at => tomorrow)]

   @controller.index(:timeframe => 'today')
   @controller.events.should == today_events
 end

  it   "should return tomorrow's events" ...
  it   "should return this week's events" ...
  it   "should return events for specified date range" ...
  it   "should default date range to this business week" ...
  it   "returns events for a specified hour" ...
end
class TimeFrame < Struct.new(:start_date, :end_date)
  def self.for(type, start_date, end_date, hour)
    case type
    when 'tomorrow'
      date = DateTime.now + 1
      TimeFrame.new(date.at_beginning_of_day, date.end_of_day)
    when 'this_week'
      TimeFrame.new(DateTime.now, (DateTime.now + 6 ).end_of_day)
    when 'custom'
      start_date = start_date.blank? ? DateTime.now.beginning_of_week :
DateTime.strptime(start_date, '%m/%d/%Y')
      end_date = end_date.blank? ? (DateTime.now.end_of_week - 2) :
DateTime.strptime(end_date, '%m/%d/%Y').end_of_day
      TimeFrame.new(start_date, end_date)
    when 'hour'
      start_date = DateTime.strptime(hour, '%m/%d/%Y %H:%M')
      end_date = start_date + 1.hour-1.second
      TimeFrame.new(start_date, end_date)
    when 'today'
      date = DateTime.now
      TimeFrame.new(date.at_beginning_of_day, date.end_of_day)
    end
  end
end
describe TimeFrame do
  before do
    @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
    DateTime.stub!(:now).and_return(@today)
  end

  describe "today's event" do
    it "should use beginning and end of day" do
      timeframe = TimeFrame.for('today', nil, nil, nil)

      timeframe.start_date.should == @today.at_beginning_of_day
      timeframe.end_date.should == @today.end_of_day
    end
  end
  ...
end
describe TimeFrame do
  before do
    @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
    DateTime.stub!(:now).and_return(@today)
  end

  describe "today's event" do
    it "should use beginning and end of day" do
      timeframe = TimeFrame.for('today', nil, nil, nil)

      timeframe.start_date.should == @today.at_beginning_of_day
      timeframe.end_date.should == @today.end_of_day
    end
  Rakefile                            |    4 ++
  end
  lib/calendar_search_controller.rb   |   24 +---------
  ...
  lib/time_frame.rb                   |   24 ++++++++++
end
  spec/acceptance_tests.rb            |   75 +++++++++++++++++++++++++++++++
  spec/calendar_search_controller_spec.rb |   75 ++++---------------------------
  spec/time_frame_spec.rb                 |   63 ++++++++++++++++++++++++++
  6 files changed, 178 insertions(+), 87 deletions(-)
Antes
 .......
                             ds
describe d in 0 .25355 secon
 Finishe TimeFrame do es
  before les, 0 failur
  7 examp do
    @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
    DateTime.stub!(:now).and_return(@today)
  end

  describe "today's event" do
    it "should use beginning and end of day" do
      timeframe = TimeFrame.for('today', nil, nil, nil)

      timeframe.start_date.should == @today.at_beginning_of_day
      timeframe.end_date.should == @today.end_of_day
    end
  Rakefile                            |    4 ++
  end
  lib/calendar_search_controller.rb   |   24 +---------
  ...
  lib/time_frame.rb                   |   24 ++++++++++
end
  spec/acceptance_tests.rb            |   75 +++++++++++++++++++++++++++++++
  spec/calendar_search_controller_spec.rb |   75 ++++---------------------------
  spec/time_frame_spec.rb                 |   63 ++++++++++++++++++++++++++
  6 files changed, 178 insertions(+), 87 deletions(-)
Antes                                          Depois
                                                 ........
 .......
                             ds             Finished in
describe d in 0 .25355 secon
      she TimeFrame do
                                                         0.17938 seco
                                                                      nds
 Fini                                       8 examples,
  before les, 0 failures
  7 ex amp do
                                                         0 failures
    @today = DateTime.strptime('06/01/2011', '%m/%d/%Y')
    DateTime.stub!(:now).and_return(@today)
  end

  describe "today's event" do
    it "should use beginning and end of day" do
      timeframe = TimeFrame.for('today', nil, nil, nil)

      timeframe.start_date.should == @today.at_beginning_of_day
      timeframe.end_date.should == @today.end_of_day
    end
  Rakefile                            |    4 ++
  end
  lib/calendar_search_controller.rb   |   24 +---------
  ...
  lib/time_frame.rb                   |   24 ++++++++++
end
  spec/acceptance_tests.rb            |   75 +++++++++++++++++++++++++++++++
  spec/calendar_search_controller_spec.rb |   75 ++++---------------------------
  spec/time_frame_spec.rb                 |   63 ++++++++++++++++++++++++++
  6 files changed, 178 insertions(+), 87 deletions(-)
O Plano

1. Centralizar a lógica de manipulação de datas

2. Unificar named scopes

3. Extrair lógica do Controller

4. Quebrar timeframe em vários pedaços
class TimeFrame
  attr_reader :start_date, :end_date

  class Today < TimeFrame
    def initialize
      date = DateTime.now
      @start_date, @end_date = date.at_beginning_of_day, date.end_of_day
    end
  end

  ...
end



describe TimeFrame::Today do
  it "should use beginning and end of day" do
    timeframe = TimeFrame::Today.new

    timeframe.start_date.should == @today.at_beginning_of_day
    timeframe.end_date.should == @today.end_of_day
  end

  ...
end
class TimeFrame
  ...
  def self.for(type, start_date, end_date, hour)
    case type
    when 'tomorrow' then Tomorrow.new
    when 'this_week' then ThisWeek.new
    when 'custom' then Custom.new(start_date, end_date)
    when 'hour' then Hour.new(hour)
    when 'today' then Today.new
    end
  end
end



describe TimeFrame::Today do
  ...
  describe "parsing" do
    it "should parse today's timeframe" do
      TimeFrame.for('today', nil, nil, nil).should
be_an_instance_of(TimeFrame::Today)
    end
    ...
  end
end
class TimeFrame
  ...          Antes
 .def .self.for(type, start_date, end_date, hour)
   ... ...
     case type
                              ds
               0 .17938 secon
     when 'tomorrow' then Tomorrow.new
 Finished in
     when les, 0 failures ThisWeek.new
  8 examp 'this_week' then
     when 'custom' then Custom.new(start_date, end_date)
     when 'hour' then Hour.new(hour)
     when 'today' then Today.new
     end
  end
end



describe TimeFrame::Today do
  ...
  describe "parsing" do
    it "should parse today's timeframe" do
      TimeFrame.for('today', nil, nil, nil).should
be_an_instance_of(TimeFrame::Today)
    end
    ...
  end
end
class TimeFrame
  ...         Antes                                      Depois
                                              ............
  def .self.for(type, start_date, end_date, hour)         .
 ....  ...
    case type
                             ds              Finished in
    when d in 0 .17938 secon
      she 'tomorrow' then Tomorrow.new
                                                          0.19023 seco
                                                                       nds
 Fini                                        13 examples,
    when les, 0 failures ThisWeek.new
  8 examp 'this_week' then
                                                           0 failures
    when 'custom' then Custom.new(start_date, end_date)
    when 'hour' then Hour.new(hour)
    when 'today' then Today.new
    end
  end
end



describe TimeFrame::Today do
  ...
  describe "parsing" do
    it "should parse today's timeframe" do
      TimeFrame.for('today', nil, nil, nil).should
be_an_instance_of(TimeFrame::Today)
    end
    ...
  end
end
class TimeFrame
  ...         Antes                                      Depois
                                              ............
  def .self.for(type, start_date, end_date, hour)         .
 ....  ...
    case type
                             ds              Finished in
    when d in 0 .17938 secon
      she 'tomorrow' then Tomorrow.new
                                                          0.19023 seco
                                                                       nds
 Fini                                        13 examples,
    when les, 0 failures ThisWeek.new
  8 examp 'this_week' then
                                                           0 failures
    when 'custom' then Custom.new(start_date, end_date)
    when 'hour' then Hour.new(hour)
    when 'today' then Today.new
    end
  end
end



describe TimeFrame::Today do
  ...
  describe "parsing" do
  lib/time_frame.rb       |   59 +++++++++++++++++++++++++++++++++-------------
    it "should parse today's timeframe" do
  spec/time_frame_spec.rb |   44 ++++++++++++++++++++++++++--------
      TimeFrame.for('today', nil, nil, nil).should
  2 files changed, 75 insertions(+), 28 deletions(-)
be_an_instance_of(TimeFrame::Today)
    end
    ...
  end
end
Estratégia




Mecânica
“Big Picture”

• Mudanças Arquiteturais
• Unificação de abordagens diferentes
• Substituição de componentes/frameworks
“Big Picture”
“Big Picture”



Escopo    Risco   Esforço   Comunicação
Mikado Method




    Criar pacote para Stranger
            Eons Ltda.
Mikado Method




Criar projeto para
Stranger Eons Ltda.



                      Criar pacote para Stranger
                              Eons Ltda.
Mikado Method




Criar projeto para                                 Criar teste de aceitação
Stranger Eons Ltda.                                  para nova aplicação



                      Criar pacote para Stranger
                              Eons Ltda.
Mikado Method



                                                   Código de UI em projeto
                                                          separado



Criar projeto para                                 Criar teste de aceitação
Stranger Eons Ltda.                                  para nova aplicação



                      Criar pacote para Stranger
                              Eons Ltda.
Mikado Method

                                                    Mover código UI para
                                                       novo projeto

 Criar projeto UI
                                                   Código de UI em projeto
                                                          separado



Criar projeto para                                 Criar teste de aceitação
Stranger Eons Ltda.                                  para nova aplicação



                      Criar pacote para Stranger
                              Eons Ltda.
Mikado Method
    Quebrar dependência
circular entre Aplicação e UI

                                                          Mover código UI para
                                                             novo projeto

       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para                                 Criar teste de aceitação
      Stranger Eons Ltda.                                  para nova aplicação



                            Criar pacote para Stranger
                                    Eons Ltda.
Mikado Method
Extrair ApplicationInterface




    Quebrar dependência
circular entre Aplicação e UI

                                                          Mover código UI para
                                                             novo projeto

       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para                                 Criar teste de aceitação
      Stranger Eons Ltda.                                  para nova aplicação



                            Criar pacote para Stranger
                                    Eons Ltda.
Mikado Method
Extrair ApplicationInterface
                                                           Injetar instância de
                                                           ApplicationInterface


    Quebrar dependência
circular entre Aplicação e UI

                                                          Mover código UI para
                                                             novo projeto

       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para                                 Criar teste de aceitação
      Stranger Eons Ltda.                                  para nova aplicação



                            Criar pacote para Stranger
                                    Eons Ltda.
Mikado Method
        ✔
Extrair ApplicationInterface
                                                           Injetar instância de
                                                                                  ✔
                                                           ApplicationInterface


    Quebrar dependência
                          ✔
circular entre Aplicação e UI

                                                          Mover código UI para
                                                             novo projeto

       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para                                 Criar teste de aceitação
      Stranger Eons Ltda.                                  para nova aplicação



                            Criar pacote para Stranger
                                    Eons Ltda.
Mikado Method
        ✔
Extrair ApplicationInterface
                                                           Injetar instância de
                                                                                  ✔
                                                           ApplicationInterface


    Quebrar dependência
                          ✔
circular entre Aplicação e UI

                                                          Mover código UI para    ✔
                                                             novo projeto
                          ✔
                                                                                  ✔
       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para                                 Criar teste de aceitação
      Stranger Eons Ltda.                                  para nova aplicação



                            Criar pacote para Stranger
                                    Eons Ltda.
Mikado Method
        ✔
Extrair ApplicationInterface
                                                           Injetar instância de
                                                                                  ✔
                                                           ApplicationInterface


    Quebrar dependência
                          ✔
circular entre Aplicação e UI

                                                          Mover código UI para    ✔
                                                             novo projeto
                          ✔
                                                                                  ✔
       Criar projeto UI
                                                         Código de UI em projeto
                                                                separado



      Criar projeto para    ✔                            Criar teste de aceitação ✔
      Stranger Eons Ltda.                                  para nova aplicação




                                                     ✔
                            Criar pacote para Stranger
                                    Eons Ltda.
Uma história


          APP
Uma história


          APP

SVC
Uma história


          APP

SVC
Uma história


          APP

SVC
A verdade

            APP

            Model


            View


        Controller
A verdade

            APP

            Model


            View


        Controller


            Helper
A verdade

             APP

             Model


             View
SVC
         Controller


             Helper
A verdade

                      APP

                      Model


                      View
SVC
                    Controller

      vai quebrar
        tudo !!!
                     Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
  transição
             APP

             Model


             View


           Controller

 SVC
            Helper
Arquitetura de
         Transição
• Go:
 • “Branch by Abstraction”
 • Migrar de iBatis para Hibernate
 • Migrar de Velocity/JsTemplate para JRuby
    on Rails
Arquitetura de
              Transição
    • Go:
     • “Branch by Abstraction”
     • Migrar de iBatis para Hibernate
     • Migrar de Velocity/JsTemplate para JRuby
         on Rails
                                                     -
                                  0 11/05/make-large
http://continuo usdelivery.com/2
                                              -
                           l y-with-branch-by
scale-cha nges-incremental
abstraction/
Referências
Livros:
"Refactoring: Improving the Design of Existing Code" - Martin Fowler, Kent Beck, John
Brant, William Opdyke, Don Roberts
"Refactoring to Patterns" - Joshua Kerievsky
"Working Effectively with Legacy Code" - Michael Feathers
"Beheading the Software Beast: Relentless Restructurings with The Mikado Method" -
Daniel Brolund, Ola Ellnestam
Créditos (fotos):
http://www.flickr.com/photos/dhammza/2227347832/
http://www.flickr.com/photos/pragdave/173640462/
Links:
http://paulhammant.com/2011/09/01/refactoring-experiment
http://continuousdelivery.com/2011/05/make-large-scale-changes-incrementally-with-
branch-by-abstraction/
Código:
https://github.com/dtsato/refactoring_experiment
https://github.com/dtsato/kata-refactoring-calendar
S etembro (18h):
     Segun da-Feira, 12 de
                                / join-revolution
http://thought works.com/events
Obrigado!
Danilo Sato - @dtsato
   ThoughtWorks
  www.dtsato.com

More Related Content

What's hot

An Introduction to the World of Testing for Front-End Developers
An Introduction to the World of Testing for Front-End DevelopersAn Introduction to the World of Testing for Front-End Developers
An Introduction to the World of Testing for Front-End DevelopersFITC
 
The rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningsThe rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningschicagonewsyesterday
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascriptcrgwbr
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter ClientKenji Tanaka
 
Vivipos Order Schema Release 1 2 X Rev 1 2 1
Vivipos Order Schema Release 1 2 X Rev 1 2 1Vivipos Order Schema Release 1 2 X Rev 1 2 1
Vivipos Order Schema Release 1 2 X Rev 1 2 1racklin
 
Basically Redux - Android Listeners
Basically Redux - Android ListenersBasically Redux - Android Listeners
Basically Redux - Android ListenersCody Engel
 
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法Kenji Tanaka
 
描画とビジネスをクリーンに分ける(公開用)
描画とビジネスをクリーンに分ける(公開用)描画とビジネスをクリーンに分ける(公開用)
描画とビジネスをクリーンに分ける(公開用)Kenji Tanaka
 
Settings
SettingsSettings
Settingsyito24
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...OPITZ CONSULTING Deutschland
 
Performance improvements tips and tricks
Performance improvements tips and tricksPerformance improvements tips and tricks
Performance improvements tips and tricksdiego bragato
 
Simplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackSimplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackGabor Varadi
 

What's hot (18)

An Introduction to the World of Testing for Front-End Developers
An Introduction to the World of Testing for Front-End DevelopersAn Introduction to the World of Testing for Front-End Developers
An Introduction to the World of Testing for Front-End Developers
 
The rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screeningsThe rise and fall of a techno DJ, plus more new reviews and notable screenings
The rise and fall of a techno DJ, plus more new reviews and notable screenings
 
Android 3
Android 3Android 3
Android 3
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascript
 
Deep dive into Oracle ADF
Deep dive into Oracle ADFDeep dive into Oracle ADF
Deep dive into Oracle ADF
 
Hidden rocks in Oracle ADF
Hidden rocks in Oracle ADFHidden rocks in Oracle ADF
Hidden rocks in Oracle ADF
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter Client
 
Vivipos Order Schema Release 1 2 X Rev 1 2 1
Vivipos Order Schema Release 1 2 X Rev 1 2 1Vivipos Order Schema Release 1 2 X Rev 1 2 1
Vivipos Order Schema Release 1 2 X Rev 1 2 1
 
Basically Redux - Android Listeners
Basically Redux - Android ListenersBasically Redux - Android Listeners
Basically Redux - Android Listeners
 
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法
VC「もしかして...」Model「私たち...」「「入れ替わってるー!?」」を前前前世から防ぐ方法
 
描画とビジネスをクリーンに分ける(公開用)
描画とビジネスをクリーンに分ける(公開用)描画とビジネスをクリーンに分ける(公開用)
描画とビジネスをクリーンに分ける(公開用)
 
Settings
SettingsSettings
Settings
 
Maze
MazeMaze
Maze
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
 
Performance improvements tips and tricks
Performance improvements tips and tricksPerformance improvements tips and tricks
Performance improvements tips and tricks
 
Android wearpp
Android wearppAndroid wearpp
Android wearpp
 
Con5623 pdf 5623_001
Con5623 pdf 5623_001Con5623 pdf 5623_001
Con5623 pdf 5623_001
 
Simplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackSimplified Android Development with Simple-Stack
Simplified Android Development with Simple-Stack
 

Viewers also liked

XP In the Real World
XP In the Real WorldXP In the Real World
XP In the Real WorldCarlos Lopes
 
Multiple projects, different goals, one thing in common: the codebase! at Agi...
Multiple projects, different goals, one thing in common: the codebase! at Agi...Multiple projects, different goals, one thing in common: the codebase! at Agi...
Multiple projects, different goals, one thing in common: the codebase! at Agi...Carlos Lopes
 
The .NET Platform - A Brief Overview
The .NET Platform - A Brief OverviewThe .NET Platform - A Brief Overview
The .NET Platform - A Brief OverviewCarlos Lopes
 
Refactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsRefactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsDanilo Sato
 
Application versioning
Application versioningApplication versioning
Application versioningTed Steinmann
 
Continuous Delivery Overview
Continuous Delivery OverviewContinuous Delivery Overview
Continuous Delivery OverviewLuca Minudel
 
Trunk Based Development Explored
Trunk Based Development ExploredTrunk Based Development Explored
Trunk Based Development ExploredCarlos Lopes
 
Lessons from Deploying an EMR in Rural India
Lessons from Deploying an EMR in Rural IndiaLessons from Deploying an EMR in Rural India
Lessons from Deploying an EMR in Rural IndiaGurpreet Luthra
 
Web Vulnerabilities - Building Basic Security Awareness
Web Vulnerabilities - Building Basic Security AwarenessWeb Vulnerabilities - Building Basic Security Awareness
Web Vulnerabilities - Building Basic Security AwarenessGurpreet Luthra
 
Trunk Based Development
Trunk Based DevelopmentTrunk Based Development
Trunk Based DevelopmentCarlos Lopes
 
TDD and more than 9000 tries to sell it to a customer
TDD and more than 9000 tries to sell it to a customerTDD and more than 9000 tries to sell it to a customer
TDD and more than 9000 tries to sell it to a customerAnuar Nurmakanov
 
How Continuous Delivery and Lean Management Make your DevOps Amazeballs
How Continuous Delivery and Lean Management Make your DevOps AmazeballsHow Continuous Delivery and Lean Management Make your DevOps Amazeballs
How Continuous Delivery and Lean Management Make your DevOps AmazeballsNicole Forsgren
 
Continuous Delivery: Making DevOps Awesome
Continuous Delivery: Making DevOps AwesomeContinuous Delivery: Making DevOps Awesome
Continuous Delivery: Making DevOps AwesomeNicole Forsgren
 
Branching Strategies: Feature Branches vs Branch by Abstraction
Branching Strategies: Feature Branches vs Branch by AbstractionBranching Strategies: Feature Branches vs Branch by Abstraction
Branching Strategies: Feature Branches vs Branch by AbstractionChris Birchall
 
Multiple projects, different goals, one thing in common: the codebase!
Multiple projects, different goals, one thing in common: the codebase!Multiple projects, different goals, one thing in common: the codebase!
Multiple projects, different goals, one thing in common: the codebase!Carlos Lopes
 
Merge hells - Feature Toggles to the rescue
Merge hells - Feature Toggles to the rescueMerge hells - Feature Toggles to the rescue
Merge hells - Feature Toggles to the rescueLeena N
 
WANTED: Seeking Single Agile Knowledge Development Tool-set
WANTED: Seeking Single Agile Knowledge Development Tool-setWANTED: Seeking Single Agile Knowledge Development Tool-set
WANTED: Seeking Single Agile Knowledge Development Tool-setBrad Appleton
 
Is agile adoption losing steam?
Is agile adoption losing steam?Is agile adoption losing steam?
Is agile adoption losing steam?Go2Group, Inc.
 
Delphix modernization whitepaper
Delphix  modernization whitepaperDelphix  modernization whitepaper
Delphix modernization whitepaperFranco_Dagosto
 

Viewers also liked (20)

XP In the Real World
XP In the Real WorldXP In the Real World
XP In the Real World
 
Multiple projects, different goals, one thing in common: the codebase! at Agi...
Multiple projects, different goals, one thing in common: the codebase! at Agi...Multiple projects, different goals, one thing in common: the codebase! at Agi...
Multiple projects, different goals, one thing in common: the codebase! at Agi...
 
Cognitive Biases
Cognitive BiasesCognitive Biases
Cognitive Biases
 
The .NET Platform - A Brief Overview
The .NET Platform - A Brief OverviewThe .NET Platform - A Brief Overview
The .NET Platform - A Brief Overview
 
Refactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsRefactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the Basics
 
Application versioning
Application versioningApplication versioning
Application versioning
 
Continuous Delivery Overview
Continuous Delivery OverviewContinuous Delivery Overview
Continuous Delivery Overview
 
Trunk Based Development Explored
Trunk Based Development ExploredTrunk Based Development Explored
Trunk Based Development Explored
 
Lessons from Deploying an EMR in Rural India
Lessons from Deploying an EMR in Rural IndiaLessons from Deploying an EMR in Rural India
Lessons from Deploying an EMR in Rural India
 
Web Vulnerabilities - Building Basic Security Awareness
Web Vulnerabilities - Building Basic Security AwarenessWeb Vulnerabilities - Building Basic Security Awareness
Web Vulnerabilities - Building Basic Security Awareness
 
Trunk Based Development
Trunk Based DevelopmentTrunk Based Development
Trunk Based Development
 
TDD and more than 9000 tries to sell it to a customer
TDD and more than 9000 tries to sell it to a customerTDD and more than 9000 tries to sell it to a customer
TDD and more than 9000 tries to sell it to a customer
 
How Continuous Delivery and Lean Management Make your DevOps Amazeballs
How Continuous Delivery and Lean Management Make your DevOps AmazeballsHow Continuous Delivery and Lean Management Make your DevOps Amazeballs
How Continuous Delivery and Lean Management Make your DevOps Amazeballs
 
Continuous Delivery: Making DevOps Awesome
Continuous Delivery: Making DevOps AwesomeContinuous Delivery: Making DevOps Awesome
Continuous Delivery: Making DevOps Awesome
 
Branching Strategies: Feature Branches vs Branch by Abstraction
Branching Strategies: Feature Branches vs Branch by AbstractionBranching Strategies: Feature Branches vs Branch by Abstraction
Branching Strategies: Feature Branches vs Branch by Abstraction
 
Multiple projects, different goals, one thing in common: the codebase!
Multiple projects, different goals, one thing in common: the codebase!Multiple projects, different goals, one thing in common: the codebase!
Multiple projects, different goals, one thing in common: the codebase!
 
Merge hells - Feature Toggles to the rescue
Merge hells - Feature Toggles to the rescueMerge hells - Feature Toggles to the rescue
Merge hells - Feature Toggles to the rescue
 
WANTED: Seeking Single Agile Knowledge Development Tool-set
WANTED: Seeking Single Agile Knowledge Development Tool-setWANTED: Seeking Single Agile Knowledge Development Tool-set
WANTED: Seeking Single Agile Knowledge Development Tool-set
 
Is agile adoption losing steam?
Is agile adoption losing steam?Is agile adoption losing steam?
Is agile adoption losing steam?
 
Delphix modernization whitepaper
Delphix  modernization whitepaperDelphix  modernization whitepaper
Delphix modernization whitepaper
 

Similar to Refatoração em Larga Escala

Refactoring at Large
Refactoring at LargeRefactoring at Large
Refactoring at LargeDanilo Sato
 
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"LogeekNightUkraine
 
CodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigCodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigDusan Zamurovic
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design PrinciplesJon Kruger
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsŁukasz Chruściel
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsJarod Ferguson
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...Mateusz Zalewski
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsColin DeCarlo
 
Sylius and Api Platform The story of integration
Sylius and Api Platform The story of integrationSylius and Api Platform The story of integration
Sylius and Api Platform The story of integrationŁukasz Chruściel
 
Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片cfc
 
MBL205 Monetizing Your App on Kindle Fire - AWS re: Invent 2012
MBL205 Monetizing Your App on Kindle Fire  - AWS re: Invent 2012MBL205 Monetizing Your App on Kindle Fire  - AWS re: Invent 2012
MBL205 Monetizing Your App on Kindle Fire - AWS re: Invent 2012Amazon Web Services
 
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze..."Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...Mateusz Zalewski
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEDarwin Durand
 
LJC Conference 2014 Cassandra for Java Developers
LJC Conference 2014 Cassandra for Java DevelopersLJC Conference 2014 Cassandra for Java Developers
LJC Conference 2014 Cassandra for Java DevelopersChristopher Batey
 
Practical Event Sourcing
Practical Event SourcingPractical Event Sourcing
Practical Event SourcingMathias Verraes
 
So S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeSo S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeNeil Crookes
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design PatternsGodfrey Nolan
 

Similar to Refatoração em Larga Escala (20)

Refactoring at Large
Refactoring at LargeRefactoring at Large
Refactoring at Large
 
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
 
CodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigCodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPig
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
Solid principles
Solid principlesSolid principles
Solid principles
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
Sylius and Api Platform The story of integration
Sylius and Api Platform The story of integrationSylius and Api Platform The story of integration
Sylius and Api Platform The story of integration
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片
 
MBL205 Monetizing Your App on Kindle Fire - AWS re: Invent 2012
MBL205 Monetizing Your App on Kindle Fire  - AWS re: Invent 2012MBL205 Monetizing Your App on Kindle Fire  - AWS re: Invent 2012
MBL205 Monetizing Your App on Kindle Fire - AWS re: Invent 2012
 
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze..."Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
LJC Conference 2014 Cassandra for Java Developers
LJC Conference 2014 Cassandra for Java DevelopersLJC Conference 2014 Cassandra for Java Developers
LJC Conference 2014 Cassandra for Java Developers
 
Practical Event Sourcing
Practical Event SourcingPractical Event Sourcing
Practical Event Sourcing
 
So S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeSo S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better Code
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
 

More from Danilo Sato

Padrões de deploy para devops e entrega contínua - DevDay 2014
Padrões de deploy para devops e entrega contínua - DevDay 2014Padrões de deploy para devops e entrega contínua - DevDay 2014
Padrões de deploy para devops e entrega contínua - DevDay 2014Danilo Sato
 
Keynote RuPy Natal 2014
Keynote RuPy Natal 2014Keynote RuPy Natal 2014
Keynote RuPy Natal 2014Danilo Sato
 
Padrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaPadrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaDanilo Sato
 
Padrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaPadrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaDanilo Sato
 
Revisitando as Práticas de Engenharia Ágil
Revisitando as Práticas de Engenharia ÁgilRevisitando as Práticas de Engenharia Ágil
Revisitando as Práticas de Engenharia ÁgilDanilo Sato
 
O que você NÃO aprendeu sobre Programação Orientada a Objetos
O que você NÃO aprendeu sobre Programação Orientada a ObjetosO que você NÃO aprendeu sobre Programação Orientada a Objetos
O que você NÃO aprendeu sobre Programação Orientada a ObjetosDanilo Sato
 
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...Danilo Sato
 
Estratégias de Refatoração: além do be-a-bá
Estratégias de Refatoração: além do be-a-báEstratégias de Refatoração: além do be-a-bá
Estratégias de Refatoração: além do be-a-báDanilo Sato
 
Coding Dojo Introduction
Coding Dojo IntroductionCoding Dojo Introduction
Coding Dojo IntroductionDanilo Sato
 
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...Danilo Sato
 
Managing your technical debt - AgileBrazil 2011
Managing your technical debt - AgileBrazil 2011Managing your technical debt - AgileBrazil 2011
Managing your technical debt - AgileBrazil 2011Danilo Sato
 

More from Danilo Sato (12)

Padrões de deploy para devops e entrega contínua - DevDay 2014
Padrões de deploy para devops e entrega contínua - DevDay 2014Padrões de deploy para devops e entrega contínua - DevDay 2014
Padrões de deploy para devops e entrega contínua - DevDay 2014
 
Keynote RuPy Natal 2014
Keynote RuPy Natal 2014Keynote RuPy Natal 2014
Keynote RuPy Natal 2014
 
Padrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaPadrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega Contínua
 
Padrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega ContínuaPadrões de deploy para DevOps e Entrega Contínua
Padrões de deploy para DevOps e Entrega Contínua
 
Revisitando as Práticas de Engenharia Ágil
Revisitando as Práticas de Engenharia ÁgilRevisitando as Práticas de Engenharia Ágil
Revisitando as Práticas de Engenharia Ágil
 
O que você NÃO aprendeu sobre Programação Orientada a Objetos
O que você NÃO aprendeu sobre Programação Orientada a ObjetosO que você NÃO aprendeu sobre Programação Orientada a Objetos
O que você NÃO aprendeu sobre Programação Orientada a Objetos
 
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...
Princípios e Práticas para lidar com requisitos não-funcionais em desenvolvim...
 
Estratégias de Refatoração: além do be-a-bá
Estratégias de Refatoração: além do be-a-báEstratégias de Refatoração: além do be-a-bá
Estratégias de Refatoração: além do be-a-bá
 
Coding Dojo Introduction
Coding Dojo IntroductionCoding Dojo Introduction
Coding Dojo Introduction
 
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...
Direto das Trincheiras: Boas e más práticas de aplicações Ruby em ambientes c...
 
Managing your technical debt - AgileBrazil 2011
Managing your technical debt - AgileBrazil 2011Managing your technical debt - AgileBrazil 2011
Managing your technical debt - AgileBrazil 2011
 
Lean Lego Game
Lean Lego GameLean Lego Game
Lean Lego Game
 

Recently uploaded

Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 

Recently uploaded (20)

Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 

Refatoração em Larga Escala

  • 1. Refatoração em Larga Escala Danilo Sato - @dtsato ThoughtWorks www.dtsato.com
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8. 8 países 0+ esc ritórios 2 On & off shore 1600+ pessoas $200m receita US
  • 9. 8 países 0+ esc ritórios 2 On & off shore 1600+ pessoas $200m receita US Estam os contratando! s r ent-opportunitie http://thou ghtworks.com/cur
  • 10.
  • 11. Por que mudamos código?
  • 12. Por que mudamos código? • Adicionar funcionalidade
  • 13. Por que mudamos código? • Adicionar funcionalidade • Arrumar bugs
  • 14. Por que mudamos código? • Adicionar funcionalidade • Arrumar bugs • Melhorar o design
  • 15. Por que mudamos código? • Adicionar funcionalidade • Arrumar bugs • Melhorar o design • Otimização
  • 16. Por que mudamos código? • Adicionar funcionalidade • Arrumar bugs • Melhorar o design • Otimização
  • 17.
  • 18.
  • 19.
  • 20. "Refatoração é uma técnica disciplinada para reestruturar código, alterando sua estrutura interna sem alterar seu comportamento externo"
  • 21. Refatoração Código
  • 22. Refatoração Código
  • 23. Refatoração Código Extr air Método
  • 24. Refatoração Código
  • 25. Refatoração Código
  • 26. Refatoração Código Eliminar Duplicação
  • 27. Extrair Método • Mover Método • Extrair Classe • Remover Mediador • Auto-Encapsular Atributo • Decompor Condicional • ...
  • 28. Testes! Código Teste
  • 29. Testes! Código Teste
  • 30. Testes! Código Teste Eliminar Duplicação
  • 31. Outros tipos... Código Teste
  • 32. Outros tipos... Código Código Teste
  • 33. Outros tipos... Código Código Teste Teste
  • 34. Outros tipos... Código Código Teste Teste Se paração de Respons abilidades
  • 35. Outros tipos... Código Teste
  • 38. Outros tipos... Teste Código Mudança no Design
  • 49. CheckoutControllerTest CheckoutController Order Cart
  • 50. m/dtsato/refact oring-experiment ht tp://github.co - mant.com/2011/0 9/01/refactoring http://paulham experiment CheckoutControllerTest CheckoutController Order Cart
  • 51. public class CheckoutControllerTest { private CheckoutController checkoutController; private Cart cart = new Cart(); // could as easily be a mock private Order order = new Order(); // could as easily be a mock private ModelMap model = new ModelMap(); @Before public void setup() { checkoutController = new CheckoutController(cart, order); } @Test public void checkout_should_add_an_upsell() { String result = checkoutController.goCheckout(model); assertThat(result, equalTo("checkout")); assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}")); } @Test public void place_order_in_checkout_should_make_an_order() { cart.addTo("dummy"); String result = checkoutController.placeOrder(model); assertThat(result, equalTo("orderPlaced")); assertThat(model.toString(), equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}")); } }
  • 52. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 53. @Controller public class CheckoutController { “Extrair Clas se” private final Cart cart; OrderControll er em private final Order order; placeOrder() gerando get/s et @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 54. @Controller public class CheckoutController { private final Cart cart; private final Order order; private final OrderController orderController = new OrderController(this); @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return orderController.placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } public Order getOrder() { return order; } public Cart getCart() { return cart; } }
  • 55. @Controller public class CheckoutController { ⌘⌥N private final Cart cart; “Inline” inic private final Order order; ialização de private final OrderController orderController = orderController new OrderController(this); @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return orderController.placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } public Order getOrder() { return order; } public Cart getCart() { return cart; } }
  • 56. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return new OrderController(this).placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } public Order getOrder() { return order; } public Cart getCart() { return cart; } }
  • 57. public class OrderController { private final CheckoutController checkoutController; public OrderController(CheckoutController checkoutController) { this.checkoutController = checkoutController; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { checkoutController.getOrder().place(checkoutController.getCart()); model.addAttribute("order", checkoutController.getOrder()); return "orderPlaced"; } }
  • 58. ⌘⌥F “Introduzir a tributo” orde cart em Order r e Controller public class OrderController { private final CheckoutController checkoutController; public OrderController(CheckoutController checkoutController) { this.checkoutController = checkoutController; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { checkoutController.getOrder().place(checkoutController.getCart()); model.addAttribute("order", checkoutController.getOrder()); return "orderPlaced"; } }
  • 59. public class OrderController { private final CheckoutController checkoutController; private final Order order; private final Cart cart; public OrderController(CheckoutController checkoutController) { this.checkoutController = checkoutController; order = this.checkoutController.getOrder(); cart = this.checkoutController.getCart(); } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } }
  • 60. ⌘⌥P / ⌥ / ⌘Y “Introduzir p arâmetro” ord e cart no con er public class OrderController { strutor de OrderControl private final CheckoutController checkoutController; ler e inic ializar private final Order order; private final Cart cart; public OrderController(CheckoutController checkoutController) { this.checkoutController = checkoutController; order = this.checkoutController.getOrder(); cart = this.checkoutController.getCart(); } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } }
  • 61. public class OrderController { private final CheckoutController checkoutController; private final Order order; private final Cart cart; public OrderController(CheckoutController checkoutController, Order order, Cart cart) { this.checkoutController = checkoutController; this.order = order; this.cart = cart; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } }
  • 62. ⌘⌫ “Remoção Segu ra” do atribu public class OrderController { e parâmetro to private final CheckoutController checkoutController; checkoutContr oller private final Order order; private final Cart cart; public OrderController(CheckoutController checkoutController, Order order, Cart cart) { this.checkoutController = checkoutController; this.order = order; this.cart = cart; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } }
  • 63. public class OrderController { private final Order order; private final Cart cart; public OrderController(Order order, Cart cart) { this.order = order; this.cart = cart; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { order.place(cart); model.addAttribute("order", order); return "orderPlaced"; } }
  • 64. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return new OrderController(order, cart).placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } public Order getOrder() { return order; } public Cart getCart() { return cart; } }
  • 65. @Controller public class CheckoutController { ⌘⌫ “Remoção Segu private final Cart cart; ra” de getCar e getOrder() t() private final Order order; em CheckoutContr oller @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return new OrderController(order, cart).placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } public Order getOrder() { return order; } public Cart getCart() { return cart; } }
  • 66. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return new OrderController(order, cart).placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 67. ⌘⌥N @Controller public class CheckoutController { “Inline” méto do placeOrder mudar argumen e private final Cart cart; tos para usar cart e order private final Order order; no teste @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } @RequestMapping("/place/order") public String placeOrder(ModelMap model) { return new OrderController(order, cart).placeOrder(model); } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 68. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 69. public class CheckoutControllerTest { private CheckoutController checkoutController; private Cart cart = new Cart(); // could as easily be a mock private Order order = new Order(); // could as easily be a mock private ModelMap model = new ModelMap(); @Before public void setup() { checkoutController = new CheckoutController(cart, order); } @Test public void checkout_should_add_an_upsell() { String result = checkoutController.goCheckout(model); assertThat(result, equalTo("checkout")); assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}")); } @Test public void place_order_in_checkout_should_make_an_order() { cart.addTo("dummy"); String result = new OrderController(order, cart).placeOrder(model); assertThat(result, equalTo("orderPlaced")); assertThat(model.toString(), equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}")); } }
  • 70. public class CheckoutControllerTest { ⌘⌥F “ Introduzir at private CheckoutController checkoutController; ributo” private or be a ntro Cart cart = new Cart(); // could as easily derComock ller no teste, private inicialia ando Order order = new Order(); // could as easily be z mock no setUp() private ModelMap model = new ModelMap(); @Before public void setup() { checkoutController = new CheckoutController(cart, order); } @Test public void checkout_should_add_an_upsell() { String result = checkoutController.goCheckout(model); assertThat(result, equalTo("checkout")); assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}")); } @Test public void place_order_in_checkout_should_make_an_order() { cart.addTo("dummy"); String result = new OrderController(order, cart).placeOrder(model); assertThat(result, equalTo("orderPlaced")); assertThat(model.toString(), equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}")); } }
  • 71. public class CheckoutControllerTest { private CheckoutController checkoutController; private Cart cart = new Cart(); // could as easily be a mock private Order order = new Order(); // could as easily be a mock private ModelMap model = new ModelMap(); private OrderController orderController; @Before public void setup() { checkoutController = new CheckoutController(cart, order); orderController = new OrderController(order, cart); } @Test public void checkout_should_add_an_upsell() { String result = checkoutController.goCheckout(model); assertThat(result, equalTo("checkout")); assertThat(model.toString(), equalTo("{cart=Cart{contents=[[iPad]]}}")); } @Test public void place_order_in_checkout_should_make_an_order() { cart.addTo("dummy"); String result = orderController.placeOrder(model); assertThat(result, equalTo("orderPlaced")); assertThat(model.toString(), equalTo("{order=Order{cart=Cart{contents=[[dummy]]}}}")); } }
  • 72. @Controller public class CheckoutController { private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 73. ⌘⌫ “Remoção Segu ra” do atribu e parâmetro o to @Controller public class CheckoutController { rder no CheckoutContr oller private final Cart cart; private final Order order; @Autowired public CheckoutController(Cart cart, Order order) { this.cart = cart; this.order = order; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 74. @Controller public class CheckoutController { private final Cart cart; @Autowired public CheckoutController(Cart cart) { this.cart = cart; } @RequestMapping("/go/to/checkout/") public String goCheckout(ModelMap model) { // other stuff cart.addTo(findUpsell(cart)); model.addAttribute("cart", cart); return "checkout"; } String findUpsell(Cart cart) { return cart.size() == 0 ? "iPad" : "iPod Nano"; } }
  • 78. Identificar Objetivo Design “ativo”
  • 79. Identificar Objetivo Design “ativo” • Design OO
  • 80. Identificar Objetivo Design “ativo” • Design OO • Direção do Projeto
  • 81. Identificar Objetivo Design “ativo” • Design OO • Direção do Projeto • Decisões Arquiteturais
  • 82. Identificar Objetivo Design “passivo”
  • 83. Identificar Objetivo Design “passivo” • Maus Cheiros
  • 84. Identificar Objetivo Design “passivo” • Maus Cheiros • Métricas
  • 85. Identificar Objetivo Design “passivo” • Maus Cheiros • Métricas • Visualizações
  • 89. Traçar Estratégia • Isole o Impacto das Mudanças
  • 90. Traçar Estratégia • Isole o Impacto das Mudanças • Baby Steps
  • 91. Traçar Estratégia • Isole o Impacto das Mudanças • Baby Steps • Mantenha os testes passando
  • 92. Traçar Estratégia • Isole o Impacto das Mudanças • Baby Steps • Mantenha os testes passando • Ir para trás antes de ir para frente
  • 93. CalendarSearchController CalendarSearchController Test Event Event
  • 94. r dtsato/kata-ref actoring-calenda http ://github.com/ CalendarSearchController CalendarSearchController Test Event Event
  • 95. def index(params) scope = Event case params[:timeframe] when 'tomorrow' scope = scope.between_day(DateTime.now + 1) when 'this_week' scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day) when 'custom' if params[:start_date].blank? params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y') end if params[:end_date].blank? params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y') end scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'), DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day) when 'hour' scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H: %M')) when 'today' scope = scope.between_day(DateTime.now) end @events = scope.all end
  • 96. def index(params) scope = Event switch/case case params[:timeframe] when 'tomorrow' scope = scope.between_day(DateTime.now + 1) when 'this_week' scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day) when 'custom' if params[:start_date].blank? params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y') end if params[:end_date].blank? params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y') end scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'), DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day) when 'hour' scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H: %M')) when 'today' scope = scope.between_day(DateTime.now) end @events = scope.all end
  • 97. def index(params) scope = Event case params[:timeframe] when 'tomorrow' scope = scope.between_day(DateTime.now + 1) when 'this_week' string parsing scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day) when 'custom' if params[:start_date].blank? params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y') end if params[:end_date].blank? params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y') end scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'), DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day) when 'hour' scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H: %M')) when 'today' scope = scope.between_day(DateTime.now) end @events = scope.all end
  • 98. def index(params) scope = Event case params[:timeframe] when 'tomorrow' scope = scope.between_day(DateTime.now + 1) when 'this_week' scope = scope.between_dates(DateTime.now, ( DateTime.now + 6 ).end_of_day) when 'custom' if params[:start_date].blank? params[:start_date] = DateTime.now.beginning_of_week.strftime('%m/%d/%Y') end if params[:end_date].blank? params[:end_date] = (DateTime.now.end_of_week - 2).strftime('%m/%d/%Y') end scope = scope.between_dates(DateTime.strptime(params[:start_date], '%m/%d/%Y'), DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day) when 'hour' scope = scope.between_hour_on_day(DateTime.strptime(params[:hour], '%m/%d/%Y %H: %M')) when 'today' scope = scope.between_day(DateTime.now) end vários named scopes @events = scope.all end
  • 99. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] } } named_scope :between_hour_on_day, lambda { |start_hour| end_date = start_hour + 1.hour-1.second { :conditions => {:at => start_hour..end_date} } } named_scope :between_day, lambda { |date| start_date = date.at_beginning_of_day end_date = start_date.end_of_day { :conditions => {:at => start_date..end_date} } } end
  • 100. jeitos diferentes de fazer a mesma class Event < ActiveRecord::Base coisa named_scope :between_dates, lambda { |start_date, end_date| {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] } } named_scope :between_hour_on_day, lambda { |start_hour| end_date = start_hour + 1.hour-1.second { :conditions => {:at => start_hour..end_date} } } named_scope :between_day, lambda { |date| start_date = date.at_beginning_of_day end_date = start_date.end_of_day { :conditions => {:at => start_date..end_date} } } end
  • 101. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => ["at >= ? AND at <= ?", start_date, end_date ] } } named_scope :between_hour_on_day, lambda { |start_hour| end_date = start_hour + 1.hour-1.second { :conditions => {:at => start_hour..end_date} } } mais lógica named_scope :between_day, lambda { |date| start_date = date.at_beginning_of_day end_date = start_date.end_of_day { :conditions => {:at => start_date..end_date} } } end
  • 102. Objetivos Ativo: • Isolar testes unitários do banco de dados Passivo: • Tratar dos maus cheiros
  • 103. O Plano 1. Centralizar a lógica de manipulação de datas 2. Unificar named scopes 3. Extrair lógica do Controller 4. Quebrar timeframe em vários pedaços
  • 104. def index(params) case params[:timeframe] when 'tomorrow' date = DateTime.now + 1 start_date = date.at_beginning_of_day end_date = start_date.end_of_day when 'this_week' start_date = DateTime.now end_date = (DateTime.now + 6 ).end_of_day when 'custom' start_date = params[:start_date].blank? ? DateTime.now.beginning_of_week : DateTime.strptime(params[:start_date], '%m/%d/%Y') end_date = params[:end_date].blank? ? (DateTime.now.end_of_week - 2) : DateTime.strptime(params[:end_date], '%m/%d/%Y').end_of_day when 'hour' start_date = DateTime.strptime(params[:hour], '%m/%d/%Y %H:%M') end_date = start_date + 1.hour-1.second when 'today' date = DateTime.now start_date = date.at_beginning_of_day end_date = start_date.end_of_day end @events = Event.between_dates(start_date, end_date) end
  • 105. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end
  • 106. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end lib/calendar_search_controller.rb | 27 +++++++++++++-------------- lib/event.rb | 13 +------------ spec/event_spec.rb | 37 ------------------------------------- 3 files changed, 14 insertions(+), 63 deletions(-)
  • 107. Antes . ............ ds 0 .49367 secon Finished in res 13 examp les, 0 failu class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end lib/calendar_search_controller.rb | 27 +++++++++++++-------------- lib/event.rb | 13 +------------ spec/event_spec.rb | 37 ------------------------------------- 3 files changed, 14 insertions(+), 63 deletions(-)
  • 108. Antes Depois ....... . ............ ds Finished in 0 .49367 secon 0.25355 seco Finished in res 7 examples, nds 13 examp les, 0 failu 0 failures class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end lib/calendar_search_controller.rb | 27 +++++++++++++-------------- lib/event.rb | 13 +------------ spec/event_spec.rb | 37 ------------------------------------- 3 files changed, 14 insertions(+), 63 deletions(-)
  • 109. O Plano 1. Centralizar a lógica de manipulação de datas 2. Unificar named scopes 3. Extrair lógica do Controller 4. Quebrar timeframe em vários pedaços
  • 110. class CalendarSearchController attr_reader :events def index(params) timeframe = TimeFrame.for(params[:timeframe], params[:start_date], params[:end_date], params[:hour]) @events = Event.between_dates(timeframe.start_date, timeframe.end_date) end end mudança nos testes: it "should create time frame from params and retrieve events" do timeframe = TimeFrame.new(DateTime.now, DateTime.now) TimeFrame.should_receive(:for).with('today', 'start', 'end', 'hour').and_return(timeframe) events = [Event.new, Event.new] Event.should_receive(:between_dates).with(timeframe.start_date, timeframe.end_date).and_return(events) @controller.index(:timeframe => 'today', :start_date => 'start', :end_date => 'end', :hour => 'hour') @controller.events.should == events end
  • 111. describe "Acceptance tests" do around(:each) do |example| Event.transaction { example.run; raise ActiveRecord::Rollback } end before do @controller = CalendarSearchController.new @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end it "should return today's events" do today_events = [Event.create(:at => @today), Event.create(:at => @today)] tomorrow = @today + 1 tomorrow_events = [Event.create(:at => tomorrow), Event.create(:at => tomorrow)] @controller.index(:timeframe => 'today') @controller.events.should == today_events end it "should return tomorrow's events" ... it "should return this week's events" ... it "should return events for specified date range" ... it "should default date range to this business week" ... it "returns events for a specified hour" ... end
  • 112. describe "Acceptance tests" do around(:each) do |example| Depois ...... Event.transaction { example.run; raise ActiveRecord::Rollback } end Finished in 0.24538 seco before do 6 examples, nds 0 failures @controller = CalendarSearchController.new @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end it "should return today's events" do today_events = [Event.create(:at => @today), Event.create(:at => @today)] tomorrow = @today + 1 tomorrow_events = [Event.create(:at => tomorrow), Event.create(:at => tomorrow)] @controller.index(:timeframe => 'today') @controller.events.should == today_events end it "should return tomorrow's events" ... it "should return this week's events" ... it "should return events for specified date range" ... it "should default date range to this business week" ... it "returns events for a specified hour" ... end
  • 113. class TimeFrame < Struct.new(:start_date, :end_date) def self.for(type, start_date, end_date, hour) case type when 'tomorrow' date = DateTime.now + 1 TimeFrame.new(date.at_beginning_of_day, date.end_of_day) when 'this_week' TimeFrame.new(DateTime.now, (DateTime.now + 6 ).end_of_day) when 'custom' start_date = start_date.blank? ? DateTime.now.beginning_of_week : DateTime.strptime(start_date, '%m/%d/%Y') end_date = end_date.blank? ? (DateTime.now.end_of_week - 2) : DateTime.strptime(end_date, '%m/%d/%Y').end_of_day TimeFrame.new(start_date, end_date) when 'hour' start_date = DateTime.strptime(hour, '%m/%d/%Y %H:%M') end_date = start_date + 1.hour-1.second TimeFrame.new(start_date, end_date) when 'today' date = DateTime.now TimeFrame.new(date.at_beginning_of_day, date.end_of_day) end end end
  • 114. describe TimeFrame do before do @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end describe "today's event" do it "should use beginning and end of day" do timeframe = TimeFrame.for('today', nil, nil, nil) timeframe.start_date.should == @today.at_beginning_of_day timeframe.end_date.should == @today.end_of_day end end ... end
  • 115. describe TimeFrame do before do @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end describe "today's event" do it "should use beginning and end of day" do timeframe = TimeFrame.for('today', nil, nil, nil) timeframe.start_date.should == @today.at_beginning_of_day timeframe.end_date.should == @today.end_of_day end Rakefile | 4 ++ end lib/calendar_search_controller.rb | 24 +--------- ... lib/time_frame.rb | 24 ++++++++++ end spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++ spec/calendar_search_controller_spec.rb | 75 ++++--------------------------- spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 87 deletions(-)
  • 116. Antes ....... ds describe d in 0 .25355 secon Finishe TimeFrame do es before les, 0 failur 7 examp do @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end describe "today's event" do it "should use beginning and end of day" do timeframe = TimeFrame.for('today', nil, nil, nil) timeframe.start_date.should == @today.at_beginning_of_day timeframe.end_date.should == @today.end_of_day end Rakefile | 4 ++ end lib/calendar_search_controller.rb | 24 +--------- ... lib/time_frame.rb | 24 ++++++++++ end spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++ spec/calendar_search_controller_spec.rb | 75 ++++--------------------------- spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 87 deletions(-)
  • 117. Antes Depois ........ ....... ds Finished in describe d in 0 .25355 secon she TimeFrame do 0.17938 seco nds Fini 8 examples, before les, 0 failures 7 ex amp do 0 failures @today = DateTime.strptime('06/01/2011', '%m/%d/%Y') DateTime.stub!(:now).and_return(@today) end describe "today's event" do it "should use beginning and end of day" do timeframe = TimeFrame.for('today', nil, nil, nil) timeframe.start_date.should == @today.at_beginning_of_day timeframe.end_date.should == @today.end_of_day end Rakefile | 4 ++ end lib/calendar_search_controller.rb | 24 +--------- ... lib/time_frame.rb | 24 ++++++++++ end spec/acceptance_tests.rb | 75 +++++++++++++++++++++++++++++++ spec/calendar_search_controller_spec.rb | 75 ++++--------------------------- spec/time_frame_spec.rb | 63 ++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 87 deletions(-)
  • 118. O Plano 1. Centralizar a lógica de manipulação de datas 2. Unificar named scopes 3. Extrair lógica do Controller 4. Quebrar timeframe em vários pedaços
  • 119. class TimeFrame attr_reader :start_date, :end_date class Today < TimeFrame def initialize date = DateTime.now @start_date, @end_date = date.at_beginning_of_day, date.end_of_day end end ... end describe TimeFrame::Today do it "should use beginning and end of day" do timeframe = TimeFrame::Today.new timeframe.start_date.should == @today.at_beginning_of_day timeframe.end_date.should == @today.end_of_day end ... end
  • 120. class TimeFrame ... def self.for(type, start_date, end_date, hour) case type when 'tomorrow' then Tomorrow.new when 'this_week' then ThisWeek.new when 'custom' then Custom.new(start_date, end_date) when 'hour' then Hour.new(hour) when 'today' then Today.new end end end describe TimeFrame::Today do ... describe "parsing" do it "should parse today's timeframe" do TimeFrame.for('today', nil, nil, nil).should be_an_instance_of(TimeFrame::Today) end ... end end
  • 121. class TimeFrame ... Antes .def .self.for(type, start_date, end_date, hour) ... ... case type ds 0 .17938 secon when 'tomorrow' then Tomorrow.new Finished in when les, 0 failures ThisWeek.new 8 examp 'this_week' then when 'custom' then Custom.new(start_date, end_date) when 'hour' then Hour.new(hour) when 'today' then Today.new end end end describe TimeFrame::Today do ... describe "parsing" do it "should parse today's timeframe" do TimeFrame.for('today', nil, nil, nil).should be_an_instance_of(TimeFrame::Today) end ... end end
  • 122. class TimeFrame ... Antes Depois ............ def .self.for(type, start_date, end_date, hour) . .... ... case type ds Finished in when d in 0 .17938 secon she 'tomorrow' then Tomorrow.new 0.19023 seco nds Fini 13 examples, when les, 0 failures ThisWeek.new 8 examp 'this_week' then 0 failures when 'custom' then Custom.new(start_date, end_date) when 'hour' then Hour.new(hour) when 'today' then Today.new end end end describe TimeFrame::Today do ... describe "parsing" do it "should parse today's timeframe" do TimeFrame.for('today', nil, nil, nil).should be_an_instance_of(TimeFrame::Today) end ... end end
  • 123. class TimeFrame ... Antes Depois ............ def .self.for(type, start_date, end_date, hour) . .... ... case type ds Finished in when d in 0 .17938 secon she 'tomorrow' then Tomorrow.new 0.19023 seco nds Fini 13 examples, when les, 0 failures ThisWeek.new 8 examp 'this_week' then 0 failures when 'custom' then Custom.new(start_date, end_date) when 'hour' then Hour.new(hour) when 'today' then Today.new end end end describe TimeFrame::Today do ... describe "parsing" do lib/time_frame.rb | 59 +++++++++++++++++++++++++++++++++------------- it "should parse today's timeframe" do spec/time_frame_spec.rb | 44 ++++++++++++++++++++++++++-------- TimeFrame.for('today', nil, nil, nil).should 2 files changed, 75 insertions(+), 28 deletions(-) be_an_instance_of(TimeFrame::Today) end ... end end
  • 125. “Big Picture” • Mudanças Arquiteturais • Unificação de abordagens diferentes • Substituição de componentes/frameworks
  • 127. “Big Picture” Escopo Risco Esforço Comunicação
  • 128.
  • 129. Mikado Method Criar pacote para Stranger Eons Ltda.
  • 130. Mikado Method Criar projeto para Stranger Eons Ltda. Criar pacote para Stranger Eons Ltda.
  • 131. Mikado Method Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 132. Mikado Method Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 133. Mikado Method Mover código UI para novo projeto Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 134. Mikado Method Quebrar dependência circular entre Aplicação e UI Mover código UI para novo projeto Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 135. Mikado Method Extrair ApplicationInterface Quebrar dependência circular entre Aplicação e UI Mover código UI para novo projeto Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 136. Mikado Method Extrair ApplicationInterface Injetar instância de ApplicationInterface Quebrar dependência circular entre Aplicação e UI Mover código UI para novo projeto Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 137. Mikado Method ✔ Extrair ApplicationInterface Injetar instância de ✔ ApplicationInterface Quebrar dependência ✔ circular entre Aplicação e UI Mover código UI para novo projeto Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 138. Mikado Method ✔ Extrair ApplicationInterface Injetar instância de ✔ ApplicationInterface Quebrar dependência ✔ circular entre Aplicação e UI Mover código UI para ✔ novo projeto ✔ ✔ Criar projeto UI Código de UI em projeto separado Criar projeto para Criar teste de aceitação Stranger Eons Ltda. para nova aplicação Criar pacote para Stranger Eons Ltda.
  • 139. Mikado Method ✔ Extrair ApplicationInterface Injetar instância de ✔ ApplicationInterface Quebrar dependência ✔ circular entre Aplicação e UI Mover código UI para ✔ novo projeto ✔ ✔ Criar projeto UI Código de UI em projeto separado Criar projeto para ✔ Criar teste de aceitação ✔ Stranger Eons Ltda. para nova aplicação ✔ Criar pacote para Stranger Eons Ltda.
  • 141. Uma história APP SVC
  • 142. Uma história APP SVC
  • 143. Uma história APP SVC
  • 144. A verdade APP Model View Controller
  • 145. A verdade APP Model View Controller Helper
  • 146. A verdade APP Model View SVC Controller Helper
  • 147. A verdade APP Model View SVC Controller vai quebrar tudo !!! Helper
  • 148. Arquitetura de transição APP Model View Controller SVC Helper
  • 149. Arquitetura de transição APP Model View Controller SVC Helper
  • 150. Arquitetura de transição APP Model View Controller SVC Helper
  • 151. Arquitetura de transição APP Model View Controller SVC Helper
  • 152. Arquitetura de transição APP Model View Controller SVC Helper
  • 153. Arquitetura de transição APP Model View Controller SVC Helper
  • 154. Arquitetura de Transição • Go: • “Branch by Abstraction” • Migrar de iBatis para Hibernate • Migrar de Velocity/JsTemplate para JRuby on Rails
  • 155. Arquitetura de Transição • Go: • “Branch by Abstraction” • Migrar de iBatis para Hibernate • Migrar de Velocity/JsTemplate para JRuby on Rails - 0 11/05/make-large http://continuo usdelivery.com/2 - l y-with-branch-by scale-cha nges-incremental abstraction/
  • 156. Referências Livros: "Refactoring: Improving the Design of Existing Code" - Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts "Refactoring to Patterns" - Joshua Kerievsky "Working Effectively with Legacy Code" - Michael Feathers "Beheading the Software Beast: Relentless Restructurings with The Mikado Method" - Daniel Brolund, Ola Ellnestam Créditos (fotos): http://www.flickr.com/photos/dhammza/2227347832/ http://www.flickr.com/photos/pragdave/173640462/ Links: http://paulhammant.com/2011/09/01/refactoring-experiment http://continuousdelivery.com/2011/05/make-large-scale-changes-incrementally-with- branch-by-abstraction/ Código: https://github.com/dtsato/refactoring_experiment https://github.com/dtsato/kata-refactoring-calendar
  • 157.
  • 158. S etembro (18h): Segun da-Feira, 12 de / join-revolution http://thought works.com/events
  • 159. Obrigado! Danilo Sato - @dtsato ThoughtWorks www.dtsato.com

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. zoom out\n
  15. zoom out\n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. Mec&amp;#xE2;nica: IDE resolve, ferramentas, cat&amp;#xE1;logos...\n
  64. Exerc&amp;#xED;cios para praticar\nMelhoram uma habilidade espec&amp;#xED;fica: TDD, Algoritmos, Design, C&amp;#xF3;digo ruim? etc...\n
  65. \n
  66. Cobertura 100%\nApplica&amp;#xE7;&amp;#xE3;o Java/Spring\n
  67. \n
  68. Objetivo: extrair placeOrder para outro controller\n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. Foco n&amp;#xED;vel um pouco mais alto\n
  83. \n
  84. N&amp;#xE3;o tem segredo para identificar objetivo\n
  85. N&amp;#xE3;o tem segredo para identificar objetivo\n
  86. N&amp;#xE3;o tem segredo para identificar objetivo\n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  96. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  97. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  98. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  99. Aplica&amp;#xE7;&amp;#xE3;o Rails. Cobertura 100%\nForm de busca de eventos\nEm Ruby -&gt; n&amp;#xE3;o tem mesmas ferramentas avan&amp;#xE7;adas de refatora&amp;#xE7;&amp;#xE3;o\n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. * Escopo &amp;#xFA;nico: between_dates\n* Mais feio (indo para tr&amp;#xE1;s antes de ir para frente)\n* Isolando mudan&amp;#xE7;a (toda a l&amp;#xF3;gica de datas num &amp;#xFA;nico lugar)\n
  111. * Remo&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo &gt; Adi&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo\n* Testes mais r&amp;#xE1;pidos pois os testes dos 3 named scopes acessavam o BD\n
  112. * Remo&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo &gt; Adi&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo\n* Testes mais r&amp;#xE1;pidos pois os testes dos 3 named scopes acessavam o BD\n
  113. * Remo&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo &gt; Adi&amp;#xE7;&amp;#xE3;o de c&amp;#xF3;digo\n* Testes mais r&amp;#xE1;pidos pois os testes dos 3 named scopes acessavam o BD\n
  114. \n
  115. Skinny Controller\nTestes do Controller usam mocks para testar colabora&amp;#xE7;&amp;#xE3;o\n
  116. Testes do controller moveram para teste de aceita&amp;#xE7;&amp;#xE3;o (cucumber?)\n\n
  117. * Timeframe s&amp;#xF3; cont&amp;#xEA;m start/end\n* L&amp;#xF3;gica ainda &amp;#xE9; feia\n
  118. * Teste n&amp;#xE3;o acessa mais o BD!\n* Adi&amp;#xE7;&amp;#xE3;o de muitos testes\n* Pouca mudan&amp;#xE7;a no c&amp;#xF3;digo em si\n
  119. * Teste n&amp;#xE3;o acessa mais o BD!\n* Adi&amp;#xE7;&amp;#xE3;o de muitos testes\n* Pouca mudan&amp;#xE7;a no c&amp;#xF3;digo em si\n
  120. * Teste n&amp;#xE3;o acessa mais o BD!\n* Adi&amp;#xE7;&amp;#xE3;o de muitos testes\n* Pouca mudan&amp;#xE7;a no c&amp;#xF3;digo em si\n
  121. \n
  122. * Separa&amp;#xE7;&amp;#xE3;o de subclasses em TimeFrame para remover switch/case\n* Testes mudam junto\n
  123. * Factory method ainda tem switch/case (discutir poss&amp;#xED;vel uso de metaprograma&amp;#xE7;&amp;#xE3;o)\n* Redu&amp;#xE7;&amp;#xE3;o total dos testes unit&amp;#xE1;rios: de 0.4936 para 0.19023 (61%)\n
  124. * Factory method ainda tem switch/case (discutir poss&amp;#xED;vel uso de metaprograma&amp;#xE7;&amp;#xE3;o)\n* Redu&amp;#xE7;&amp;#xE3;o total dos testes unit&amp;#xE1;rios: de 0.4936 para 0.19023 (61%)\n
  125. * Factory method ainda tem switch/case (discutir poss&amp;#xED;vel uso de metaprograma&amp;#xE7;&amp;#xE3;o)\n* Redu&amp;#xE7;&amp;#xE3;o total dos testes unit&amp;#xE1;rios: de 0.4936 para 0.19023 (61%)\n
  126. \n
  127. \n
  128. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\n
  129. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\n
  130. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\n
  131. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\n
  132. Escolha objetivo, comece de forma inocente, aprenda e desenho um grafo, rollback quando est&amp;#xE1; quebrado, trabalhe das folhas para a ra&amp;#xED;z\n
  133. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  134. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  135. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  136. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  137. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  138. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  139. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  140. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  141. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  142. 1. Rollback ao decidir separar o projeto UI\n2. Depend&amp;#xEA;ncia circular entre Aplica&amp;#xE7;&amp;#xE3;o e UI\n
  143. \n
  144. \n
  145. \n
  146. Exemplo\n
  147. Exemplo\n
  148. Exemplo\n
  149. Exemplo\n
  150. Exemplo\n
  151. Exemplo\n
  152. Exemplo\n
  153. Exemplo\n
  154. Exemplo\n
  155. Exemplo\n
  156. Exemplo\n
  157. Exemplo\n
  158. Exemplo\n
  159. Exemplo\n
  160. \n
  161. \n
  162. \n
  163. \n