SlideShare une entreprise Scribd logo
1  sur  42
TDD
and
OO
Design
Lessons
from
 We
value
code

  
 that
is
easy
to
maintain

 over
code

  
 that
is
easy
to
write
Some
Design
Principles

   Not
meant
to
be
comprehensive




                                    3
   Coupling
and
Cohesion:
     Loose
coupling

easier
maintenance
     Cohesion:
unit
of
responsibility
   Roles,
Responsibilities,
Collaborators:
     Role:
set
of
related
responsibilities
     Collaborators:
roles
you
interact
with
   Internals
vs.
Peers
   No
And’s,
Or’s,
or
But’s
     Every
object
should
have
a
single,
clearly
defined

      responsibility
   Three
types
of
Peers:
     Dependencies
      ▪ The
object
can’t
live
without
them
     Notifications
      ▪ Need
to
be
kept
up
to
date,
but
we
“don’t
care”
if
they

        listen
     Adjustments
   New
or
new
not.
There
is
no
try.
(Yoda)

 Dependencies
have
to
be
passed
into
the

  constructor.
 Notifications
and
Adjustments
can
be

  initialised
to
safe
defaults.
   Identify
Relationships
with
Interfaces
   Keep
interfaces
narrow
   Interfaces
are
pulled
into
existence
by
tests
   No
I<class>
(ICustomer 
Customer)
   No
InterfaceImpl
(Customer 
CustomerImpl)
   Name
each
implementation!
   If
you
don’t
find
a
good
name
for
the

    implementation,
maybe
it’s
not
a
good

    interface…
Important
Design
Principle
Use
with
Objects,
not
People
:‐)
   Try
to
understand
this
(train
wreck):
((EditSaveCustomizer) master
.getModelisable()
  .getDockablePanel()
    .getCustomizer())
      .getSaveItem()

 
        .setEnabled(Boolean.FALSE.booleanValue());

   Isn’t
this
simpler?
master.allowSavingOfCustomisations();
   Or,
now
really
with
a
train:
public class Train {
  private final List<Carriage> carriages […]
  private int percentReservedBarrier = 70;
  public void reserveSeats(ReservationRequest request) {
    for (Carriage carriage : carriages) {
      if (carriage.getSeats().getPercentReserved() <
    
      
       
       
        
      percentReservedBarrier) {
        request.reserveSeatsIn(carriage);
        return;
      }
    }
    request.cannotFindSeats();
  }
}
   Why
isn’t
that
good
design?
   Isn’t
this
simpler?
public void reserveSeats(ReservationRequest request) {
  for (Carriage carriage : carriages) {
    if (carriage.hasSeatsAvailableWithin

 
       
       
       (percentReservedBarrier)) {
      request.reserveSeatsIn(carriage);
      return;
    }
  }
  request.cannotFindSeats() ;
}
General
Tips
on
Testing

   How
to
make
it
simpler...




                                12
Phrase
Messages
with
Meaning

   What
went
wrong
here?
     Found
<null>
expected
<not
null>
     Found
<0>
expected
<17>
 Use
constants
 Use
special
types
     Found
<Harry>
expected
<Customer.NotFound>




                                                   13
Be
Literal

 Numbers,
Strings,
…
are
hard
to
understand
 Better:
     Constants
     Enumerations
     Value
Types
   There
is
no
“too
small”
for
types



                                               14
Beware
“Long”
Strings!

   Test
format
and
contents
independently
   “13/09/10
–
Order
8715
signed
by
Manfred
Mayer”
   Define
a
Value
Type
for
longer
Messages
   “<decision.date>
‐
Order
    
<decision.no>
signed
by
<decision.owner>”
   Public
class
Decision{
     Public
Date
date;
     Public
String
no;
     Public
String
owner;
   }
                                                  15
Use
Assertions
sensibly

   Assert
one
expected
behaviour
in
exactly
one

    test
     Otherwise
you
have
to
regularly
update
multiple

      tests!
     Otherwise
it’s
much
less
clear
what
the
test
does
 Rather
have
one
more
test
than
an
unclear

  one
 The
“Single
Responsibility
Principle”
applies

  here,
too!
                                                          16
Working
with
Test
Data

   How
to
make
your
life
easier




                                   17
   Many
attempts
to
communicate
are
nullified

    by
saying
too
much.—
Robert
Greenleaf
   First
Try
@Test public void chargesCustomerForTotalCostOfAllOrderedItems() {
  Order order = new Order(
    new Customer("Sherlock Holmes",
       new Address("221b Baker Street",
              "London",
              new PostCode("NW1", "3RX"))));
  order.addLine(new OrderLine("Deerstalker Hat", 1));
  order.addLine(new OrderLine("Tweed Cape", 1));
[…]
}
Test
Data‐by
hand?

 Complex,
confusing
 Hard
to
write
 Error‐prone




                       20
   Centralise
test
data
creation…

Order order1 =
  ExampleOrders.newDeerstalkerAndCapeAndSwordstickOrder();
Order order2 =
  ExampleOrders.newDeerstalkerAndBootsOrder();
[…]
 Test
are
clearer,
but...
 Complexity
and
repetition
just
moved
some

  place
else!
 Hide
defaults
 Show
