SlideShare ist ein Scribd-Unternehmen logo
1 von 62
Downloaden Sie, um offline zu lesen
Clean Coding Practices for Java Developers




 Clean Coding Practices for Java Developers




                                      John	
  Ferguson	
  Smart
                               john.smart@wakaleo.com
                               	
  h2p://www.wakaleo.com
                                          Twi2er:	
  wakaleo
So who is this guy, anyway?
               Consulta
                       nt
               Trainer
              Mentor
              Author
             Speaker
             Coder
   John Fer
            guson S
                    mar t
Who	
  are	
  you	
  wri;ng	
  code	
  for,	
  anyway?
Who	
  are	
  you	
  wri;ng	
  code	
  for,	
  anyway?




                                The	
  computer?
Who	
  are	
  you	
  wri;ng	
  code	
  for,	
  anyway?




                             Other	
  developers?
Who	
  are	
  you	
  wri;ng	
  code	
  for,	
  anyway?




                                Your	
  next	
  boss?
Clean Coding Practices for Java Developers



        Why	
  is	
  clean	
  code	
  so	
  important?
Easier	
  to	
  Understand




Easier	
  to	
  Change




            Cheaper	
  to	
  Maintain
Choose	
  your	
  names	
  well




"What's in a name? That which we call a rose
  By any other name would smell as sweet."
                 Romeo and Juliet (II, ii, 1-2)
   Really?
Use	
  a	
  common	
  vocabulary

getCustomerInfo()
getClientDetails()
getCustomerRecord()
...
    Which one do I use? Are they the same?



           getCustomer()
                Choose one and stick to it
Use	
  meaningful	
  names

int days;




              What does this represent?


int daysSinceCreation;

 int daysSinceLastModification;

    int durationInDays;

                         These are all more meaningful choices
Don’t	
  talk	
  in	
  code

class DtaRcrd102 {
    private Date genymdhms;
    private Date modymdhms;
    private final String pszqint = “102”;
    ...
}                                     Huh?

class Customer {
  private Date generationTimestamp;
  private Date modificationTimestamp;
  private final String recordId = “102”
  ...
}
But	
  don’t	
  state	
  the	
  obvious

List<Client> clientList;


                        Is ‘List’ significant or just noise?




List<Client> clients;

  List<Client> regularClients;

     List<Client> newClients;
In	
  short:	
  Don’t	
  make	
  me	
  think!
                                                        What does this do?




                                                   Clearer parameter name
More explicit method name


                                                       What are we counting?




 Method call rather than
  boolean expression
Make	
  your	
  code	
  tell	
  a	
  story
High-Level
Methods	
  should	
  be	
  small                                      Refactoring
  public void generateAggregateReportFor(final List<StoryTestResults> storyResults,
                                         final List<FeatureResults> featureResults) throws IOException {
      LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory());

      copyResourcesToOutputDirectory();

      Map<String, Object> storyContext = new HashMap<String, Object>();
      storyContext.put("stories", storyResults);
      storyContext.put("storyContext", "All stories");
      addFormattersToContext(storyContext);
      writeReportToOutputDirectory("stories.html",
                                   mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(storyContext));

      Map<String, Object> featureContext = new HashMap<String, Object>();
      addFormattersToContext(featureContext);
      featureContext.put("features", featureResults);
      writeReportToOutputDirectory("features.html",
                                   mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext));

      for(FeatureResults feature : featureResults) {
          generateStoryReportForFeature(feature);
      }

      generateReportHomePage(storyResults, featureResults);


                                          Code hard to understand
      getTestHistory().updateData(featureResults);

      generateHistoryReport();
  }
High-Level
Methods	
  should	
  be	
  small                                       Refactoring
  public void generateAggregateReportFor(final List<StoryTestResults> storyResults,
                                         final List<FeatureResults> featureResults) throws IOException {
      LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory());

       copyResourcesToOutputDirectory();

      private void Object> storyContext = new HashMap<String, Object>(); storyResults) throws IOException {
        Map<String, generateStoriesReport(final List<StoryTestResults>
        storyContext.put("stories", storyResults);
           Map<String, Object> context = new HashMap<String, Object>();
        storyContext.put("storyContext", "All stories");
           context.put("stories", storyResults);
        addFormattersToContext(storyContext); stories");
           context.put("storyContext", "All
        writeReportToOutputDirectory("stories.html",
           addFormattersToContext(context);
                                     mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(storyContext));
           String htmlContents = mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(context);
           writeReportToOutputDirectory("stories.html", htmlContents);
        Map<String, Object> featureContext = new HashMap<String, Object>();
      }
       addFormattersToContext(featureContext);
       featureContext.put("features", featureResults);                Refactor into clear steps
       writeReportToOutputDirectory("features.html",
                                    mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext));

       for(FeatureResults feature : featureResults) {
           generateStoryReportForFeature(feature);
       }

       generateReportHomePage(storyResults, featureResults);

       getTestHistory().updateData(featureResults);

       generateHistoryReport();
  }
High-Level
Methods	
  should	
  be	
  small                                     Refactoring
  public void generateAggregateReportFor(final List<StoryTestResults> storyResults,
                                         final List<FeatureResults> featureResults) throws IOException {
      LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory());

      copyResourcesToOutputDirectory();

      generateStoriesReportFor(storyResults);

      Map<String, Object> featureContext = new HashMap<String, Object>();
      addFormattersToContext(featureContext);
      featureContext.put("features", featureResults);
      writeReportToOutputDirectory("features.html",
                                   mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext));

      for(FeatureResults feature : featureResults) {
          generateStoryReportForFeature(feature);
      }

      generateReportHomePage(storyResults, featureResults);

      getTestHistory().updateData(featureResults);

                   private void updateHistoryFor(final List<FeatureResults> featureResults) {
      generateHistoryReport();
  }                     getTestHistory().updateData(featureResults);
                   }
