SlideShare una empresa de Scribd logo
1 de 60
Refactoring Katas
   Danilo Sato - @dtsato
      ThoughtWorks
     www.dtsato.com
Kata?
Kata?
Kata?
• Exercícios para praticar
• Melhorar habilidades específicas:
 •   TDD

 •   Algoritmos

 •   Design

 •   Código Ruim?

 •   ...
Kata?
Test


Test


Test


Test
Kata?
Test


Test


Test


Test
Kata?
Test


Test


Test


Test
Kata?
Test


Test


Test


Test
Refatoração
Test
Refatoração
Test             Code
Refatoração
Test             Code
Refatoração
                 Code
Test
Refatoração
                 Code
Test
Refatoração
                 Code
Test
Refatoração
                 Code

Test
Refatoração
                 Code

Test
Refatoração
                 Code

Test
Refatoração
                 Code

Test
Refatoração
                    Code

Test




                Remover duplicação
Outros tipos...

                Code
Test
Outros tipos...

              Code   Code
Test
Outros tipos...

                  Code   Code
Test    Test
Outros tipos...

                  Code        Code
Test    Test




                      Se paração de
                    responsa bilidades
Outros tipos...

                Code
Test
Outros tipos...

Test            Code
Outros tipos...

Test            Code
Outros tipos...

Test             Code




               Mudança no design
Ainda mais
A idéia
A idéia
A idéia


          ?
A idéia


?             ?
A idéia


    ?             ?

?
#comofas

1. Criticar código
2. Analisar a solução final
3. Planejar os passos
4. Mão na massa!
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 parse
    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
                                                    escopos diferentes
  @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
Plano

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

2. Unificar named scopes

3. Extrair lógica do Controller

4. Quebrar lógica de timeframes diferentes
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(-)
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
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(-)
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
  ...
  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
  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
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
  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
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
Obrigado!
Danilo Sato - @dtsato
   ThoughtWorks
  www.dtsato.com
sato/kata-refac toring-calendar
http: //github.com/dt




                Obrigado!
                 Danilo Sato - @dtsato
                    ThoughtWorks
                   www.dtsato.com

Más contenido relacionado

Más de Danilo 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
 
Refactoring at Large
Refactoring at LargeRefactoring at Large
Refactoring at LargeDanilo Sato
 
Refatoração em Larga Escala
Refatoração em Larga EscalaRefatoração em Larga Escala
Refatoração em Larga EscalaDanilo 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
 

Más de Danilo Sato (8)

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...
 
Refactoring at Large
Refactoring at LargeRefactoring at Large
Refactoring at Large
 
Refatoração em Larga Escala
Refatoração em Larga EscalaRefatoração em Larga Escala
Refatoração em Larga Escala
 
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
 

Último

Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 

Último (20)

Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 

Refactoring Katas - AgileBrazil 2011

  • 1. Refactoring Katas Danilo Sato - @dtsato ThoughtWorks www.dtsato.com
  • 4. Kata? • Exercícios para praticar • Melhorar habilidades específicas: • TDD • Algoritmos • Design • Código Ruim? • ...
  • 12. Refatoração Code Test
  • 13. Refatoração Code Test
  • 14. Refatoração Code Test
  • 15. Refatoração Code Test
  • 16. Refatoração Code Test
  • 17. Refatoração Code Test
  • 18. Refatoração Code Test
  • 19. Refatoração Code Test Remover duplicação
  • 20. Outros tipos... Code Test
  • 21. Outros tipos... Code Code Test
  • 22. Outros tipos... Code Code Test Test
  • 23. Outros tipos... Code Code Test Test Se paração de responsa bilidades
  • 24. Outros tipos... Code Test
  • 27. Outros tipos... Test Code Mudança no design
  • 31. A idéia ?
  • 33. A idéia ? ? ?
  • 34. #comofas 1. Criticar código 2. Analisar a solução final 3. Planejar os passos 4. Mão na massa!
  • 35. 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
  • 36. 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
  • 37. def index(params) scope = Event case params[:timeframe] when 'tomorrow' scope = scope.between_day(DateTime.now + 1) when 'this_week' string parse 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
  • 38. 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 escopos diferentes @events = scope.all end
  • 39. 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
  • 40. 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
  • 41. 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
  • 42. Plano 1. Centralizar lógica de manipulação de datas 2. Unificar named scopes 3. Extrair lógica do Controller 4. Quebrar lógica de timeframes diferentes
  • 43. 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
  • 44. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end
  • 45. 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(-)
  • 46. 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(-)
  • 47. 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(-)
  • 48. 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
  • 49. 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
  • 50. 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
  • 51. 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(-)
  • 52. 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(-)
  • 53. 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(-)
  • 54. 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
  • 55. 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
  • 56. 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 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
  • 57. 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 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
  • 58. 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
  • 59. Obrigado! Danilo Sato - @dtsato ThoughtWorks www.dtsato.com
  • 60. sato/kata-refac toring-calendar http: //github.com/dt Obrigado! Danilo Sato - @dtsato ThoughtWorks www.dtsato.com

Notas del editor

  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. \n
  15. \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