specialties
public class OrderBuilder {
  private Customer customer = new CustomerBuilder().build();
  private List<OrderLine> lines = new ArrayList<OrderLine>();
  private BigDecimal discountRate = BigDecimal.ZERO;
  public static OrderBuilder anOrder() {
    return new OrderBuilder();
  }
  public OrderBuilder withCustomer(Customer customer) {
    this.customer = customer;
    return this;
  }
  public OrderBuilder withOrderLines(List<OrderLine> lines) {
    this.lines = lines;
    return this;
  }
  public OrderBuilder withDiscount(BigDecimal discountRate) {
    this.discountRate = discountRate;
    return this;
  }
  public Order build() {
    Order order = new Order(customer);
    for (OrderLine line : lines) order.addLine(line);
    
 order.setDiscountRate(discountRate);
    }

      return order;
  }
}
public class OrderBuilder {
  private Customer customer = new CustomerBuilder().build();    Default
values
  private List<OrderLine> lines = new ArrayList<OrderLine>();
  private BigDecimal discountRate = BigDecimal.ZERO;
  public static OrderBuilder anOrder() {
    return new OrderBuilder();
  }
  public OrderBuilder withCustomer(Customer customer) {
    this.customer = customer;
    return this;
  }
  public OrderBuilder withOrderLines(List<OrderLine> lines) {
    this.lines = lines;
    return this;
  }
  public OrderBuilder withDiscount(BigDecimal discountRate) {
    this.discountRate = discountRate;
    return this;
  }
  public Order build() {
    Order order = new Order(customer);
    for (OrderLine line : lines) order.addLine(line);
    
 order.setDiscountRate(discountRate);
    }

      return order;
  }
}
public class OrderBuilder {
  private Customer customer = new CustomerBuilder().build();          Default
values
  private List<OrderLine> lines = new ArrayList<OrderLine>();
  private BigDecimal discountRate = BigDecimal.ZERO;
  public static OrderBuilder anOrder() {
    return new OrderBuilder();
  }
  public OrderBuilder withCustomer(Customer customer) {
    this.customer = customer;
    return this;                                                Return:
Builder
  }
  public OrderBuilder withOrderLines(List<OrderLine> lines) {
    this.lines = lines;
    return this;
  }
  public OrderBuilder withDiscount(BigDecimal discountRate) {
    this.discountRate = discountRate;
    return this;
  }
  public Order build() {
    Order order = new Order(customer);
    for (OrderLine line : lines) order.addLine(line);
    
 order.setDiscountRate(discountRate);
    }

      return order;
  }
}
public class OrderBuilder {
  private Customer customer = new CustomerBuilder().build();               Default
values
  private List<OrderLine> lines = new ArrayList<OrderLine>();
  private BigDecimal discountRate = BigDecimal.ZERO;
  public static OrderBuilder anOrder() {
    return new OrderBuilder();
  }
  public OrderBuilder withCustomer(Customer customer) {
    this.customer = customer;
    return this;                                                    Return:
Builder
  }
  public OrderBuilder withOrderLines(List<OrderLine> lines) {
    this.lines = lines;
    return this;
  }
  public OrderBuilder withDiscount(BigDecimal discountRate) {
    this.discountRate = discountRate;
    return this;
  }
  public Order build() {
    Order order = new Order(customer);
    for (OrderLine line : lines) order.addLine(line);
    
 order.setDiscountRate(discountRate);
    }

      return order;                                            build()
always
returns
a
new

  }
}                                                                          order!
   Default
fits
into
one
row:
Order order = new OrderBuilder().build();

   Any
deviation
is
obvious:

new OrderBuilder()
 .fromCustomer(
    new CustomerBuilder()
     .withAddress(new AddressBuilder().withNoPostcode()
   
    
       .build())
     .build())
 .build();
   Creation
using
Object
Mother
hides
the
error:
TestAddresses.newAddress("221b Baker Street", "London", "NW1 6XE");

   With
the
Data
Builder
the
error
is
explicit:
new AddressBuilder()
 .withStreet("221b Baker Street")
 .withStreet2("London")
 .withPostCode("NW1 6XE")
 .build();
   Multiple
objects
lead
to
repetition
(again...):

Order orderWithSmallDiscount = new OrderBuilder()
 .withLine("Deerstalker Hat", 1)
 .withLine("Tweed Cape", 1)
 .withDiscount(0.10)
 .build();
Order orderWithLargeDiscount = new OrderBuilder()
 .withLine("Deerstalker Hat", 1)
 .withLine("Tweed Cape", 1)
 .withDiscount(0.25)
 .build();
   This
is
better
if
objects
differ
in
only
one
field:

OrderBuilder hatAndCape = new OrderBuilder()
 .withLine("Deerstalker Hat", 1)
 .withLine("Tweed Cape", 1);
Order orderWithSmallDiscount =
   hatAndCape.withDiscount(0.10).build();
Order orderWithLargeDiscount =
   hatAndCape.withDiscount(0.25).build();
   Attention,
possible
error:

Order orderWithDiscount = hatAndCape.withDiscount(0.10) .build();
Order orderWithGiftVoucher =
  hatAndCape.withGiftVoucher("abc").build();

   The
second
order
has
a
discount
as
well!
   Better:
    We
add
a
CopyConstructor
to
the
Builder:
Order orderWithDiscount = new OrderBuilder(hatAndCape)
 .withDiscount(0.10)
 .build();
Order orderWithGiftVoucher = new OrderBuilder(hatAndCape)
 .withGiftVoucher("abc")
 .build();
   More
elegant:
    Factory‐Method,
naming
what
it’s
used
for:
Order orderWithDiscount = hatAndCape.

 but().withDiscount( 0.10).build();
Order orderWithGiftVoucher =
  hatAndCape.but().withGiftVoucher("abc").build();
   instead