High-Level
Methods	
  should	
  be	
  small                         Refactoring

private void generateAggregateReportFor(final List<StoryTestResults> storyResults,
                                        final List<FeatureResults> featureResults)
    throws IOException {

        copyResourcesToOutputDirectory();

        generateStoriesReportFor(storyResults);
        generateFeatureReportFor(featureResults);
        generateReportHomePage(storyResults, featureResults);

        updateHistoryFor(featureResults);
        generateHistoryReport();
}
High-Level Refactoring
   Methods	
  should	
  only	
  do	
  one	
  thing

                                                                    Too much going on here...
public String getReportName(String reportType, final String qualifier) {
    if (qualifier == null) {
        String testName = "";
        if (getUserStory() != null) {
             testName = NameConverter.underscore(getUserStory().getName());
        }
        String scenarioName = NameConverter.underscore(getMethodName());
        testName = withNoIssueNumbers(withNoArguments(appendToIfNotNull(testName, scenarioName)));
        return testName + "." + reportType;
    } else {
        String userStory = "";
        if (getUserStory() != null) {
             userStory = NameConverter.underscore(getUserStory().getName()) + "_";
        }
        String normalizedQualifier = qualifier.replaceAll(" ", "_");
        return userStory + withNoArguments(getMethodName()) + "_" + normalizedQualifier + "." + reportType;
    }
}
                                                                    Mixing what and how
High-Level Refactoring
    Methods	
  should	
  only	
  do	
  one	
  thing

                                                               Chose what to do here
public String getReportName(final ReportType type, final String qualifier) {
    ReportNamer reportNamer = ReportNamer.forReportType(type);
    if (shouldAddQualifier(qualifier)) {
        return reportNamer.getQualifiedTestNameFor(this, qualifier);
    } else {
        return reportNamer.getNormalizedTestNameFor(this);
    }
}



                                     The how is the responsibility of another class
Encapsulate	
  boolean	
  expressions
for (TestStep currentStep : testSteps) {
    if (!currentStep.isAGroup() && currentStep.getScreenshots() != null) {
        for (RecordedScreenshot screenshot : currentStep.getScreenshots()) {
            screenshots.add(new Screenshot(screenshot.getScreenshot().getName(),
                    currentStep.getDescription(),
                    widthOf(screenshot.getScreenshot()),
                    currentStep.getException()));
        }
    }
}



                                                 What does this boolean mean?

for (TestStep currentStep : testSteps) {
    if (currentStep.needsScreenshots()) {
        ...
              public boolean needsScreenshots() {
                  return (!isAGroup() && getScreenshotsAndHtmlSources() != null);
              }




                                                   Expresses the intent better
Avoid	
  unclear/ambiguous	
  class	
  name
         for (TestStep currentStep : testSteps) {
             if (currentStep.needsScreenshots()) {
                 for (RecordedScreenshot screenshot : currentStep.getScreenshots()) {
                     screenshots.add(new Screenshot(screenshot.getScreenshot().getName(),
                             currentStep.getDescription(),
                             widthOf(screenshot.getScreenshot()),
                             currentStep.getException()));
                 }
             }
         }
                                                     Is this class name really accurate?

 public List<Screenshot> getScreenshots() {                           Too many screenshots!
     List<Screenshot> screenshots = new ArrayList<Screenshot>();
     List<TestStep> testSteps = getFlattenedTestSteps();

     for (TestStep currentStep : testSteps) {
         if (weNeedAScreenshotFor(currentStep)) {
             for (ScreenshotAndHtmlSource screenshotAndHtml : currentStep.getScreenshotsAndHtmlSources()) {
                 screenshots.add(new Screenshot(screenshotAndHtml.getScreenshotFile().getName(),
                         currentStep.getDescription(),
                         widthOf(screenshotAndHtml.getScreenshot()),
                         currentStep.getException()));
             }
         }
     }
     return ImmutableList.copyOf(screenshots);
Using a more revealing class name
 }
                                                              And a clearer method name
Encapsulate	
  overly-­‐complex	
  code

public List<Screenshot> getScreenshots() {
    List<Screenshot> screenshots = new ArrayList<Screenshot>();
    List<TestStep> testSteps = getFlattenedTestSteps();

    for (TestStep currentStep : testSteps) {
        if (currentStep.needsScreenshots()) {
            for (ScreenshotAndHtmlSource screenshotAndHtml : currentStep.getScreenshotsAndHtmlSources()) {
                screenshots.add(new Screenshot(screenshotAndHtml.getScreenshot().getName(),
                        currentStep.getDescription(),
                        widthOf(screenshotAndHtml.getScreenshot()),
                        currentStep.getException()));
            }
        }
    }
    return ImmutableList.copyOf(screenshots);
                                                 What does all this do?
}
      public List<Screenshot> getScreenshots() {
          List<Screenshot> screenshots = new ArrayList<Screenshot>();
          List<TestStep> testSteps = getFlattenedTestSteps();

          for (TestStep currentStep : testSteps) {
              if (weNeedAScreenshotFor(currentStep)) {
                  screenshots.addAll(
                      convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep)));
              }
          }

      }
          return ImmutableList.copyOf(screenshots);                          Clearer intention
