SlideShare a Scribd company logo
1 of 148
Download to read offline
Refactoring at Large
     Danilo Sato - @dtsato
        ThoughtWorks
       www.dtsato.com
Refactoring at Large
Refactoring at Large
Refactoring at Large
Refactoring at Large
My Plan for Today
+ •    “Inside out” approach
  • Show me Code (Java)
  • Strategies and Objectives
  • Refactoring Ruby/Rails
- • Larger refactorings
Refactoring at Large
Why do we change
     code?
Why do we change
       code?
• Add features
Why do we change
       code?
• Add features
• Fix bugs
Why do we change
       code?
• Add features
• Fix bugs
• Improve design
Why do we change
       code?
• Add features
• Fix bugs
• Improve design
• Optimization
Why do we change
       code?
• Add features
• Fix bugs
• Improve design
• Optimization
Refactoring at Large
Refactoring at Large
Refactoring at Large
"Refactoring is a disciplined
 technique for restructuring an
existing body of code, altering its
    internal structure without
changing its external behavior."
Refactoring

    Code
Refactoring

    Code
Refactoring

    Code




           Extr act Method
Refactoring

    Code
Refactoring

    Code
Refactoring

    Code




           Eliminate Duplication
•   Extract Method

•   Move Method

•   Extract Class

•   Remove Middle Man

•   Self Encapsulate Field

•   Decompose Conditional

•   ...
Tests!
                Code

Test
Tests!
                Code

Test
Tests!
                     Code

Test




                Eliminate Duplication
Other types...

                    Code
Test
Other types...

                 Code   Code
Test
Other types...

                 Code   Code
Test   Test
Other types...

                 Code         Code
Test   Test




                   Split Responsibility
Other types...

                    Code
Test
Other types...

Test               Code
Other types...

Test               Code
Other types...

Test               Code




                   Change Design
Even more...
“Big Picture”
“Big Picture”
“Big Picture”
“Big Picture”
“Big Picture”
Strategy




Mechanics
Coding Kata!
Coding Kata!
CheckoutControllerTest   CheckoutController



                         Order        Cart
-
                                    1 2/10/refactoring
                 o.com/blog/2011/
http://www.dtsat                        /
                    h rough-experiment
st rategies-a-walkt
                                                  -
                               0 9/01/refactoring
http://paulh ammant.com/2011/
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"; }
}
Mechanics


                       t his video on:        riment
               Watch           factoring-expe
               com/dt sato/re
    p://vimeo.
htt
First Attempt...


                       t his video on:        riment
               Watch           factoring-expe
               com/dt sato/re
    p://vimeo.
htt
Strategy


                       t his video on:        riment
               Watch           factoring-expe
               com/dt sato/re
    p://vimeo.
htt
Identify your Objective
Identify your Objective
Identify your Objective
      “Active” design
Identify your Objective
            “Active” design




•   OO Design
Identify your Objective
              “Active” design




•   OO Design

•   Project direction
Identify your Objective
              “Active” design




•   OO Design

•   Project direction

•   Architectural decisions
Identify your Objective
      “Passive” design
Identify your Objective
                 “Passive” design




•   Bad Smells
Identify your Objective
                 “Passive” design




•   Bad Smells

•   Metrics
Identify your Objective
                 “Passive” design




•   Bad Smells

•   Metrics

•   Visualizations
Strategize
Strategize


    ?                ?

?
Strategize
Strategize

• Isolate the impact of Change
Strategize

• Isolate the impact of Change
• Baby Steps
Strategize

• Isolate the impact of Change
• Baby Steps
• Keep the tests green
Strategize

•   Isolate the impact of Change
•   Baby Steps
•   Keep the tests green
•   Moving backwards before moving forward
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
                                             multiple 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
different ways
                                                to do the same
class Event < ActiveRecord::Base                      thing
  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} }
  }
                                                       more logic
  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
Objectives

Active:

 • Isolate unit tests from the database
Passive:

 • Deal with bad smells
Strategizing

1. Centralize date manipulation logic

2. Unify named scopes

3. Extract logic from Controller

4. Break timeframe into separate pieces
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(-)
Before
                .
 ............
                             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(-)
Before                               .......
                                                                After
                .
 ............
                             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(-)
Strategizing

1. Centralize date manipulation logic

2. Unify named scopes

3. Extract logic from Controller

4. Break timeframe into separate pieces
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


                         change to tests:
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|                                         After
                                                    ......
    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(-)