of:
Order orderWithNoPostcode = new OrderBuilder()
  .fromCustomer(new CustomerBuilder()
      .withAddress(new AddressBuilder()
                                       
    .withNoPostcode()
.build()).build()).build();
   it’s
more
elegant,
to
pass
the
Builder:
Order order = new OrderBuilder()
 .fromCustomer( new CustomerBuilder()
    .withAddress(new AddressBuilder().withNoPostcode() ))).build();
   Even
more
elegant:
Factory
methods
Order order =
anOrder().fromCustomer(
aCustomer().withAddress(anAddress().withNoPostcode() ) ) .build();
   Overloading
makes
it
shorter:
Order order =
   anOrder() .from(aCustomer().with(anAddress().withNoPostcode()))
.build();
   This
is
how
readable
a
test
can
(and
should)

    be.
@Test public void reportsTotalSalesOfOrderedProducts() {
  Order order1 = anOrder()
   .withLine("Deerstalker Hat", 1)
   .withLine("Tweed Cape", 1)
   .withCustomersReference(1234)
   .build();
  requestSender.send(order1);
  progressMonitor.waitForCompletion(order1);
  Order order2 = anOrder()
   .withLine("Deerstalker Hat", 1)
   .withCustomersReference(5678)
   .build();
  requestSender.send(order2);
  progressMonitor.waitForCompletion(order2);
  TotalSalesReport report = gui.openSalesReport();
  report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) ));
  report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1)));
}
@Test public void reportsTotalSalesOfOrderedProducts() {
submitOrderFor("Deerstalker Hat", "Tweed Cape");
submitOrderFor("Deerstalker Hat");
  TotalSalesReport report = gui.openSalesReport();
  report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) ));
  report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1)));
}
void submitOrderFor(String ... products) {
  OrderBuilder orderBuilder = anOrder()
    .withCustomersReference(nextCustomerReference());
  for (String product : products) {
    orderBuilder = orderBuilder.withLine(product, 1);
  }
  Order order = orderBuilder.build();
  requestSender.send(order);
  progressMonitor.waitForCompletion(order);
}
   This
won’t
scale
well:
void submitOrderFor(String ... products) { […]
void submitOrderFor(String product, int count,
            String otherProduct, int otherCount) { […]
void submitOrderFor(String product, double discount) { […]
void submitOrderFor(String product, String giftVoucherCode) { […]
   Better,
to
use
the
builder:
@Test public void reportsTotalSalesOfOrderedProducts() {
sendAndProcess(anOrder()
   .withLine("Deerstalker Hat", 1)
   .withLine("Tweed Cape", 1));
sendAndProcess(anOrder()
   .withLine("Deerstalker Hat", 1));
  TotalSalesReport report = gui.openSalesReport();
  report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) ));
  report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1)));
}
void sendAndProcess(OrderBuilder orderDetails) {
  Order order = orderDetails
   .withDefaultCustomersReference(nextCustomerReference())
   .build();
  requestSender.send(order);
  progressMonitor.waitForCompletion(order);
}
   Better
names
improve
clarity:
@Test public void reportsTotalSalesOfOrderedProducts() {
havingReceived(anOrder()
    .withLine("Deerstalker Hat", 1)
    .withLine("Tweed Cape", 1));
havingReceived(anOrder()
    .withLine("Deerstalker Hat", 1));
  TotalSalesReport report = gui.openSalesReport();
  report.displaysTotalSalesFor("Deerstalker Hat", equalTo(2));
  report.displaysTotalSalesFor("Tweed Cape", equalTo(1) );
}
   This
is
how
readable
a
test
should
be:
@Test public void
    takesAmendmentsIntoAccountWhenCalculatingTotalSales() {
  Customer theCustomer = aCustomer().build();
havingReceived(anOrder().from(theCustomer)
   .withLine("Deerstalker Hat", 1)
   .withLine("Tweed Cape", 1));
havingReceived(anOrderAmendment().from(theCustomer)
   .withLine("Deerstalker Hat", 2));
  TotalSalesReport report = user.openSalesReport();
  report.containsTotalSalesFor("Deerstalker Hat", equalTo(2));
  report.containsTotalSalesFor("Tweed Cape", equalTo(1) );
}

Contenu connexe

En vedette

Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?
Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?
Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?Olaf Lewitz
 
Which Role does Testing Play in an Agile Development Organisation?
Which Role does Testing Play in an Agile Development Organisation?Which Role does Testing Play in an Agile Development Organisation?
Which Role does Testing Play in an Agile Development Organisation?Olaf Lewitz
 
What is Trust? Was ist Vertrauen? #t4at
What is Trust? Was ist Vertrauen? #t4atWhat is Trust? Was ist Vertrauen? #t4at
What is Trust? Was ist Vertrauen? #t4atOlaf Lewitz
 
Invitation Transforms - ALE Kraków
Invitation Transforms - ALE KrakówInvitation Transforms - ALE Kraków
Invitation Transforms - ALE KrakówOlaf Lewitz
 
Trust and responsibility for project success
Trust and responsibility for project successTrust and responsibility for project success
Trust and responsibility for project successOlaf Lewitz
 
Comment libérer et réinventer les organisations­
Comment libérer et réinventer les organisations­Comment libérer et réinventer les organisations­
Comment libérer et réinventer les organisations­Olaf Lewitz
 
Descale your organisation oop
Descale your organisation oopDescale your organisation oop
Descale your organisation oopOlaf Lewitz
 