Encapsulate	
  overly-­‐complex	
  code

public List<Screenshot> getScreenshots() {
    List<Screenshot> screenshots = new ArrayList<Screenshot>();
    List<TestStep> testSteps = getFlattenedTestSteps();

      for (TestStep currentStep : testSteps) {
          if (currentStep.needsScreenshots()) {
              screenshots.addAll(
                  convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep)));
          }
      }
      return ImmutableList.copyOf(screenshots);        What we are doing
}
    private Converter<ScreenshotAndHtmlSource, Screenshot> toScreenshotsFor(final TestStep currentStep) {
        return new Converter<ScreenshotAndHtmlSource, Screenshot>() {
            @Override
            public Screenshot convert(ScreenshotAndHtmlSource from) {
                return new Screenshot(from.getScreenshotFile().getName(),
                                      currentStep.getDescription(),
                                      widthOf(from.getScreenshotFile()),
                                      currentStep.getException());
            }
        };
    }

                                                                               How we do it
Avoid	
  deep	
  nes;ng

public List<Screenshot> getScreenshots() {
    List<Screenshot> screenshots = new ArrayList<Screenshot>();
    List<TestStep> testSteps = getFlattenedTestSteps();

        for (TestStep currentStep : testSteps) {
            if (currentStep.needsScreenshots()) {
                                                               Code doing too many things
                screenshots.addAll(
                    convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep)));
            }
        }
        return ImmutableList.copyOf(screenshots);
}                                                                 Break the code down into
    public List<Screenshot> getScreenshots() {                    logical steps
        List<Screenshot> screenshots = new ArrayList<Screenshot>();

         List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(),
                                                          having(on(TestStep.class).needsScreenshots()));

         for (TestStep currentStep : testStepsWithScreenshots) {
             screenshots.addAll(convert(currentStep.getScreenshotsAndHtmlSources(),
                                        toScreenshotsFor(currentStep)));
         }

         return ImmutableList.copyOf(screenshots);
    }                                                     Remove the nested condition
Keep	
  each	
  step	
  simple!
public List<Screenshot> getScreenshots() {
    List<Screenshot> screenshots = new ArrayList<Screenshot>();

        List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(),
                                                         having(on(TestStep.class).needsScreenshots()));

        for (TestStep currentStep : testStepsWithScreenshots) {
            screenshots.addAll(convert(currentStep.getScreenshotsAndHtmlSources(),
                                       toScreenshotsFor(currentStep)));
        }

        return ImmutableList.copyOf(screenshots);           Too much happening here?
}

    public List<Screenshot> getScreenshots() {
        List<Screenshot> screenshots = new ArrayList<Screenshot>();

          List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(),
                                                           having(on(TestStep.class).needsScreenshots()));

          for (TestStep currentStep : testStepsWithScreenshots) {
              screenshots.addAll(screenshotsIn(currentStep));
          }

          return ImmutableList.copyOf(screenshots);       This reads more smoothly
    }

    private List<Screenshot> screenshotsIn(TestStep currentStep) {
        return convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep));
    }
Code	
  should	
  communicate	
  fluently
Use	
  Fluent	
  APIs


               Complex domain object
                             Lots of variants
                                  Object tree



       FundsTransferOrder order = new FundsTransferOrder();
       order.setType("SWIFT");
       Party originatorParty = organizationServer.findPartyByCode("WPAC");
       order.setOriginatorParty(originatorParty);
       Party counterParty = organizationServer.findPartyByCode("CBAA");
       order.setCounterParty(counterParty);
       order.setDate(DateTime.parse("22/11/2011"));
       Currency currency = currencyTable.findCurrency("USD");
       Amount amount = new Amount(500, currency);
       order.setAmount(amount);
Complex code
       ...


  Need to know how to create the child objects
Use	
  Fluent	
  APIs




                                           More readable
                                               No object creation
                                                   Easier to maintain
FundsTransferOrder.createNewSWIFTOrder()
                                  .fromOriginatorParty("WPAC")
                                  .toCounterParty("CBAA")
                                  .forDebitor("WPAC")
                                  .and().forCreditor("CBAA")
                                  .settledOnThe("22/11/2011")
                                  .forAnAmountOf(500, US_DOLLARS)
                                  .asXML();
Use	
  Fluent	
  APIs


                                         Readable parameter style


TestStatistics testStatistics = testStatisticsProvider.statisticsForTests(With.tag("Boat sales"));

double recentBoatSalePassRate = testStatistics.getPassRate().overTheLast(5).testRuns();




                   Fluent method call
Use	
  Fluent	
  APIs
                             Fluent style...


                        A builder does the
                            dirty work

                           Represents how
                            to select steps

                                Override to
                               select different
                                 step types
Your	
  code	
  is	
  organic




     Help	
  it	
  grow
Replace	
  Constructors	
  with	
  Crea7on	
  Methods




                             Too many constructors
                                Business knowledge
                                hidden in the constructors
                                  Which one should I use?
Replace	
  Constructors	
  with	
  Crea7on	
  Methods




                                   Private constructor




        Static creator methods
          One implementing class
Replace	
  Constructors	
  with	
  Crea7on	
  Methods




                  Communicates	
  the	
  intended	
  use	
  be5er
                  Overcomes	
  technical	
  limits	
  with	
  constructors
                  Inconsistent	
  object	
  crea<on	
  pa5erns
Encapsulate	
  Classes	
  with	
  a	
  Factory
                     High-Level Refactoring
                                           Only this interface should
                                           be visible