Before
 .......
                             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(-)
Before                             ........
                                                              After
 .......
                             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(-)
Strategizing

1. Centralize date manipulation logic

2. Unify named scopes

3. Extract logic from Controller

4. Break timeframe into separate pieces
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
  ...          Before
 .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
  ...         Before                          ............
                                                          After
  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
  ...         Before                          ............
                                                          After
  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
“Big Picture”

• Architectural Changes
• Consolidating different approaches
• Substituting components/frameworks
“Big Picture”
“Big Picture”



Scope    Risk   Effort   Communication
Change
x x            x x
  x              x x

      Change



      x xx
       x
x x            x x
  x              x x

      Change



      x xx
       x
x
         x

       x x                x x
         x                  x x
  xx
 x               Change
xxx

                 x xx
                  x
x                 x
                              xx x
         x                      x
       x x                x x
         x                  x x
  xx
 x               Change
xxx

                 x xx
                  x
x                   x
                                        xx x
                 x                        x
               x x                 x x
                 x                   x x
  xx
 x                       Change
xxx

                         x xx
                          x
                                   xx
          xx                      x x
       xxx                        xx
        x
x                     x
                      x             x        x
x x     x                                   xx x
       x x        x                           x
 x
                x x                     x x
                  x                       x x
  xx                                                 x
 x                        Change
xxx
                                                 x       x
                          x xx                            x
                           x
  x x                               xx
           xx                      x x          x x
   x
        xxx                        xx
                                                 x
         x            x x
                       x
Refactoring at Large
Change
x x            x x
  x              x x

      Change



      x xx
       x
x x            x x
  x              x x

      Change



      x xx
       x
x
Prereq
       x            x x
       x              x x

           Change



           x xx
            x
x
Prereq
       x              x
                    x Prereq
       x              x x

           Change



           x xx
            x
x
Prereq
       x              x
                    x Prereq
       x              x x

           Change



           x xx
           Prereq
            x
Prereq            Prereq


         Change



         Prereq
x
                x

       Prereq                    Prereq

  xx
 x                      Change
xxx

                        Prereq
x
                         Prereq
                     x

            Prereq                    Prereq

  xx
 x Prereq                    Change
xxx

                             Prereq
Prereq


         Prereq              Prereq



Prereq              Change



                    Prereq
Prereq


         Prereq              Prereq



Prereq              Change



                    Prereq
Prereq


       Prereq              Prereq



Prereq ✔          Change



                  Prereq
Prereq


       Prereq              Prereq



Prereq ✔          Change



                  Prereq
Prereq   ✔
       Prereq                Prereq



Prereq ✔          Change



                  Prereq
Prereq   ✔
       Prereq   ✔            Prereq



Prereq ✔            Change



                    Prereq
Prereq   ✔
       Prereq   ✔            Prereq



Prereq ✔            Change



                    Prereq
Prereq   ✔
       Prereq   ✔            Prereq   ✔
Prereq ✔            Change



                    Prereq
Prereq   ✔
       Prereq   ✔            Prereq   ✔
Prereq ✔            Change



                    Prereq
Prereq   ✔
       Prereq   ✔                Prereq   ✔
Prereq ✔            Change



                    Prereq   ✔
Prereq   ✔
       Prereq   ✔                Prereq   ✔
Prereq ✔            Change   ✔

                    Prereq   ✔
A story


          APP
A story


                APP

SVC
A story


                APP

SVC
A story


                APP

SVC
The truth

              APP

              Model


              View


            Controller
The truth

              APP

              Model


              View


            Controller


             Helper
The truth

                APP

                Model


                View
SVC
              Controller


               Helper
The truth

                             APP

                             Model


                             View
SVC
                           Controller

        everything is
      going to break !!!
                            Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
Architecture
            APP

            Model


            View


          Controller

SVC
           Helper
Transitional
         Architecture
• Go:
 • “Branch by Abstraction”
 • Migrating from iBatis to Hibernate
 • Migrating from Velocity/JsTemplate to
    JRuby on Rails
Transitional
              Architecture
    • Go:
     • “Branch by Abstraction”
     • Migrating from iBatis to Hibernate
     • Migrating from Velocity/JsTemplate to
         JRuby on Rails
                                                     -
                                  0 11/05/make-large
http://continuo usdelivery.com/2
                                              -
                           l y-with-branch-by