Agile: A Courageous Choice (Agile Toronto Keynote)
Agile: A Courageous Choice (Agile Toronto Keynote)Agile: A Courageous Choice (Agile Toronto Keynote)
Agile: A Courageous Choice (Agile Toronto Keynote)Olaf Lewitz
 
Integral Quality Agile Testing Days 2015
Integral Quality Agile Testing Days 2015Integral Quality Agile Testing Days 2015
Integral Quality Agile Testing Days 2015Olaf Lewitz
 
Serious Play: Imaginopedia for Core Process
Serious Play: Imaginopedia for Core ProcessSerious Play: Imaginopedia for Core Process
Serious Play: Imaginopedia for Core Processf. & co
 
Booster Partners: Surprisability
Booster Partners: SurprisabilityBooster Partners: Surprisability
Booster Partners: SurprisabilityOlaf Lewitz
 

En vedette (11)

Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?
Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?
Freiheit vs. Sicherheit: Wieviel Unterdrückung ist hilfreich?
 
Which Role does Testing Play in an Agile Development Organisation?
Which Role does Testing Play in an Agile Development Organisation?Which Role does Testing Play in an Agile Development Organisation?
Which Role does Testing Play in an Agile Development Organisation?
 
What is Trust? Was ist Vertrauen? #t4at
What is Trust? Was ist Vertrauen? #t4atWhat is Trust? Was ist Vertrauen? #t4at
What is Trust? Was ist Vertrauen? #t4at
 
Invitation Transforms - ALE Kraków
Invitation Transforms - ALE KrakówInvitation Transforms - ALE Kraków
Invitation Transforms - ALE Kraków
 
Trust and responsibility for project success
Trust and responsibility for project successTrust and responsibility for project success
Trust and responsibility for project success
 
Comment libérer et réinventer les organisations­
Comment libérer et réinventer les organisations­Comment libérer et réinventer les organisations­
Comment libérer et réinventer les organisations­
 
Descale your organisation oop
Descale your organisation oopDescale your organisation oop
Descale your organisation oop
 
Agile: A Courageous Choice (Agile Toronto Keynote)
Agile: A Courageous Choice (Agile Toronto Keynote)Agile: A Courageous Choice (Agile Toronto Keynote)
Agile: A Courageous Choice (Agile Toronto Keynote)
 
Integral Quality Agile Testing Days 2015
Integral Quality Agile Testing Days 2015Integral Quality Agile Testing Days 2015
Integral Quality Agile Testing Days 2015
 
Serious Play: Imaginopedia for Core Process
Serious Play: Imaginopedia for Core ProcessSerious Play: Imaginopedia for Core Process
Serious Play: Imaginopedia for Core Process
 
Booster Partners: Surprisability
Booster Partners: SurprisabilityBooster Partners: Surprisability
Booster Partners: Surprisability
 

Similaire à Learning from GOOS - work in progress

Share pointtechies linqtosp-andsbs
Share pointtechies linqtosp-andsbsShare pointtechies linqtosp-andsbs
Share pointtechies linqtosp-andsbsShakir Majeed Khan
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design PrinciplesJon Kruger
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Vagif Abilov
 
Wann soll ich mocken?
Wann soll ich mocken?Wann soll ich mocken?
Wann soll ich mocken?David Völkel
 
Design patterns for fun and profit
Design patterns for fun and profitDesign patterns for fun and profit
Design patterns for fun and profitNikolas Vourlakis
 
Introducing N1QL: New SQL Based Query Language for JSON
Introducing N1QL: New SQL Based Query Language for JSONIntroducing N1QL: New SQL Based Query Language for JSON
Introducing N1QL: New SQL Based Query Language for JSONKeshav Murthy
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java Emmanuel Neri
 
GraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is not enough - lessons learnedGraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is not enough - lessons learnedMarcinStachniuk
 
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"LogeekNightUkraine
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012Sandeep Joshi
 
Bad test, good test
Bad test, good testBad test, good test
Bad test, good testSeb Rose
 
Java best practices
Java best practicesJava best practices
Java best practicesRay Toal
 
SOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietySOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietyChris Weldon
 
Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101IDERA Software
 
C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)Christian Nagel
 

Similaire à Learning from GOOS - work in progress (20)

SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Share pointtechies linqtosp-andsbs
Share pointtechies linqtosp-andsbsShare pointtechies linqtosp-andsbs
Share pointtechies linqtosp-andsbs
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#
 
Wann soll ich mocken?
Wann soll ich mocken?Wann soll ich mocken?
Wann soll ich mocken?
 
Design patterns for fun and profit
Design patterns for fun and profitDesign patterns for fun and profit
Design patterns for fun and profit
 
Introducing N1QL: New SQL Based Query Language for JSON
Introducing N1QL: New SQL Based Query Language for JSONIntroducing N1QL: New SQL Based Query Language for JSON
Introducing N1QL: New SQL Based Query Language for JSON
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java
 
Introduction to Linq
Introduction to LinqIntroduction to Linq
Introduction to Linq
 
Linq
LinqLinq
Linq
 
GraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is not enough - lessons learnedGraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is not enough - lessons learned
 
MongoDB Meetup
MongoDB MeetupMongoDB Meetup
MongoDB Meetup
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
Andriy Slobodyanyk "How to Use Hibernate: Key Problems and Solutions"
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012
 
Bad test, good test
Bad test, good testBad test, good test
Bad test, good test
 
Java best practices
Java best practicesJava best practices
Java best practices
 
SOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietySOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO Propriety
 
Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101Geek Sync | Rewriting Bad SQL Code 101
Geek Sync | Rewriting Bad SQL Code 101
 
C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)
 

Plus de Olaf Lewitz

How to Use your Emotions - Scrum Gathering Belgrade 2021
How to Use your Emotions - Scrum Gathering Belgrade 2021How to Use your Emotions - Scrum Gathering Belgrade 2021
How to Use your Emotions - Scrum Gathering Belgrade 2021Olaf Lewitz
 
TrustTemenos CAL - Certified Agile Leadership
TrustTemenos CAL - Certified Agile LeadershipTrustTemenos CAL - Certified Agile Leadership
TrustTemenos CAL - Certified Agile LeadershipOlaf Lewitz
 
If agile is the solution i want my problem back
If agile is the solution i want my problem backIf agile is the solution i want my problem back
If agile is the solution i want my problem backOlaf Lewitz
 
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurück
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurückOOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurück
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurückOlaf Lewitz
 
TrustTemenos Certified Agile Leadership
TrustTemenos Certified Agile LeadershipTrustTemenos Certified Agile Leadership
TrustTemenos Certified Agile LeadershipOlaf Lewitz
 
Leading with:in Tension Scan-Agile
Leading with:in Tension Scan-AgileLeading with:in Tension Scan-Agile
Leading with:in Tension Scan-AgileOlaf Lewitz
 
School of Product Ownership: Own Your Product as if it Mattered
School of Product Ownership: Own Your Product as if it MatteredSchool of Product Ownership: Own Your Product as if it Mattered
School of Product Ownership: Own Your Product as if it MatteredOlaf Lewitz
 
Leading with/in Tension Agile in the City Bristol
Leading with/in Tension Agile in the City BristolLeading with/in Tension Agile in the City Bristol
Leading with/in Tension Agile in the City BristolOlaf Lewitz
 
Leading with/in Tension
Leading with/in Tension Leading with/in Tension
Leading with/in Tension Olaf Lewitz
 
Leading with/in Tension - Agile Prague
Leading with/in Tension - Agile Prague Leading with/in Tension - Agile Prague
Leading with/in Tension - Agile Prague Olaf Lewitz
 
Agile Day Riga: How does a Technical Guy become an agile Leader?
Agile Day Riga: How does a Technical Guy become an agile Leader?Agile Day Riga: How does a Technical Guy become an agile Leader?
Agile Day Riga: How does a Technical Guy become an agile Leader?Olaf Lewitz
 
Agile Serbia 2018 - How does a technical guy become an agile leader?
Agile Serbia 2018 - How does a technical guy become an agile leader?Agile Serbia 2018 - How does a technical guy become an agile leader?
Agile Serbia 2018 - How does a technical guy become an agile leader?Olaf Lewitz
 
Organisational Neurobiology and Fitness - Agile 2017
Organisational Neurobiology and Fitness - Agile 2017Organisational Neurobiology and Fitness - Agile 2017
Organisational Neurobiology and Fitness - Agile 2017Olaf Lewitz
 
Agile World - Surprisability
Agile World - SurprisabilityAgile World - Surprisability
Agile World - SurprisabilityOlaf Lewitz
 
Surprisability (Agile in the City)
Surprisability (Agile in the City)Surprisability (Agile in the City)
Surprisability (Agile in the City)Olaf Lewitz
 
Surprisability - AgileEE 2017
Surprisability - AgileEE 2017 Surprisability - AgileEE 2017
Surprisability - AgileEE 2017 Olaf Lewitz
 
Booster Partners - How to Liberate Organisations
Booster Partners - How to Liberate OrganisationsBooster Partners - How to Liberate Organisations
Booster Partners - How to Liberate OrganisationsOlaf Lewitz
 
Surprisability - Agile Prague Sept 2016
Surprisability - Agile Prague Sept 2016Surprisability - Agile Prague Sept 2016
Surprisability - Agile Prague Sept 2016Olaf Lewitz
 
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?Olaf Lewitz
 
Integral Quality ATAGTR16
Integral Quality ATAGTR16Integral Quality ATAGTR16
Integral Quality ATAGTR16Olaf Lewitz
 

Plus de Olaf Lewitz (20)

How to Use your Emotions - Scrum Gathering Belgrade 2021
How to Use your Emotions - Scrum Gathering Belgrade 2021How to Use your Emotions - Scrum Gathering Belgrade 2021
How to Use your Emotions - Scrum Gathering Belgrade 2021
 
TrustTemenos CAL - Certified Agile Leadership
TrustTemenos CAL - Certified Agile LeadershipTrustTemenos CAL - Certified Agile Leadership
TrustTemenos CAL - Certified Agile Leadership
 
If agile is the solution i want my problem back
If agile is the solution i want my problem backIf agile is the solution i want my problem back
If agile is the solution i want my problem back
 
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurück
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurückOOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurück
OOP 2020 Wenn Agil die Lösung ist dann hätte ich gerne mein Problem zurück
 
TrustTemenos Certified Agile Leadership
TrustTemenos Certified Agile LeadershipTrustTemenos Certified Agile Leadership
TrustTemenos Certified Agile Leadership
 
Leading with:in Tension Scan-Agile
Leading with:in Tension Scan-AgileLeading with:in Tension Scan-Agile
Leading with:in Tension Scan-Agile
 
School of Product Ownership: Own Your Product as if it Mattered
School of Product Ownership: Own Your Product as if it MatteredSchool of Product Ownership: Own Your Product as if it Mattered
School of Product Ownership: Own Your Product as if it Mattered
 