Many different
implementations
                          Which implementation
                          should I use?
Encapsulate	
  Classes	
  with	
  a	
  Factory
                                 High-Level Refactoring
                             Helpful factory methods




Easier	
  to	
  create	
  the	
  right	
  instances
Hides	
  classes	
  that	
  don’t	
  need	
  to	
  be	
  exposed
Encourages	
  “programming	
  to	
  an	
  interface”
Need	
  a	
  new	
  method	
  when	
  new	
  classes	
  are	
  added
Need	
  access	
  to	
  factory	
  class	
  to	
  customize/extend
Plenty	
  of	
  other	
  refactoring	
  pa2erns...




                    But	
  know	
  why	
  you	
  are	
  applying	
  them
Learn	
  about	
  Func7onal	
  Programming!
Func;ons	
  as	
  a	
  1st	
  class	
  concept
Immutable	
  value	
  objects
No	
  side	
  effects
Benefit	
  from	
  concurrency
No	
  loops
5050



          A, B, C, D, F



          Parallel processing




       TRUE
Functional programming in Java?




Surely this is
 madness!
lambdaj
– DSL for manipulating collections in a functional style
– Replace loops with more concise and readable code




Functional constructs in Java
LambdaJ support many high level
collection-related functions


 filter                   aggregate


      sort
                       convert


extract        index             group
Find all adult ages                                    filter

            List<Integer> adultAges = new ArrayList<Integer>();
            for(int age : ages) {
                if (age >= 18) {
                    adults.add(age);
                }
            }




List<Integer> adultAges = filter(greaterThanOrEqualTo(18), ages);
Find all adults                                           filter

                List<Person> adults = new ArrayList<Person>();
                for(int person : people) {
                    if (person.getAge() >= 18) {
                        adults.add(person);
                    }
                }




List<Person> adults = filter(having(on(Person.class).getAge(), greaterThanOrEqualTo(18)),
                             people);
Find all the sales of Ferraris                                filter

            List<Sale> salesOfAFerrari = new ArrayList<Sale>();
            for (Sale sale : sales) {
                if (sale.getCar().getBrand().equals("Ferrari"))
                    salesOfAFerrari.add(sale);
            }




List<Sale> salesOfAFerrari = select(sales,
    having(on(Sale.class).getCar().getBrand(),equalTo("Ferrari")));
Sort sales by cost                                       sort

     List<Sale> sortedSales = new ArrayList<Sale>(sales);
     Collections.sort(sortedSales, new Comparator<Sale>() {
         public int compare(Sale s1, Sale s2) {
             return Double.valueOf(s1.getCost()).compareTo(s2.getCost());
         }
     });




List<Sale> sortedSales = sort(sales, on(Sale.class).getCost());
Index cars by brand                                   index


       Map<String, Car> carsByBrand = new HashMap<String, Car>();
       for (Car car : db.getCars()) {
           carsByBrand.put(car.getBrand(), car);
       }




Map<String, Car> carsByBrand = index(cars, on(Car.class).getBrand());
Find the total sales
                                                  aggregate

  double totalSales = 0.0;
  for (Sale sale : sales) {
      totalSales = totalSales + sale.getCost();
  }




      double totalSales = sumFrom(sales).getCost();
Find most costly sale
                                             aggregate

   double maxCost = 0.0;
   for (Sale sale : sales) {
       double cost = sale.getCost();
       if (cost > maxCost) maxCost = cost;
   }




          double maxCost = maxFrom(sales).getCost();
extract
Extract the costs of the cars as a list




      List<Double> costs = new ArrayList<Double>();
      for (Car car : cars) costs.add(car.getCost());




  List<Double> costs = extract(cars, on(Car.class).getCost());
guava immutable collections
guava immutable collections
   Defensive
   Thread-safe
   Efficient
Creating an immutable list

List<String> colors = ImmutableList.of("red", "green", "blue");




  ImmutableSet<Field> fields =
                     ImmutableSet.copyOf(stepLibraryClass.getDeclaredFields());



                                             Creating an immutable copy
The	
  Boy	
  Scout	
  Rule




   “Leave	
  the	
  camp	
  ground	
  cleaner	
  than	
  you	
  found	
  it”
Clean Coding Practices for Java Developers




                Thank You



                                    John	
  Ferguson	
  Smart
                             john.smart@wakaleo.com
                             	
  h2p://www.wakaleo.com
                                        Twi2er:	
  wakaleo

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Clean code
Clean codeClean code
Clean code
 
Clean Code
Clean CodeClean Code
Clean Code
 
Clean Code
Clean CodeClean Code
Clean Code
 
Clean code
Clean code Clean code
Clean code
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Clean code
Clean codeClean code
Clean code
 
Clean Code
Clean CodeClean Code
Clean Code
 
Clean Code
Clean CodeClean Code
Clean Code
 
Clean Code Principles
Clean Code PrinciplesClean Code Principles
Clean Code Principles
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable code
 
Clean code and code smells
Clean code and code smellsClean code and code smells
Clean code and code smells
 
Gitflow - Branching and Merging Flow for Git
Gitflow - Branching and Merging Flow for GitGitflow - Branching and Merging Flow for Git
Gitflow - Branching and Merging Flow for Git
 
Clean code presentation
Clean code presentationClean code presentation
Clean code presentation
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Deep drive into rust programming language
Deep drive into rust programming languageDeep drive into rust programming language
Deep drive into rust programming language
 
Clean Code
Clean CodeClean Code
Clean Code
 