scale-cha nges-incremental
abstraction/
References
Books:
"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
Credits (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/
Code:
https://github.com/dtsato/refactoring_experiment
https://github.com/dtsato/kata-refactoring-calendar
Obrigado!
Danilo Sato - @dtsato
   ThoughtWorks
  www.dtsato.com

More Related Content

Similar to Refactoring at Large

How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018Mike Harris
 
3 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 20153 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 2015Manuel Bernhardt
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in CodeEamonn Boyle
 
Refatoração em Larga Escala
Refatoração em Larga EscalaRefatoração em Larga Escala
Refatoração em Larga EscalaDanilo Sato
 
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...JavaScripters Community
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineYared Ayalew
 
Boost delivery stream with code discipline engineering
Boost delivery stream with code discipline engineeringBoost delivery stream with code discipline engineering
Boost delivery stream with code discipline engineeringMiro Wengner
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passageErik Rose
 
Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Geoffrey De Smet
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0Nate Abele
 
Surviving javascript.pptx
Surviving javascript.pptxSurviving javascript.pptx
Surviving javascript.pptxTamas Rev
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable CodeBaidu, Inc.
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Agile experiments in Machine Learning with F#
Agile experiments in Machine Learning with F#Agile experiments in Machine Learning with F#
Agile experiments in Machine Learning with F#J On The Beach
 
Advance sql - window functions patterns and tricks
Advance sql - window functions patterns and tricksAdvance sql - window functions patterns and tricks
Advance sql - window functions patterns and tricksEyal Trabelsi
 

Similar to Refactoring at Large (20)

How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
 
JavaScript Refactoring
JavaScript RefactoringJavaScript Refactoring
JavaScript Refactoring
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
3 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 20153 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 2015
 
Stop that!
Stop that!Stop that!
Stop that!
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in Code
 
Refatoração em Larga Escala
Refatoração em Larga EscalaRefatoração em Larga Escala
Refatoração em Larga Escala
 
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...
JavaScripters Event Oct 22, 2016 · 2:00 PM: Common Mistakes made by Angular D...
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
 
Qtp - Introduction to synchronization
Qtp -  Introduction to synchronizationQtp -  Introduction to synchronization
Qtp - Introduction to synchronization
 
Boost delivery stream with code discipline engineering
Boost delivery stream with code discipline engineeringBoost delivery stream with code discipline engineering
Boost delivery stream with code discipline engineering
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passage
 
Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your Code
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0
 
Surviving javascript.pptx
Surviving javascript.pptxSurviving javascript.pptx
Surviving javascript.pptx
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable Code
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Agile experiments in Machine Learning with F#
Agile experiments in Machine Learning with F#Agile experiments in Machine Learning with F#
Agile experiments in Machine Learning with F#
 
Advance sql - window functions patterns and tricks
Advance sql - window functions patterns and tricksAdvance sql - window functions patterns and tricks
Advance sql - window functions patterns and tricks
 

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
 
Refactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsRefactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsDanilo 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
 
Refactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the BasicsRefactoring Strategies: Beyond the Basics
Refactoring Strategies: Beyond the Basics
 
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

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Brian Pichman
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsSeth Reyes
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7DianaGray10
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 
VoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXVoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXTarek Kalaji
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Governance in SharePoint Premium:What's in the box?
Governance in SharePoint Premium:What's in the box?Governance in SharePoint Premium:What's in the box?
Governance in SharePoint Premium:What's in the box?Juan Carlos Gonzalez
 
100+ ChatGPT Prompts for SEO Optimization
100+ ChatGPT Prompts for SEO Optimization100+ ChatGPT Prompts for SEO Optimization
100+ ChatGPT Prompts for SEO Optimizationarrow10202532yuvraj
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
Valere | Digital Solutions & AI Transformation Portfolio | 2024
Valere | Digital Solutions & AI Transformation Portfolio | 2024Valere | Digital Solutions & AI Transformation Portfolio | 2024
Valere | Digital Solutions & AI Transformation Portfolio | 2024Alexander Turgeon
 
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"DianaGray10
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Websitedgelyza
 

Recently uploaded (20)

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and Hazards
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 
VoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBXVoIP Service and Marketing using Odoo and Asterisk PBX
VoIP Service and Marketing using Odoo and Asterisk PBX
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
Governance in SharePoint Premium:What's in the box?
Governance in SharePoint Premium:What's in the box?Governance in SharePoint Premium:What's in the box?
Governance in SharePoint Premium:What's in the box?
 
100+ ChatGPT Prompts for SEO Optimization
100+ ChatGPT Prompts for SEO Optimization100+ ChatGPT Prompts for SEO Optimization
100+ ChatGPT Prompts for SEO Optimization
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
Valere | Digital Solutions & AI Transformation Portfolio | 2024
Valere | Digital Solutions & AI Transformation Portfolio | 2024Valere | Digital Solutions & AI Transformation Portfolio | 2024
Valere | Digital Solutions & AI Transformation Portfolio | 2024
 
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"
UiPath Clipboard AI: "A TIME Magazine Best Invention of 2023 Unveiled"
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
COMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a WebsiteCOMPUTER 10 Lesson 8 - Building a Website
COMPUTER 10 Lesson 8 - Building a Website
 

Refactoring at Large

  • 1. Refactoring at Large Danilo Sato - @dtsato ThoughtWorks www.dtsato.com
  • 6. My Plan for Today + • “Inside out” approach • Show me Code (Java) • Strategies and Objectives • Refactoring Ruby/Rails - • Larger refactorings
  • 8. Why do we change code?
  • 9. Why do we change code? • Add features
  • 10. Why do we change code? • Add features • Fix bugs
  • 11. Why do we change code? • Add features • Fix bugs • Improve design
  • 12. Why do we change code? • Add features • Fix bugs • Improve design • Optimization
  • 13. Why do we change code? • Add features • Fix bugs • Improve design • Optimization
  • 17. "Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior."
  • 18. Refactoring Code
  • 19. Refactoring Code
  • 20. Refactoring Code Extr act Method
  • 21. Refactoring Code
  • 22. Refactoring Code
  • 23. Refactoring Code Eliminate Duplication
  • 24. Extract Method • Move Method • Extract Class • Remove Middle Man • Self Encapsulate Field • Decompose Conditional • ...
  • 25. Tests! Code Test
  • 26. Tests! Code Test
  • 27. Tests! Code Test Eliminate Duplication
  • 28. Other types... Code Test
  • 29. Other types... Code Code Test
  • 30. Other types... Code Code Test Test
  • 31. Other types... Code Code Test Test Split Responsibility
  • 32. Other types... Code Test
  • 35. Other types... Test Code Change Design
  • 45. CheckoutControllerTest CheckoutController Order Cart
  • 46. - 1 2/10/refactoring o.com/blog/2011/ http://www.dtsat / h rough-experiment st rategies-a-walkt - 0 9/01/refactoring http://paulh ammant.com/2011/ experiment CheckoutControllerTest CheckoutController Order Cart
  • 47. 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]]}}}")); } }
  • 48. @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"; } }
  • 49. Mechanics t his video on: riment Watch factoring-expe com/dt sato/re p://vimeo. htt
  • 50. First Attempt... t his video on: riment Watch factoring-expe com/dt sato/re p://vimeo. htt
  • 51. Strategy t his video on: riment Watch factoring-expe com/dt sato/re p://vimeo. htt
  • 54. Identify your Objective “Active” design
  • 55. Identify your Objective “Active” design • OO Design
  • 56. Identify your Objective “Active” design • OO Design • Project direction
  • 57. Identify your Objective “Active” design • OO Design • Project direction • Architectural decisions
  • 58. Identify your Objective “Passive” design
  • 59. Identify your Objective “Passive” design • Bad Smells
  • 60. Identify your Objective “Passive” design • Bad Smells • Metrics
  • 61. Identify your Objective “Passive” design • Bad Smells • Metrics • Visualizations
  • 63. Strategize ? ? ?
  • 65. Strategize • Isolate the impact of Change
  • 66. Strategize • Isolate the impact of Change • Baby Steps
  • 67. Strategize • Isolate the impact of Change • Baby Steps • Keep the tests green
  • 68. Strategize • Isolate the impact of Change • Baby Steps • Keep the tests green • Moving backwards before moving forward
  • 69. CalendarSearchController CalendarSearchController Test Event Event
  • 70. r dtsato/kata-ref actoring-calenda http ://github.com/ CalendarSearchController CalendarSearchController Test Event Event
  • 71. 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
  • 72. 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
  • 73. 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
  • 74. 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 multiple named scopes @events = scope.all end
  • 75. 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
  • 76. different ways to do the same class Event < ActiveRecord::Base thing 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
  • 77. 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} } } more logic 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
  • 78. Objectives Active: • Isolate unit tests from the database Passive: • Deal with bad smells
  • 79. Strategizing 1. Centralize date manipulation logic 2. Unify named scopes 3. Extract logic from Controller 4. Break timeframe into separate pieces
  • 80. 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
  • 81. class Event < ActiveRecord::Base named_scope :between_dates, lambda { |start_date, end_date| {:conditions => {:at => start_date..end_date}} } end
  • 82. 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(-)
  • 83. Before . ............ 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(-)
  • 84. Before ....... After . ............ 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(-)
  • 85. Strategizing 1. Centralize date manipulation logic 2. Unify named scopes 3. Extract logic from Controller 4. Break timeframe into separate pieces
  • 86. 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 change to tests: 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
  • 87. 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
  • 88. describe "Acceptance tests" do around(:each) do |example| After ...... 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
  • 89. 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
  • 90. 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
  • 91. 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(-)
  • 92. Before ....... 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(-)
  • 93. Before ........ After ....... 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(-)
  • 94. Strategizing 1. Centralize date manipulation logic 2. Unify named scopes 3. Extract logic from Controller 4. Break timeframe into separate pieces
  • 95. 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
  • 96. 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
  • 97. class TimeFrame ... Before .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
  • 98. class TimeFrame ... Before ............ After 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
  • 99. class TimeFrame ... Before ............ After 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
  • 100. “Big Picture” • Architectural Changes • Consolidating different approaches • Substituting components/frameworks
  • 102. “Big Picture” Scope Risk Effort Communication
  • 103. Change
  • 104. x x x x x x x Change x xx x
  • 105. x x x x x x x Change x xx x
  • 106. x x x x x x x x x xx x Change xxx x xx x
  • 107. x x xx x x x x x x x x x x xx x Change xxx x xx x
  • 108. x x xx x x x x x x x x x x xx x Change xxx x xx x xx xx x x xxx xx x
  • 109. x x x x x x x x xx x x x x x x x x x x x x x xx x x Change xxx x x x xx x x x x xx xx x x x x x xxx xx x x x x x
  • 111. Change
  • 112. x x x x x x x Change x xx x
  • 113. x x x x x x x Change x xx x
  • 114. x Prereq x x x x x x Change x xx x
  • 115. x Prereq x x x Prereq x x x Change x xx x
  • 116. x Prereq x x x Prereq x x x Change x xx Prereq x
  • 117. Prereq Prereq Change Prereq
  • 118. x x Prereq Prereq xx x Change xxx Prereq
  • 119. x Prereq x Prereq Prereq xx x Prereq Change xxx Prereq
  • 120. Prereq Prereq Prereq Prereq Change Prereq
  • 121. Prereq Prereq Prereq Prereq Change Prereq
  • 122. Prereq Prereq Prereq Prereq ✔ Change Prereq
  • 123. Prereq Prereq Prereq Prereq ✔ Change Prereq
  • 124. Prereq ✔ Prereq Prereq Prereq ✔ Change Prereq
  • 125. Prereq ✔ Prereq ✔ Prereq Prereq ✔ Change Prereq
  • 126. Prereq ✔ Prereq ✔ Prereq Prereq ✔ Change Prereq
  • 127. Prereq ✔ Prereq ✔ Prereq ✔ Prereq ✔ Change Prereq
  • 128. Prereq ✔ Prereq ✔ Prereq ✔ Prereq ✔ Change Prereq
  • 129. Prereq ✔ Prereq ✔ Prereq ✔ Prereq ✔ Change Prereq ✔
  • 130. Prereq ✔ Prereq ✔ Prereq ✔ Prereq ✔ Change ✔ Prereq ✔
  • 131. A story APP
  • 132. A story APP SVC
  • 133. A story APP SVC
  • 134. A story APP SVC
  • 135. The truth APP Model View Controller
  • 136. The truth APP Model View Controller Helper
  • 137. The truth APP Model View SVC Controller Helper
  • 138. The truth APP Model View SVC Controller everything is going to break !!! Helper
  • 139. Transitional Architecture APP Model View Controller SVC Helper
  • 140. Transitional Architecture APP Model View Controller SVC Helper
  • 141. Transitional Architecture APP Model View Controller SVC Helper
  • 142. Transitional Architecture APP Model View Controller SVC Helper
  • 143. Transitional Architecture APP Model View Controller SVC Helper
  • 144. Transitional Architecture APP Model View Controller SVC Helper
  • 145. Transitional Architecture • Go: • “Branch by Abstraction” • Migrating from iBatis to Hibernate • Migrating from Velocity/JsTemplate to JRuby on Rails
  • 146. Transitional Architecture • Go: • “Branch by Abstraction” • Migrating from iBatis to Hibernate • Migrating from Velocity/JsTemplate to JRuby on Rails - 0 11/05/make-large http://continuo usdelivery.com/2 - l y-with-branch-by scale-cha nges-incremental abstraction/
  • 147. References Books: "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 Credits (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/ Code: https://github.com/dtsato/refactoring_experiment https://github.com/dtsato/kata-refactoring-calendar
  • 148. Obrigado! Danilo Sato - @dtsato ThoughtWorks www.dtsato.com