Leading with/in Tension Agile in the City Bristol
Leading with/in Tension Agile in the City BristolLeading with/in Tension Agile in the City Bristol
Leading with/in Tension Agile in the City Bristol
 
Leading with/in Tension
Leading with/in Tension Leading with/in Tension
Leading with/in Tension
 
Leading with/in Tension - Agile Prague
Leading with/in Tension - Agile Prague Leading with/in Tension - Agile Prague
Leading with/in Tension - Agile Prague
 
Agile Day Riga: How does a Technical Guy become an agile Leader?
Agile Day Riga: How does a Technical Guy become an agile Leader?Agile Day Riga: How does a Technical Guy become an agile Leader?
Agile Day Riga: How does a Technical Guy become an agile Leader?
 
Agile Serbia 2018 - How does a technical guy become an agile leader?
Agile Serbia 2018 - How does a technical guy become an agile leader?Agile Serbia 2018 - How does a technical guy become an agile leader?
Agile Serbia 2018 - How does a technical guy become an agile leader?
 
Organisational Neurobiology and Fitness - Agile 2017
Organisational Neurobiology and Fitness - Agile 2017Organisational Neurobiology and Fitness - Agile 2017
Organisational Neurobiology and Fitness - Agile 2017
 
Agile World - Surprisability
Agile World - SurprisabilityAgile World - Surprisability
Agile World - Surprisability
 
Surprisability (Agile in the City)
Surprisability (Agile in the City)Surprisability (Agile in the City)
Surprisability (Agile in the City)
 
Surprisability - AgileEE 2017
Surprisability - AgileEE 2017 Surprisability - AgileEE 2017
Surprisability - AgileEE 2017
 
Booster Partners - How to Liberate Organisations
Booster Partners - How to Liberate OrganisationsBooster Partners - How to Liberate Organisations
Booster Partners - How to Liberate Organisations
 
Surprisability - Agile Prague Sept 2016
Surprisability - Agile Prague Sept 2016Surprisability - Agile Prague Sept 2016
Surprisability - Agile Prague Sept 2016
 
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?
AgileTransitionDay: Wer ist Agilität und wenn ja, wie viele?
 
Integral Quality ATAGTR16
Integral Quality ATAGTR16Integral Quality ATAGTR16
Integral Quality ATAGTR16
 

Dernier

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
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
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKJago de Vreede
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 

Dernier (20)

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
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
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 

Learning from GOOS - work in progress

  • 2.  We
value
code
 
 that
is
easy
to
maintain
  over
code
 
 that
is
easy
to
write
  • 3. Some
Design
Principles  Not
meant
to
be
comprehensive 3
  • 4. Coupling
and
Cohesion:  Loose
coupling

easier
maintenance  Cohesion:
unit
of
responsibility  Roles,
Responsibilities,
Collaborators:  Role:
set
of
related
responsibilities  Collaborators:
roles
you
interact
with  Internals
vs.
Peers
  • 5. No
And’s,
Or’s,
or
But’s  Every
object
should
have
a
single,
clearly
defined
 responsibility  Three
types
of
Peers:  Dependencies ▪ The
object
can’t
live
without
them  Notifications ▪ Need
to
be
kept
up
to
date,
but
we
“don’t
care”
if
they
 listen  Adjustments
  • 6. New
or
new
not.
There
is
no
try.
(Yoda)  Dependencies
have
to
be
passed
into
the
 constructor.  Notifications
and
Adjustments
can
be
 initialised
to
safe
defaults.
  • 7. Identify
Relationships
with
Interfaces  Keep
interfaces
narrow  Interfaces
are
pulled
into
existence
by
tests  No
I<class>
(ICustomer 
Customer)  No
InterfaceImpl
(Customer 
CustomerImpl)  Name
each
implementation!  If
you
don’t
find
a
good
name
for
the
 implementation,
maybe
it’s
not
a
good
 interface…
  • 9. Try
to
understand
this
(train
wreck): ((EditSaveCustomizer) master .getModelisable() .getDockablePanel() .getCustomizer()) .getSaveItem() .setEnabled(Boolean.FALSE.booleanValue());  Isn’t
this
simpler? master.allowSavingOfCustomisations();
  • 10. Or,
now
really
with
a
train: public class Train { private final List<Carriage> carriages […] private int percentReservedBarrier = 70; public void reserveSeats(ReservationRequest request) { for (Carriage carriage : carriages) { if (carriage.getSeats().getPercentReserved() < percentReservedBarrier) { request.reserveSeatsIn(carriage); return; } } request.cannotFindSeats(); } }  Why
isn’t
that
good
design?
  • 11. Isn’t
this
simpler? public void reserveSeats(ReservationRequest request) { for (Carriage carriage : carriages) { if (carriage.hasSeatsAvailableWithin (percentReservedBarrier)) { request.reserveSeatsIn(carriage); return; } } request.cannotFindSeats() ; }
  • 12. General
Tips
on
Testing  How
to
make
it
simpler... 12
  • 13. Phrase
Messages
with
Meaning  What
went
wrong
here?  Found
<null>
expected
<not
null>  Found
<0>
expected
<17>  Use
constants  Use
special
types  Found
<Harry>
expected
<Customer.NotFound> 13
  • 14. Be
Literal  Numbers,
Strings,
…
are
hard
to
understand  Better:  Constants  Enumerations  Value
Types  There
is
no
“too
small”
for
types 14
  • 15. Beware