Whitebox testing of Spring Boot applications
Whitebox testing of Spring Boot applicationsWhitebox testing of Spring Boot applications
Whitebox testing of Spring Boot applications
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 

Ähnlich wie Clean coding-practices

Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo Ali Parmaksiz
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven DevelopmentAgileOnTheBeach
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
Advance Java Programs skeleton
Advance Java Programs skeletonAdvance Java Programs skeleton
Advance Java Programs skeletonIram Ramrajkar
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good TestsTomek Kaczanowski
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Paco de la Cruz
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Jason Lotito
 
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Binary patching for fun and profit @ JUG.ru, 25.02.2012Binary patching for fun and profit @ JUG.ru, 25.02.2012
Binary patching for fun and profit @ JUG.ru, 25.02.2012Anton Arhipov
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!DataArt
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interfaceJoakim Gustin
 

Ähnlich wie Clean coding-practices (20)

JavaZone 2014 - goto java;
JavaZone 2014 - goto java;JavaZone 2014 - goto java;
JavaZone 2014 - goto java;
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Rx workshop
Rx workshopRx workshop
Rx workshop
 
Advance Java Programs skeleton
Advance Java Programs skeletonAdvance Java Programs skeleton
Advance Java Programs skeleton
 
#JavaFX.forReal() - ElsassJUG
#JavaFX.forReal() - ElsassJUG#JavaFX.forReal() - ElsassJUG
#JavaFX.forReal() - ElsassJUG
 
2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Jersey Guice AOP
Jersey Guice AOPJersey Guice AOP
Jersey Guice AOP
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Binary patching for fun and profit @ JUG.ru, 25.02.2012Binary patching for fun and profit @ JUG.ru, 25.02.2012
Binary patching for fun and profit @ JUG.ru, 25.02.2012
 
Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
Net/http and the http.handler interface
Net/http and the http.handler interfaceNet/http and the http.handler interface
Net/http and the http.handler interface
 

Mehr von John Ferguson Smart Limited

My Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosMy Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosJohn Ferguson Smart Limited
 
Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...John Ferguson Smart Limited
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceJohn Ferguson Smart Limited
 
Sustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplaySustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplayJohn Ferguson Smart Limited
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceJohn Ferguson Smart Limited
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Screenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingScreenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingJohn Ferguson Smart Limited
 
All the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesAll the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesJohn Ferguson Smart Limited
 
It's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersIt's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersJohn Ferguson Smart Limited
 

Mehr von John Ferguson Smart Limited (20)

My Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosMy Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin Scenarios
 
Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a difference
 
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANTBE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
 
Sustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplaySustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and Screenplay
 
Feature Mapping Workshop
Feature Mapping WorkshopFeature Mapping Workshop
Feature Mapping Workshop
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a difference
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Shift left-devoxx-pl
Shift left-devoxx-plShift left-devoxx-pl
Shift left-devoxx-pl
 
Screenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingScreenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testing
 
Cucumber and Spock Primer
Cucumber and Spock PrimerCucumber and Spock Primer
Cucumber and Spock Primer
 
All the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesAll the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practices
 
CukeUp 2016 Agile Product Planning Workshop
CukeUp 2016 Agile Product Planning WorkshopCukeUp 2016 Agile Product Planning Workshop
CukeUp 2016 Agile Product Planning Workshop
 
BDD Anti-patterns
BDD Anti-patternsBDD Anti-patterns
BDD Anti-patterns
 
Serenity and the Journey Pattern
Serenity and the Journey PatternSerenity and the Journey Pattern
Serenity and the Journey Pattern
 
BDD - Collaborate like you mean it!
BDD - Collaborate like you mean it!BDD - Collaborate like you mean it!
BDD - Collaborate like you mean it!
 
BDD-Driven Microservices
BDD-Driven MicroservicesBDD-Driven Microservices
BDD-Driven Microservices
 
BDD Anti-patterns
BDD Anti-patternsBDD Anti-patterns
BDD Anti-patterns
 
It's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersIt's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for Testers
 

Kürzlich hochgeladen

How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?IES VE
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfJamie (Taka) Wang
 
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
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioChristian Posta
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostKubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostMatt Ray
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Adtran
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopBachir Benyammi
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationIES VE
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAshyamraj55
 
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
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URLRuncy Oommen
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
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 AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxUdaiappa Ramachandran
 

Kürzlich hochgeladen (20)

How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?
 
Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
 
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
 
Comparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and IstioComparing Sidecar-less Service Mesh from Cilium and Istio
Comparing Sidecar-less Service Mesh from Cilium and Istio
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCostKubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
KubeConEU24-Monitoring Kubernetes and Cloud Spend with OpenCost
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 Workshop
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
 
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
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
Designing A Time bound resource download URL
Designing A Time bound resource download URLDesigning A Time bound resource download URL
Designing A Time bound resource download URL
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
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 AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptx
 