Editor's Notes

  1. \n
  2. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  3. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  4. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  5. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  6. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  7. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  8. Developer, Agile Coach, Tech Lead, DevOps, Trainer\n
  9. Assumptions:\n- You&amp;#x2019;re not in a complete mess\n- You have tests\n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. zoom out\n
  17. zoom out\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. \n
  64. \n
  65. Mec&amp;#xE2;nica: IDE resolve, ferramentas, cat&amp;#xE1;logos...\n
  66. Exerc&amp;#xED;cios para praticar\nMelhoram uma habilidade espec&amp;#xED;fica: TDD, Algoritmos, Design, C&amp;#xF3;digo ruim? etc...\n
  67. Cobertura 100%\nApplica&amp;#xE7;&amp;#xE3;o Java/Spring\n
  68. \n
  69. Objetivo: extrair placeOrder para outro controller\n
  70. Extracting placeOrder() into a new OrderController class, and a new OrderControllerTest.\nNote: Controller Annotation is copy/pasted\n
  71. Note: Controller name first typo (Products -&gt; SuggestedProducts)\n\n
  72. Extracting Upseller collaborator\nNote: Controller annotation needs to be copy/pasted\n
  73. \n
  74. N&amp;#xE3;o tem segredo para identificar objetivo (NFRs)\n
  75. N&amp;#xE3;o tem segredo para identificar objetivo (NFRs)\n
  76. N&amp;#xE3;o tem segredo para identificar objetivo (NFRs)\n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  86. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  87. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  88. Michael Feathers: Effect Sketches\nCluster de m&amp;#xE9;todos/atributos\nMova c&amp;#xF3;digo repetido para um mesmo lugar\n
  89. 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
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. * 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
  101. * 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
  102. * 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
  103. * 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
  104. \n
  105. Skinny Controller\nTestes do Controller usam mocks para testar colabora&amp;#xE7;&amp;#xE3;o\n
  106. Testes do controller moveram para teste de aceita&amp;#xE7;&amp;#xE3;o (cucumber?)\n\n
  107. * Timeframe s&amp;#xF3; cont&amp;#xEA;m start/end\n* L&amp;#xF3;gica ainda &amp;#xE9; feia\n
  108. * 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
  109. * 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
  110. * 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
  111. \n
  112. * Separa&amp;#xE7;&amp;#xE3;o de subclasses em TimeFrame para remover switch/case\n* Testes mudam junto\n
  113. * 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
  114. * 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
  115. * 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
  116. \n
  117. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\nRequires a disciplined approach to tackling large changes\n
  118. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\nRequires a disciplined approach to tackling large changes\n
  119. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\nRequires a disciplined approach to tackling large changes\n
  120. L&amp;#xED;der T&amp;#xE9;cnico: compartilha a vis&amp;#xE3;o\nWorkshops de arquitetura presente vs. futura\nRequires a disciplined approach to tackling large changes\n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n
  129. \n
  130. \n
  131. \n
  132. \n
  133. 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
  134. \n
  135. \n
  136. \n
  137. \n
  138. \n
  139. \n
  140. \n
  141. \n
  142. \n
  143. \n
  144. \n
  145. \n
  146. \n
  147. \n
  148. \n
  149. \n
  150. \n
  151. \n
  152. \n
  153. \n
  154. \n
  155. \n
  156. Exemplo\n
  157. Exemplo\n
  158. Exemplo\n
  159. Exemplo\n
  160. Exemplo\n
  161. Exemplo\n
  162. Exemplo\n
  163. Exemplo\n
  164. Exemplo\n
  165. Exemplo\n
  166. Exemplo\n
  167. Exemplo\n
  168. Exemplo\n
  169. Exemplo\n
  170. \n
  171. \n
  172. \n