“Long”
Strings!  Test
format
and
contents
independently  “13/09/10
–
Order
8715
signed
by
Manfred
Mayer”  Define
a
Value
Type
for
longer
Messages  “<decision.date>
‐
Order 
<decision.no>
signed
by
<decision.owner>”  Public
class
Decision{  Public
Date
date;  Public
String
no;  Public
String
owner;  } 15
  • 16. Use
Assertions
sensibly  Assert
one
expected
behaviour
in
exactly
one
 test  Otherwise
you
have
to
regularly
update
multiple
 tests!  Otherwise
it’s
much
less
clear
what
the
test
does  Rather
have
one
more
test
than
an
unclear
 one  The
“Single
Responsibility
Principle”
applies
 here,
too! 16
  • 17. Working
with
Test
Data  How
to
make
your
life
easier 17
  • 18. Many
attempts
to
communicate
are
nullified
 by
saying
too
much.—
Robert
Greenleaf
  • 19. First
Try @Test public void chargesCustomerForTotalCostOfAllOrderedItems() { Order order = new Order( new Customer("Sherlock Holmes", new Address("221b Baker Street", "London", new PostCode("NW1", "3RX")))); order.addLine(new OrderLine("Deerstalker Hat", 1)); order.addLine(new OrderLine("Tweed Cape", 1)); […] }
  • 21. Centralise
test
data
creation…
 Order order1 = ExampleOrders.newDeerstalkerAndCapeAndSwordstickOrder(); Order order2 = ExampleOrders.newDeerstalkerAndBootsOrder(); […]
  • 24. public class OrderBuilder { private Customer customer = new CustomerBuilder().build(); private List<OrderLine> lines = new ArrayList<OrderLine>(); private BigDecimal discountRate = BigDecimal.ZERO; public static OrderBuilder anOrder() { return new OrderBuilder(); } public OrderBuilder withCustomer(Customer customer) { this.customer = customer; return this; } public OrderBuilder withOrderLines(List<OrderLine> lines) { this.lines = lines; return this; } public OrderBuilder withDiscount(BigDecimal discountRate) { this.discountRate = discountRate; return this; } public Order build() { Order order = new Order(customer); for (OrderLine line : lines) order.addLine(line); order.setDiscountRate(discountRate); } return order; } }
  • 25. public class OrderBuilder { private Customer customer = new CustomerBuilder().build(); Default
values private List<OrderLine> lines = new ArrayList<OrderLine>(); private BigDecimal discountRate = BigDecimal.ZERO; public static OrderBuilder anOrder() { return new OrderBuilder(); } public OrderBuilder withCustomer(Customer customer) { this.customer = customer; return this; } public OrderBuilder withOrderLines(List<OrderLine> lines) { this.lines = lines; return this; } public OrderBuilder withDiscount(BigDecimal discountRate) { this.discountRate = discountRate; return this; } public Order build() { Order order = new Order(customer); for (OrderLine line : lines) order.addLine(line); order.setDiscountRate(discountRate); } return order; } }
  • 26. public class OrderBuilder { private Customer customer = new CustomerBuilder().build(); Default
values private List<OrderLine> lines = new ArrayList<OrderLine>(); private BigDecimal discountRate = BigDecimal.ZERO; public static OrderBuilder anOrder() { return new OrderBuilder(); } public OrderBuilder withCustomer(Customer customer) { this.customer = customer; return this; Return:
Builder } public OrderBuilder withOrderLines(List<OrderLine> lines) { this.lines = lines; return this; } public OrderBuilder withDiscount(BigDecimal discountRate) { this.discountRate = discountRate; return this; } public Order build() { Order order = new Order(customer); for (OrderLine line : lines) order.addLine(line); order.setDiscountRate(discountRate); } return order; } }
  • 27. public class OrderBuilder { private Customer customer = new CustomerBuilder().build(); Default
values private List<OrderLine> lines = new ArrayList<OrderLine>(); private BigDecimal discountRate = BigDecimal.ZERO; public static OrderBuilder anOrder() { return new OrderBuilder(); } public OrderBuilder withCustomer(Customer customer) { this.customer = customer; return this; Return:
Builder } public OrderBuilder withOrderLines(List<OrderLine> lines) { this.lines = lines; return this; } public OrderBuilder withDiscount(BigDecimal discountRate) { this.discountRate = discountRate; return this; } public Order build() { Order order = new Order(customer); for (OrderLine line : lines) order.addLine(line); order.setDiscountRate(discountRate); } return order; build()
always
returns
a
new
 } } order!
  • 28. Default
fits
into
one
row: Order order = new OrderBuilder().build();  Any
deviation
is
obvious: new OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode() .build()) .build()) .build();
  • 29. Creation
using
Object
Mother
hides
the
error: TestAddresses.newAddress("221b Baker Street", "London", "NW1 6XE");  With
the
Data
Builder
the
error
is
explicit: new AddressBuilder() .withStreet("221b Baker Street") .withStreet2("London") .withPostCode("NW1 6XE") .build();
  • 30. Multiple
objects
lead
to
repetition
(again...): Order orderWithSmallDiscount = new OrderBuilder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1) .withDiscount(0.10) .build(); Order orderWithLargeDiscount = new OrderBuilder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1) .withDiscount(0.25) .build();
  • 31. This
is
better
if
objects
differ
in
only
one
field: OrderBuilder hatAndCape = new OrderBuilder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1); Order orderWithSmallDiscount = hatAndCape.withDiscount(0.10).build(); Order orderWithLargeDiscount = hatAndCape.withDiscount(0.25).build();
  • 32. Attention,