Clean coding-practices

  • 1. Clean Coding Practices for Java Developers Clean Coding Practices for Java Developers John  Ferguson  Smart john.smart@wakaleo.com  h2p://www.wakaleo.com Twi2er:  wakaleo
  • 2. So who is this guy, anyway? Consulta nt Trainer Mentor Author Speaker Coder John Fer guson S mar t
  • 3. Who  are  you  wri;ng  code  for,  anyway?
  • 4. Who  are  you  wri;ng  code  for,  anyway? The  computer?
  • 5. Who  are  you  wri;ng  code  for,  anyway? Other  developers?
  • 6. Who  are  you  wri;ng  code  for,  anyway? Your  next  boss?
  • 7. Clean Coding Practices for Java Developers Why  is  clean  code  so  important?
  • 8. Easier  to  Understand Easier  to  Change Cheaper  to  Maintain
  • 9. Choose  your  names  well "What's in a name? That which we call a rose By any other name would smell as sweet." Romeo and Juliet (II, ii, 1-2) Really?
  • 10. Use  a  common  vocabulary getCustomerInfo() getClientDetails() getCustomerRecord() ... Which one do I use? Are they the same? getCustomer() Choose one and stick to it
  • 11. Use  meaningful  names int days; What does this represent? int daysSinceCreation; int daysSinceLastModification; int durationInDays; These are all more meaningful choices
  • 12. Don’t  talk  in  code class DtaRcrd102 { private Date genymdhms; private Date modymdhms; private final String pszqint = “102”; ... } Huh? class Customer { private Date generationTimestamp; private Date modificationTimestamp; private final String recordId = “102” ... }
  • 13. But  don’t  state  the  obvious List<Client> clientList; Is ‘List’ significant or just noise? List<Client> clients; List<Client> regularClients; List<Client> newClients;
  • 14. In  short:  Don’t  make  me  think! What does this do? Clearer parameter name More explicit method name What are we counting? Method call rather than boolean expression
  • 15. Make  your  code  tell  a  story
  • 16. High-Level Methods  should  be  small Refactoring public void generateAggregateReportFor(final List<StoryTestResults> storyResults, final List<FeatureResults> featureResults) throws IOException { LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory()); copyResourcesToOutputDirectory(); Map<String, Object> storyContext = new HashMap<String, Object>(); storyContext.put("stories", storyResults); storyContext.put("storyContext", "All stories"); addFormattersToContext(storyContext); writeReportToOutputDirectory("stories.html", mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(storyContext)); Map<String, Object> featureContext = new HashMap<String, Object>(); addFormattersToContext(featureContext); featureContext.put("features", featureResults); writeReportToOutputDirectory("features.html", mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext)); for(FeatureResults feature : featureResults) { generateStoryReportForFeature(feature); } generateReportHomePage(storyResults, featureResults); Code hard to understand getTestHistory().updateData(featureResults); generateHistoryReport(); }
  • 17. High-Level Methods  should  be  small Refactoring public void generateAggregateReportFor(final List<StoryTestResults> storyResults, final List<FeatureResults> featureResults) throws IOException { LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory()); copyResourcesToOutputDirectory(); private void Object> storyContext = new HashMap<String, Object>(); storyResults) throws IOException { Map<String, generateStoriesReport(final List<StoryTestResults> storyContext.put("stories", storyResults); Map<String, Object> context = new HashMap<String, Object>(); storyContext.put("storyContext", "All stories"); context.put("stories", storyResults); addFormattersToContext(storyContext); stories"); context.put("storyContext", "All writeReportToOutputDirectory("stories.html", addFormattersToContext(context); mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(storyContext)); String htmlContents = mergeTemplate(STORIES_TEMPLATE_PATH).usingContext(context); writeReportToOutputDirectory("stories.html", htmlContents); Map<String, Object> featureContext = new HashMap<String, Object>(); } addFormattersToContext(featureContext); featureContext.put("features", featureResults); Refactor into clear steps writeReportToOutputDirectory("features.html", mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext)); for(FeatureResults feature : featureResults) { generateStoryReportForFeature(feature); } generateReportHomePage(storyResults, featureResults); getTestHistory().updateData(featureResults); generateHistoryReport(); }
  • 18. High-Level Methods  should  be  small Refactoring public void generateAggregateReportFor(final List<StoryTestResults> storyResults, final List<FeatureResults> featureResults) throws IOException { LOGGER.info("Generating summary report for user stories to "+ getOutputDirectory()); copyResourcesToOutputDirectory(); generateStoriesReportFor(storyResults); Map<String, Object> featureContext = new HashMap<String, Object>(); addFormattersToContext(featureContext); featureContext.put("features", featureResults); writeReportToOutputDirectory("features.html", mergeTemplate(FEATURES_TEMPLATE_PATH).usingContext(featureContext)); for(FeatureResults feature : featureResults) { generateStoryReportForFeature(feature); } generateReportHomePage(storyResults, featureResults); getTestHistory().updateData(featureResults); private void updateHistoryFor(final List<FeatureResults> featureResults) { generateHistoryReport(); } getTestHistory().updateData(featureResults); }
  • 19. High-Level Methods  should  be  small Refactoring private void generateAggregateReportFor(final List<StoryTestResults> storyResults, final List<FeatureResults> featureResults) throws IOException { copyResourcesToOutputDirectory(); generateStoriesReportFor(storyResults); generateFeatureReportFor(featureResults); generateReportHomePage(storyResults, featureResults); updateHistoryFor(featureResults); generateHistoryReport(); }
  • 20. High-Level Refactoring Methods  should  only  do  one  thing Too much going on here... public String getReportName(String reportType, final String qualifier) { if (qualifier == null) { String testName = ""; if (getUserStory() != null) { testName = NameConverter.underscore(getUserStory().getName()); } String scenarioName = NameConverter.underscore(getMethodName()); testName = withNoIssueNumbers(withNoArguments(appendToIfNotNull(testName, scenarioName))); return testName + "." + reportType; } else { String userStory = ""; if (getUserStory() != null) { userStory = NameConverter.underscore(getUserStory().getName()) + "_"; } String normalizedQualifier = qualifier.replaceAll(" ", "_"); return userStory + withNoArguments(getMethodName()) + "_" + normalizedQualifier + "." + reportType; } } Mixing what and how
  • 21. High-Level Refactoring Methods  should  only  do  one  thing Chose what to do here public String getReportName(final ReportType type, final String qualifier) { ReportNamer reportNamer = ReportNamer.forReportType(type); if (shouldAddQualifier(qualifier)) { return reportNamer.getQualifiedTestNameFor(this, qualifier); } else { return reportNamer.getNormalizedTestNameFor(this); } } The how is the responsibility of another class
  • 22. Encapsulate  boolean  expressions for (TestStep currentStep : testSteps) { if (!currentStep.isAGroup() && currentStep.getScreenshots() != null) { for (RecordedScreenshot screenshot : currentStep.getScreenshots()) { screenshots.add(new Screenshot(screenshot.getScreenshot().getName(), currentStep.getDescription(), widthOf(screenshot.getScreenshot()), currentStep.getException())); } } } What does this boolean mean? for (TestStep currentStep : testSteps) { if (currentStep.needsScreenshots()) { ... public boolean needsScreenshots() { return (!isAGroup() && getScreenshotsAndHtmlSources() != null); } Expresses the intent better
  • 23. Avoid  unclear/ambiguous  class  name for (TestStep currentStep : testSteps) { if (currentStep.needsScreenshots()) { for (RecordedScreenshot screenshot : currentStep.getScreenshots()) { screenshots.add(new Screenshot(screenshot.getScreenshot().getName(), currentStep.getDescription(), widthOf(screenshot.getScreenshot()), currentStep.getException())); } } } Is this class name really accurate? public List<Screenshot> getScreenshots() { Too many screenshots! List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testSteps = getFlattenedTestSteps(); for (TestStep currentStep : testSteps) { if (weNeedAScreenshotFor(currentStep)) { for (ScreenshotAndHtmlSource screenshotAndHtml : currentStep.getScreenshotsAndHtmlSources()) { screenshots.add(new Screenshot(screenshotAndHtml.getScreenshotFile().getName(), currentStep.getDescription(), widthOf(screenshotAndHtml.getScreenshot()), currentStep.getException())); } } } return ImmutableList.copyOf(screenshots); Using a more revealing class name } And a clearer method name
  • 24. Encapsulate  overly-­‐complex  code public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testSteps = getFlattenedTestSteps(); for (TestStep currentStep : testSteps) { if (currentStep.needsScreenshots()) { for (ScreenshotAndHtmlSource screenshotAndHtml : currentStep.getScreenshotsAndHtmlSources()) { screenshots.add(new Screenshot(screenshotAndHtml.getScreenshot().getName(), currentStep.getDescription(), widthOf(screenshotAndHtml.getScreenshot()), currentStep.getException())); } } } return ImmutableList.copyOf(screenshots); What does all this do? } public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testSteps = getFlattenedTestSteps(); for (TestStep currentStep : testSteps) { if (weNeedAScreenshotFor(currentStep)) { screenshots.addAll( convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep))); } } } return ImmutableList.copyOf(screenshots); Clearer intention
  • 25. Encapsulate  overly-­‐complex  code public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testSteps = getFlattenedTestSteps(); for (TestStep currentStep : testSteps) { if (currentStep.needsScreenshots()) { screenshots.addAll( convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep))); } } return ImmutableList.copyOf(screenshots); What we are doing } private Converter<ScreenshotAndHtmlSource, Screenshot> toScreenshotsFor(final TestStep currentStep) { return new Converter<ScreenshotAndHtmlSource, Screenshot>() { @Override public Screenshot convert(ScreenshotAndHtmlSource from) { return new Screenshot(from.getScreenshotFile().getName(), currentStep.getDescription(), widthOf(from.getScreenshotFile()), currentStep.getException()); } }; } How we do it
  • 26. Avoid  deep  nes;ng public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testSteps = getFlattenedTestSteps(); for (TestStep currentStep : testSteps) { if (currentStep.needsScreenshots()) { Code doing too many things screenshots.addAll( convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep))); } } return ImmutableList.copyOf(screenshots); } Break the code down into public List<Screenshot> getScreenshots() { logical steps List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(), having(on(TestStep.class).needsScreenshots())); for (TestStep currentStep : testStepsWithScreenshots) { screenshots.addAll(convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep))); } return ImmutableList.copyOf(screenshots); } Remove the nested condition
  • 27. Keep  each  step  simple! public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(), having(on(TestStep.class).needsScreenshots())); for (TestStep currentStep : testStepsWithScreenshots) { screenshots.addAll(convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep))); } return ImmutableList.copyOf(screenshots); Too much happening here? } public List<Screenshot> getScreenshots() { List<Screenshot> screenshots = new ArrayList<Screenshot>(); List<TestStep> testStepsWithScreenshots = select(getFlattenedTestSteps(), having(on(TestStep.class).needsScreenshots())); for (TestStep currentStep : testStepsWithScreenshots) { screenshots.addAll(screenshotsIn(currentStep)); } return ImmutableList.copyOf(screenshots); This reads more smoothly } private List<Screenshot> screenshotsIn(TestStep currentStep) { return convert(currentStep.getScreenshotsAndHtmlSources(), toScreenshotsFor(currentStep)); }
  • 29. Use  Fluent  APIs Complex domain object Lots of variants Object tree FundsTransferOrder order = new FundsTransferOrder(); order.setType("SWIFT"); Party originatorParty = organizationServer.findPartyByCode("WPAC"); order.setOriginatorParty(originatorParty); Party counterParty = organizationServer.findPartyByCode("CBAA"); order.setCounterParty(counterParty); order.setDate(DateTime.parse("22/11/2011")); Currency currency = currencyTable.findCurrency("USD"); Amount amount = new Amount(500, currency); order.setAmount(amount); Complex code ... Need to know how to create the child objects
  • 30. Use  Fluent  APIs More readable No object creation Easier to maintain FundsTransferOrder.createNewSWIFTOrder() .fromOriginatorParty("WPAC") .toCounterParty("CBAA") .forDebitor("WPAC") .and().forCreditor("CBAA") .settledOnThe("22/11/2011") .forAnAmountOf(500, US_DOLLARS) .asXML();
  • 31. Use  Fluent  APIs Readable parameter style TestStatistics testStatistics = testStatisticsProvider.statisticsForTests(With.tag("Boat sales")); double recentBoatSalePassRate = testStatistics.getPassRate().overTheLast(5).testRuns(); Fluent method call
  • 32. Use  Fluent  APIs Fluent style... A builder does the dirty work Represents how to select steps Override to select different step types
  • 33. Your  code  is  organic Help  it  grow
  • 34. Replace  Constructors  with  Crea7on  Methods Too many constructors Business knowledge hidden in the constructors Which one should I use?
  • 35. Replace  Constructors  with  Crea7on  Methods Private constructor Static creator methods One implementing class
  • 36. Replace  Constructors  with  Crea7on  Methods Communicates  the  intended  use  be5er Overcomes  technical  limits  with  constructors Inconsistent  object  crea<on  pa5erns
  • 37. Encapsulate  Classes  with  a  Factory High-Level Refactoring Only this interface should be visible Many different implementations Which implementation should I use?
  • 38. Encapsulate  Classes  with  a  Factory High-Level Refactoring Helpful factory methods Easier  to  create  the  right  instances Hides  classes  that  don’t  need  to  be  exposed Encourages  “programming  to  an  interface” Need  a  new  method  when  new  classes  are  added Need  access  to  factory  class  to  customize/extend
  • 39. Plenty  of  other  refactoring  pa2erns... But  know  why  you  are  applying  them
  • 40. Learn  about  Func7onal  Programming!
  • 41. Func;ons  as  a  1st  class  concept
  • 46. 5050 A, B, C, D, F Parallel processing TRUE
  • 47. Functional programming in Java? Surely this is madness!
  • 48. lambdaj – DSL for manipulating collections in a functional style – Replace loops with more concise and readable code Functional constructs in Java
  • 49. LambdaJ support many high level collection-related functions filter aggregate sort convert extract index group
  • 50. Find all adult ages filter List<Integer> adultAges = new ArrayList<Integer>(); for(int age : ages) { if (age >= 18) { adults.add(age); } } List<Integer> adultAges = filter(greaterThanOrEqualTo(18), ages);
  • 51. Find all adults filter List<Person> adults = new ArrayList<Person>(); for(int person : people) { if (person.getAge() >= 18) { adults.add(person); } } List<Person> adults = filter(having(on(Person.class).getAge(), greaterThanOrEqualTo(18)), people);
  • 52. Find all the sales of Ferraris filter List<Sale> salesOfAFerrari = new ArrayList<Sale>(); for (Sale sale : sales) {     if (sale.getCar().getBrand().equals("Ferrari"))         salesOfAFerrari.add(sale); } List<Sale> salesOfAFerrari = select(sales, having(on(Sale.class).getCar().getBrand(),equalTo("Ferrari")));
  • 53. Sort sales by cost sort List<Sale> sortedSales = new ArrayList<Sale>(sales); Collections.sort(sortedSales, new Comparator<Sale>() {     public int compare(Sale s1, Sale s2) {         return Double.valueOf(s1.getCost()).compareTo(s2.getCost());     } }); List<Sale> sortedSales = sort(sales, on(Sale.class).getCost());
  • 54. Index cars by brand index Map<String, Car> carsByBrand = new HashMap<String, Car>(); for (Car car : db.getCars()) {     carsByBrand.put(car.getBrand(), car); } Map<String, Car> carsByBrand = index(cars, on(Car.class).getBrand());
  • 55. Find the total sales aggregate double totalSales = 0.0; for (Sale sale : sales) {     totalSales = totalSales + sale.getCost(); } double totalSales = sumFrom(sales).getCost();
  • 56. Find most costly sale aggregate double maxCost = 0.0; for (Sale sale : sales) {     double cost = sale.getCost();     if (cost > maxCost) maxCost = cost; } double maxCost = maxFrom(sales).getCost();
  • 57. extract Extract the costs of the cars as a list List<Double> costs = new ArrayList<Double>(); for (Car car : cars) costs.add(car.getCost()); List<Double> costs = extract(cars, on(Car.class).getCost());
  • 59. guava immutable collections Defensive Thread-safe Efficient
  • 60. Creating an immutable list List<String> colors = ImmutableList.of("red", "green", "blue"); ImmutableSet<Field> fields = ImmutableSet.copyOf(stepLibraryClass.getDeclaredFields()); Creating an immutable copy
  • 61. The  Boy  Scout  Rule “Leave  the  camp  ground  cleaner  than  you  found  it”
  • 62. Clean Coding Practices for Java Developers Thank You John  Ferguson  Smart john.smart@wakaleo.com  h2p://www.wakaleo.com Twi2er:  wakaleo