possible
error: Order orderWithDiscount = hatAndCape.withDiscount(0.10) .build(); Order orderWithGiftVoucher = hatAndCape.withGiftVoucher("abc").build();  The
second
order
has
a
discount
as
well!
  • 33. Better: We
add
a
CopyConstructor
to
the
Builder: Order orderWithDiscount = new OrderBuilder(hatAndCape) .withDiscount(0.10) .build(); Order orderWithGiftVoucher = new OrderBuilder(hatAndCape) .withGiftVoucher("abc") .build();
  • 34. More
elegant: Factory‐Method,
naming
what
it’s
used
for: Order orderWithDiscount = hatAndCape. but().withDiscount( 0.10).build(); Order orderWithGiftVoucher = hatAndCape.but().withGiftVoucher("abc").build();
  • 35. instead
of: Order orderWithNoPostcode = new OrderBuilder() .fromCustomer(new CustomerBuilder() .withAddress(new AddressBuilder() .withNoPostcode() .build()).build()).build();  it’s
more
elegant,
to
pass
the
Builder: Order order = new OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode() ))).build();
  • 36. Even
more
elegant:
Factory
methods Order order = anOrder().fromCustomer( aCustomer().withAddress(anAddress().withNoPostcode() ) ) .build();  Overloading
makes
it
shorter: Order order = anOrder() .from(aCustomer().with(anAddress().withNoPostcode())) .build();  This
is
how
readable
a
test
can
(and
should)
 be.
  • 37. @Test public void reportsTotalSalesOfOrderedProducts() { Order order1 = anOrder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1) .withCustomersReference(1234) .build(); requestSender.send(order1); progressMonitor.waitForCompletion(order1); Order order2 = anOrder() .withLine("Deerstalker Hat", 1) .withCustomersReference(5678) .build(); requestSender.send(order2); progressMonitor.waitForCompletion(order2); TotalSalesReport report = gui.openSalesReport(); report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) )); report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1))); }
  • 38. @Test public void reportsTotalSalesOfOrderedProducts() { submitOrderFor("Deerstalker Hat", "Tweed Cape"); submitOrderFor("Deerstalker Hat"); TotalSalesReport report = gui.openSalesReport(); report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) )); report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1))); } void submitOrderFor(String ... products) { OrderBuilder orderBuilder = anOrder() .withCustomersReference(nextCustomerReference()); for (String product : products) { orderBuilder = orderBuilder.withLine(product, 1); } Order order = orderBuilder.build(); requestSender.send(order); progressMonitor.waitForCompletion(order); }
  • 39. This
won’t
scale
well: void submitOrderFor(String ... products) { […] void submitOrderFor(String product, int count, String otherProduct, int otherCount) { […] void submitOrderFor(String product, double discount) { […] void submitOrderFor(String product, String giftVoucherCode) { […]
  • 40. Better,
to
use
the
builder: @Test public void reportsTotalSalesOfOrderedProducts() { sendAndProcess(anOrder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1)); sendAndProcess(anOrder() .withLine("Deerstalker Hat", 1)); TotalSalesReport report = gui.openSalesReport(); report.checkDisplayedTotalSalesFor("Deerstalker Hat", is(equalTo(2) )); report.checkDisplayedTotalSalesFor("Tweed Cape", is(equalTo(1))); } void sendAndProcess(OrderBuilder orderDetails) { Order order = orderDetails .withDefaultCustomersReference(nextCustomerReference()) .build(); requestSender.send(order); progressMonitor.waitForCompletion(order); }
  • 41. Better
names
improve
clarity: @Test public void reportsTotalSalesOfOrderedProducts() { havingReceived(anOrder() .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1)); havingReceived(anOrder() .withLine("Deerstalker Hat", 1)); TotalSalesReport report = gui.openSalesReport(); report.displaysTotalSalesFor("Deerstalker Hat", equalTo(2)); report.displaysTotalSalesFor("Tweed Cape", equalTo(1) ); }
  • 42. This
is
how
readable
a
test
should
be: @Test public void takesAmendmentsIntoAccountWhenCalculatingTotalSales() { Customer theCustomer = aCustomer().build(); havingReceived(anOrder().from(theCustomer) .withLine("Deerstalker Hat", 1) .withLine("Tweed Cape", 1)); havingReceived(anOrderAmendment().from(theCustomer) .withLine("Deerstalker Hat", 2)); TotalSalesReport report = user.openSalesReport(); report.containsTotalSalesFor("Deerstalker Hat", equalTo(2)); report.containsTotalSalesFor("Tweed Cape", equalTo(1) ); }

Notes de l'éditeur

  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. This.lines = lines (aber &amp;#xFC;bergibts OrderLines); deklarierst aber list&lt;orderline&gt; lines\n\nDas passt nicht!\n\npublic OrderBuilder withOrderLines(List&lt;OrderLine&gt; lines) { this.lines = lines; return this; }\n
  27. This.lines = lines (aber &amp;#xFC;bergibts OrderLines); deklarierst aber list&lt;orderline&gt; lines\n\nDas passt nicht!\n\npublic OrderBuilder withOrderLines(List&lt;OrderLine&gt; lines) { this.lines = lines; return this; }\n
  28. This.lines = lines (aber &amp;#xFC;bergibts OrderLines); deklarierst aber list&lt;orderline&gt; lines\n\nDas passt nicht!\n\npublic OrderBuilder withOrderLines(List&lt;OrderLine&gt; lines) { this.lines = lines; return this; }\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