際際滷

際際滷Share a Scribd company logo
Clean, effective Java
    Bert Van Vreckem
2
?
    3
(TODO)

         4
5
6
Josh Bloch
             7
Inhoud EJ
                       (2nd Ed, 2008)

   Creatie objecten              Algemene
   Gemeensch. methods             programmeertips
   Klassen en interfaces
                                  Foutafhandeling
   Generieke klassen
                                  Concurrency
   Enums, annotaties
                                  Serialisatie
   Methods
                                  78 items (EJ#nn)

                                                        8
9
Robert 'Uncle Bob' Martin

                            10
Inhoud CC
                        (2009)

   Naamgeving                  Unit tests
   Functies                    Klassen
   Commentaar                  Systemen
   Formattering                Emergent design
   Objecten &                  Iteratieve verfijning
    datastructuren              Refactoring case
   Foutafhandeling             Indicatoren van
   Grenzen                      slechte code            11
Wat is heldere code?




                         12
Doel:
   Disseminatie
   Discussie
   Feedback

PS. Koop de boeken! (vakgroepbib?)




                                     13
Conventies
   Kleurtjes:
       good practice
       bad practice
       nadruk
   Verwijzingen:
       CC5 = Clean Code, hoofdstuk 5
       EJ5 = Effective Java, hoofdstuk 5
       EJ#5 = Effective Java, item 5
                                            14
Onderwerpen
   Klassen
  Functies
  Unit tests
  Ontwerp
     Stijl
               15
Klassen


          16
Klassen
   EJ4 Classes and Interfaces
   CC6 Objects and Data Structures
   CC10 Classes




                                        17
Richtlijnen voor klassen (CC10)
   Klassen moeten klein zijn
       Geen God-klassen (vb. DomainContoller!)
       Single Responsibility Principle: er is maar 1 reden
        om de klasse te wijzigen
       Cohesie: klein aantal instantievariabelen, methods
        manipuleren meerdere instantievariabelen




                                                                18
Beperk mutability (EJ#15)
   Geen mutators
   Laat geen overerving toe
   Alle velden final
   Alle velden private
   Geen toegang tot wijzigbare componenten



                                              19
Voorbeeld: Breuken

public class Fraction {

    public int numerator;
    public int denominator;

}




                              20
Breuken: Bean pattern
public class Fraction {
    private int numerator;
    private int denominator;

    public Fraction(int numerator, int denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
        reduce();
    }

    public int getNumerator() { return numerator; }
    public int getDenominator() { return denominator; }
    public void setNumerator(int numerator) {
        this.numerator = numerator; reduce(); }
    public void setDenominator(int denominator) {
        this.denominator = denominator; reduce(); }
    ...                                                 21
}
Breuken: hulpcode
private void reduce() {
    int gcd = gcd(numerator, denominator);
    numerator /= gcd;
    denominator /= gcd);
}

private static int gcd(int a, int b) {
   if (b==0) return a;
   return gcd(b,a%b);
}

@Override public String toString() {
    return "" + getNumerator() + "/" + getDenominator();
}


                                                           22
Breuken: rekenen
public void add(Fraction that) {
    numerator = this.getNumerator() * that.getDenominator()
              + this.getDenominator() * that.getNumerator();
    denominator = this.getDenominator() * that.getDenominator();
    reduce();
}

public void multiply(Fraction that) {
    numerator = this.getNumerator() * that.getNumerator();
    denominator = this.getDenominator() * that.getDenominator();
    reduce();
}




                                                               23
Onveranderlijke Breuken
public final class Fraction {

    private final int numerator;
    private final int denominator;

    public Fraction(int numerator, int denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
    }

    public int getNumerator() { return numerator; }
    public int getDenominator() { return denominator; }
}


                                                          24
Of misschien zelfs
public final class Fraction {

    public final int numerator;
    public final int denominator;

    public Fraction(int numerator, int denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
    }
}




                                                        25
Terzijde: hetzelfde in Scala ;-)



class Fraction(val numerator: Int, val denominator: Int)




                                                           26
Rekenen met onveranderlijke
            breuken
public Fraction add(Fraction that) {
    return new Fraction(
           this.numerator * that.denominator
             + that.numerator * this.denominator,
           this.denominator * that.denominator);
}

public Fraction multiply(Fraction that) {
    return new Fraction(
           this.numerator * that.numerator,
           this.denominator * that.denominator);
}


                                                    27
Wijzigbare componenten
public class Farm {
    private Field[][] fields;
    public Farm(int width) {
        this.fields = new Field[width][width];
        initFields();
    }
    private void initFields() {  }

      public Field[][] getFields() {
          return fields;
      }
}



    Farm farm = new Farm(4);
    Field[][] fields = farm.getFields();
    fields[2][3] = null; // zou niet mogen!
                                                 28
Wijzigbare componenten
   Geef individuele elementen terug, vb.
     public Field getField(int row, int col) {
         return fields[row][col];
     }

   Maak een defensieve kopie




                                                 29
Let op! (EJ#39)
public final class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        this.start = start;
        this.end = end;
    }

    public Date getStart() { return start; }
    public Date getEnd() { return end; }
}




                                               30
Aanval op interne toestand Period

   Date start = new Date(2012, 06, 01);
   Date end = new Date(2012, 06, 30);
   Period p = new Period(start, end);

   end.setYear(2013);

   // Deze test zal falen!
   assertEquals(2012, p.getEnd().getYear());




                                               31
Defensieve kopie



public Period(Date start, Date end) {
    this.start = new Date(start.getTime());
    this.end = new Date(end.getTime());
}




                                              32
Immutability  voordelen
   Simpel: 辿辿n toestand
   Makkelijker testen
   Altijd thread-safe!
   Kan je hergebruiken
    public static final Fraction ZERO = new Fraction(0,0);
    public static final Fraction ONE = new Fraction(1,1);

   Kopies maken eigenlijk overbodig
   Bouwstenen voor andere objecten
                                                             33
Immutability  nadelen
   Veel objecten aanmaken
       op te lossen, bv. met static factories (zie verder)




                                                              34
Is doorgedreven immutability
     mogelijk / wenselijk?




                                 35
Verkies compositie boven overerving
             (EJ#16)
   Overerving kan
       binnen zelfde package, onder controle van zelfde
        programmeurs
       van specifiek daarvoor ontworpen klassen
       van interfaces
   Overerving vermijden
       van gewone concrete klassen over packages heen


                                                           36
Waarom?
   Overerving breekt encapsulatie
       Subklassen hangen af van implementatie superklasse
   Superklasse wijzigen  problemen in subklassen
       Compilatie
       Verkeerd gedrag
       Beveiligingsproblemen
   Oplossing: wrapper class

                                                             37
Verkies interfaces boven abstracte
              klassen (EJ#18)
   Bestaande klassen kunnen makkelijk aangepast
    worden om nieuwe interface te implementeren
   Interfaces zijn ideaal voor het defini谷ren van
    mixins (vgl. Scala Traits, Ruby Modules)
   Interfaces maken niet-hierarchische
    typeframeworks mogelijk
   Veilige manier om functionaliteit uit te breiden

                                                       38
Niet-hierarchische typeframeworks




                                    39
Nadelen
   Geen implementatie
       voorzie basisimplementatie (skeletal)
       kan jouw klasse niet overerven van basisimpl.?
        simulated multiple inheritance
   Eens een interface gepubliceerd is, kan je niet
    meer wijzigen



                                                         40
Simulated Multiple Inheritance




                                 41
Objecten vs Datastructuren (CC6)
   Objecten
       Verbergen data/implementatie achter abstracties
       Hebben functies om deze data te bewerken
   Datastructuren
       Hebben data
       Hebben geen functies van belang



                                                          42
Vb: 2 implementaties voor vormen
   Datastructuren/procedureel
              public class Square {
                  public Point topLeft;
                  public double side;
              }
              public class Circle {
                  public Point center;
                  public double radius;
              }




                                          43
public class Geometry {
    public double area(Object shape) {
        if (shape instanceof Square) {
            Square s = (Square)shape;
            return s.side * s.side;
        } else if(shape instanceof Circle) {
            Circle c = (Circle) shape;
            return c.radius * c.radius * Math.PI;
        } else {
            throw new IllegalArgumentException(
                "Not a known shape");
        }
    }
}


         Jamaar, da's geen OO!                      44
Vb: 2 implementaties voor vormen
   Objectgeorienteerd
        public interface Shape {
            public double area();
        }

        public class Square implements Shape {
            private Point topLeft;
            private double side;

            @Override public double area() {
                return side * side;
            }
        }
                                                 45
public class Circle implements Shape {
    private Point center;
    private double radius;

    @Override public double area() {
        return Math.PI * radius * radius;
    }
}




                                            46
Twee soorten refactorings
   Functie toevoegen (bv. perimeter())
       Procedureel: enkel Geometry aanpassen
            Shapes en hun clients blijven ongewijzigd!
       OO: ALLE Shapes aanpassen
   Shape toevoegen (bv. Rectangle)
       Procedureel: ALLE functies in Geometry aanpassen
       OO: enkel Rectangle-klasse schrijven


                                                            47
Is de procedurele aanpak uit het vorige voorbeeld
           soms toelaatbaar/aangewezen?




                                                      48
Functies


           49
Functies / methods
   CC3 Functions
   EJ2 Creating and destroying objects
   EJ3 Methods common to all objects
   EJ5 Methods




                                          50
Functies mogen maar 辿辿n ding doen
    Ze moeten dat goed doen
    Ze mogen alleen dat doen




                                    51
Richtlijnen voor functies (CC3)
   Kort! => verstaanbaar
       geen geneste controlestructuren
       ingewikkelde tests in aparte functie
   E辿n niveau van abstractie per functie
   Beschrijvende namen
       voor functies en variabelen/parameters
   Leesbaar van boven naar beneden
       beginnen met hoofdfunctie, daarna hulpfuncties
                                                           52
Richtlijnen voor functies (CC3)
   G辿辿n neveneffecten
       zwakkere betekenis: 辿辿n ding doen
        public boolean checkPwd(String user, String passwd) {
          
          if(hash.equals(storedHash)) {
            session.initialize();
            return true;
          }
        }
       sterkere betekenis: geen data muteren
            = basisgedachte functioneel programmeren
       N.B. System.out.println() is een neveneffect
                                                                53
Richtlijnen voor functies (CC3)
   Command/query separation
       ofwel iets doen, ofwel een antwoord geven
       niet beide
   G辿辿n output arguments
       vb. Arrays.fill(boolean[]   a, boolean val)

   Exceptions ipv foutcodes of null (zie ook
    EJ#43)
   Don't repeat yourself
                                                      54
Functie-argumenten (CC3)
   Aantal:
       0 argumenten is best
       1 argument (monad) is het op 辿辿n na beste
       2 argumenten (dyad) is al moeilijker te begrijpen
       3 argumenten (triad) is ongeveer het maximum
        toelaatbare aantal
   Zie ook EJ#40


                                                            55
Functie-argumenten (CC3)
   Geen vlag-argumenten
       = booleans die gedrag veranderen
       Schrijf 2 functies!
   Lange argumentenlijsten
       Gebruik argument-objecten
        Circle makeCircle(double x, double y, double radius)
        Circle makeCircle(Point center, double radius)
       Varargs tellen als 辿辿n argument
        void monad(Integer... args)
        void dyad(String name, Integer... args)

                                                               56
Cre谷ren van objecten (EJ2)
   Static factory methods ipv constructors (EJ#1)
public static Fraction
       valueOf(int numerator, int denominator) {

     int g = gcd(numerator, denominator);
     return new Fraction(numerator / g, denominator / g);
}

private Fraction(int numerator, int denominator) {
    this.numerator = numerator;
    this.denominator = denominator;
}


                                                        57
Voordelen van static factory methods
   Hebben naam, returntype
   Cre谷ren niet noodzakelijk een nieuw object
       caching
       instance-controlled klasse, bv. Boolean
       laat toe om te garanderen dat bij immutable klassen
        geldt: a.equals(b) als en slechts als a == b
   Kunnen object van subtype teruggeven

                                                              58
Nadelen van static factory methods
   Onmogelijk overerven van klassen zonder
    publieke/protected constructors
        misschien niet echt een nadeel
   niet te onderscheiden van andere static methods
        naamgeving: valueOf(), of(), newInstance(),
         getInstance()




                                                       59
Cre谷ren van objecten (EJ2)
   Builder pattern: voor constructors met
       teveel parameters
       optionele/default parameters
       verschillende parameters van zelfde type




                                                   60
Voorbeeld: Boerderij-object
        aanmaken
 public Farm(String farmName,
             String playerName,
             double startBudget,
             int gridWidth) {

     this.farmName = farmName;
     this.playerName = playerName;
     this.startBudget = startBudget;
     this.width = width;
     this.fields = makeEmptyFields();
 }



                                        61
Builder (binnen Farm)
public static class Builder {
    String farmName = "";           String playerName = "";
    double startBudget = 1_000.0;   int gridWidth = 4;

    public Builder withFarmName(String farmName) {
        this.farmName = farmName; return this;
    }
    public Builder withPlayerName(String playerName) {
        this.playerName = playerName; return this;
    }
    public Builder withStartBudget(double budget) {
        this.startBudget = budget; return this;
    }
    public Builder withGridWidth(int gridWidth) {
        this.gridWidth = gridWidth; return this;
    }

    public Farm build() {
        return new Farm(this);
    }
}                                                             62
Constructors
private Farm(String farmName,
             String playerName,
             double startBudget,
             int gridWidth) {
    this.farmName = farmName;
    this.playerName = playerName;
    this.budget = startBudget;
    this.gridWidth = gridWidth;
    this.fields = makeEmptyFields();
}

private Farm(Builder builder) {
    this(builder.farmName,
         builder.playerName,
         builder.startBudget,
         builder.gridWidth);
}                                      63
Client code


Farm farm = new Farm.Builder()
    .withFarmName("Carlokes")
    .withPlayerName("Ren辿")
    .withStartBudget(1_000.00)
    .withGridWidth(5)
    .build();




                                 64
Voordelen van Builders
   Autocomplete helpt bij invullen van parameters
   Niet meer onthouden in welke volgorde
    parameters komen
   Vermijden verschillende ctors voor default-
    waarden
   Opleggen van invariants bij objectcreatie
   Verschillende varargs mogelijk
   Makkelijker parameters toevoegen
                                                     65
Let op bij implementeren equals()
                  (EJ#8)
   Enkel implementeren wanneer nodig
   Typisch voor waarde-objecten, bv. Date,
    Integer, Fraction
   Respecteer het contract van equals()




                                                66
equals() is een equivalentierelatie
   Reflexief:  x  null: x.equals(x)
   Symmetrisch:  x,y  null: x.equals(y) 
    y.equals(x)

    Transitief:  x,y,z  null: x.equals(y) en
    y.equals(z)  x.equals(z)
   Consistent:  x,y  null: x.equals(y) geeft
    telkens zelfde waarde terug

     x  null: x.equals(null) geeft altijd false terug
                                                          67
Recept voor equals(Object o)
1.Controleer of o referentie naar dit object is
     zo ja true
2.Controleer met instanceof of o het correcte
  type heeft,
     zo niet false
     zo ja, casten naar juiste type
3.Controleer of elk significant attribuut van o
  overeenkomt met het corresponderende
  attribuut van dit object                          68
vb. Fraction
         (gegenereerd door Eclipse!)
@Override
public boolean equals(Object obj) {
    if (this == obj)    // 1
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass()) // 2
        return false;
    Fraction other = (Fraction) obj;
    if (denominator != other.denominator) // 3
        return false;
    if (numerator != other.numerator)
        return false;
    return true;
}
                                                 69
Overschrijf hashCode() als je equals()
        overschrijft (EJ#9)
   Zoniet overtreed je contract van
    Object.hashCode()
       vb.  x,y  null: x.equals(y)  x.hashCode() ==
        y.hashCode()
   Klasse zal niet werken in HashMap, HashSet,
    Hashtable
    
        default impl.: verschillend object verschillende
        hashCodes

                                                             70
Recept voor hashCode()
   cfr. boek
   gebruik door Eclipse gegenereerde hashCode()




                                                   71
vb. Fraction


@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + denominator;
    result = prime * result + numerator;
    return result;
}




                                             72
hashCode voor ingewikkeld
            immutable object
   Lazily initialized, cached hashCode
      private volatile int hashCode;

      @Override public int hashCode() {
          if(hashCode == 0) {
              final int prime = 31;
              int result = 1;
              result = prime * result + denominator;
              result = prime * result + numerator;
              hashCode = result;
          }
          return hashCode;
      }
                                                       73
Altijd toString() overschrijven (EJ#10)
   Klasse makkelijker te gebruiken
    vb. Fraction: 3/5 ipv Fraction@163b94
   Bevat zo mogelijk alle interessante info uit object
   Documenteer formaat in javadoc
   Alle info in de string is via accessors/publieke
    velden te verkrijgen



                                                          74
hashCode(), equals() en toString() in
             Scala ;-)


         case class Fraction(
             val numerator: Int,
             val denominator: Int)




                                        75
Argumenten controleren (EJ#38)
   Client-code is de vijand
   Expliciet maken van veronderstellingen over
    gebruik van de method
   Vermijden van problemen bij geven van
    verkeerde/onverwachte input
   Sneller fouten opsporen



                                                  76
Argumenten controleren (EJ#38)
   Publieke methods:
       Gebruik IllegalArgumentException en duidelijke
        foutboodschap
       Documenteer met Javadoc @throws
   Niet-publieke methods
       Gebruik assert
       Wordt enkel gecompileerd met optie -ea


                                                         77
Schrijf nooit return null;
   Client-code verplicht uitzondering te behandelen
       null-checks vervuilen je code
   Aanleiding tot NullPointerException
   Alternatief:
       Exception
       Leeg object, bv. Collections.emptyList()
       Opl. in Scala: Option[T]  Some[T] of None

                                                       78
Exceptions
   EJ#60: bij voorkeur standaard-exceptions
    gebruiken
   EJ#62: alle mogelijke exceptions documenteren
    met @throws
   EJ#65: niet onder de mat vegen
    
        try {  }
        catch(SomeException e) {}
    
        try {  }
        catch(SomeException e)
        { e.printStackTrace(); }                    79
Checked vs Unchecked Exceptions
   Tegenspraak tussen EJ en CC
   EJ#58: Checked exceptions voor uitzonderlijke
    condities, runtime exceptions voor bugs
       daarvoor zijn ze ontworpen!
   CC7: The debate is over. Use Unchecked
    Exceptions.
       doorbreken encapsulatie
       ontbreken van checked exceptions staan robuuste
        code niet in de weg
                                                          80
Checked vs Unchecked Exceptions
   EJ#59. Onnodig gebruik van checked exceptions
    vermijden
       lastig voor gebruiker API
       nodigt uit slechte foutafhandeling te schrijven
   EJ#64. Streven naar atomair falen
       Exception  laat object in toestand van v坦坦r method
        call
       cfr. ACID bij databases

                                                              81
Unit tests


             82
3 wetten van Test Driven
         Development (CC9)
1. Schrijf geen productiecode v坦坦r een
   mislukkende unit test
2. Schrijf niet meer in een unit test dan voldoende
   om te falen (niet compileren = falen)
3. Schrijf niet meer productiecode dan voldoende
   om de falende test te laten slagen



                                                      83
Aanbevelingen voor Unit tests
   Hou de test-code clean, leesbaar
        testcode is even belangrijk als productiecode
   Domeinspecifieke test-taal
        = utility methods die testcode leesbaarder maken
   E辿n assert per test
        Niet in steen gebeiteld, maar hou minimaal
         E辿n concept per test
   Gebruik code coverage tool & streef naar 100%
   Private method package local maken om te kunnen testen
    mag!                                                      84
F.I.R.S.T. principe voor Unit Tests
   Fast: je moet tests vaak willen draaien
   Independent: waterval van problemen
    vermijden
   Repeatable: in ontwikkelings/QA/UA/productie-
    omgevingen
   Self-Validating: wit-zwart, geen grijs
   Timely: tijdig schrijven zorgt voor testbare code

                                                        85
Ontwerpen


            86
Emergent design (CC12)
   Een ontwerp is eenvoudig als het volgende
    regels volgt:
       draait alle tests
       bevat geen duplicatie
       is expressief, drukt de bedoeling van de
        programmeur uit
       minimaliseert het aantal klassen en functies
   < Kent Beck, Extreme Programming Explained

                                                       87
Emergent design
   Met deze regels ontstaat een goed ontwerp
    als vanzelf tijdens het programmeren
   Maakt het makkelijker bv. Single Responsibility
    Principle of Dependency Inversion Principle te
    volgen




                                                        88
Alle tests draaien
   Een goed ontwerp produceert een systeem dat
    zich gedraagt zoals bedoeld was
   Zorgen voor testbare code zorgt voor beter
    ontwerp
       leidt tot high cohesion  low coupling
   Code opkuisen zal functionaliteit niet breken



                                                    89
Geen duplicatie
   Makkelijkst: identieke lijnen code
   Ook bvb. int size() vs boolean isEmpty()
       met aparte implementatie voor beide
   Template methods gebruiken
   Wat met identieke implementatie, maar
    verschillende intentie?


                                               90
Intentie vs implementatie
                   (RubySlim voorbeeld)
   Slim methodnaam naar Ruby methodnaam:
    def slim_to_ruby_method(method_name)
      value = method_name[0..0].downcase + method_name[1..-1]
      value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }
    end
   Slim packagenaam omzetten naar
    bestandsnaam
    def to_file_name(module_name)
      value = module_name[0..0].downcase + module_name[1..-1]
      value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }
    end
           http://www.informit.com/articles/article.aspx?p=1313447   91
Intentie vs implementatie
   Naar elkaar laten verwijzen?
       Nee: to_file_name moet niets weten van
        methodnamen en v.v.
   Hernoemen naar to_camel_case?
       Nee: client-code moet niets weten van
        implementatiedetails
   Aparte method to_camel_case + oorspronkelijke
    2 er naar laten verwijzen
       = toepassing 辿辿n niveau van abstractie
                                                    92
Intentie vs implementatie
def slim_to_ruby_method(method_name)
  camel_to_underscore(method_name)
end

def to_file_name(module_name)
  camel_to_underscore(module_name)
end

def camel_to_underscore(camel_namme)
  value = camel_name[0..0].downcase + camel_name[1..-1]
  value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }
end



                                                          93
Expressiviteit
   Maak systeem makkelijk begrijpbaar
       code drukt uit wat de programmeur bedoelt
   Goede naamgeving
       weergave van verantwoordelijkheden
       gestandaardiseerde naamen (bv. patterns)
   Goed geschreven Unit Test
       = documentatie a.h.v. voorbeeld

                                                    94
Expressiviteit
   Voldoende aandacht besteden hieraan
       Niet verder doen met iets anders zodra het werkt
   Fierheid over je vakmanschap




                                                             95
Minimaal aantal klassen en methods
   Tegenspraak met kleine klassen?
        kan te ver gedreven worden
        mag geen dogma zijn (vb. scheiden van data- &
         gedrag-klassen)
        evenwicht
   Tests, elimineren duplicatie, expressiviteit zijn
    belangrijker


                                                           96
Stijl


        97
Commentaar (CC4)
   Commentaar is geen oplossing voor slechte code
   Druk je intentie uit in code




                                                     98
Goede commentaar
   Wettelijke bepalingen (vb. licentie, copyrigth)
   Informatieve commentaar
    // Returns the numerator of this Fraction.
    public int getNumerator() {
        return numerator;
    }
       functienaam zegt het al!
       bv. w辿l uitleg bij ingewikkelde regexp


                                                      99
Goede commentaar
   Intentie uitleggen
   Verduidelijking
       vb. betekenis argument/return-waarde
       kan best op andere manier in je eigen code
       bij API-calls geen keuze
   Waarschuwing consequenties
       bv. test die lang duurt

                                                     100
Goede commentaar
   TODO
       worden bijgehouden in Eclipse, Netbeans
   Javadoc publieke API (cfr. EJ#44)
       Let op, Javadocs kunnen even misleidend zijn dan
        andere (slechte) commentaar
       Is dit goede commentaar?
         /** Returns the denominator of this Fraction.
          * @return the denominator of this Fraction.
          */
         public int getDenominator() { return denominator; }

                                                               101
Slechte commentaar
   Gebrabbel
   Redundante commentaar
       zegt hetzelfde als de code (maar dan minder precies)
       legt niets uit over intentie code
   Misleidende commentaar
       te vaag om te kloppen
   Verplichte commentaar
       vb. Javadoc van triviale methods
                                                               102
Slechte commentaar
   Log van wijzigingen
       is werk voor versiebeheersysteem!
   Commentaar als vervanging van goede
    variabele-/methodnaam
   Positiemarkeringen
    //---------- Accessors --------------------------

   Commentaar bij sluiten accolade


                                                        103
Slechte commentaar
   Vermeldingen auteurs
       Hoort in versiebeheersysteem
   Code in commentaar
       Vervuilt de code
       Wat is de intentie? Waarom in commentaar?
       Versiebeheer!
   HTML commentaar

                                                    104
Slechte commentaar
   Niet-lokale informatie
   Teveel informatie
   Onduidelijke link met code
   Functie-headers
   Javadocs in niet-publieke code



                                     105
Naamgeving (CC2)
   Namen geven intentie bloot
    
        int d; // elapsed time in days
   Vermijd desinformatie
    
        private Person[] personList;
       kleine L (l of 1?), hoofletter O (O of 0?)
   Namen zijn uitspreekbaar



                                                     106
Naamgeving
   Zinvol onderscheid tussen namen
       variabele niet verkeerd spellen om onderscheid te
        maken met andere, vb. class  klass
       geen getalseries, vb. a1, a2, a3, 
       redundante namen, vb. denominatorVariable
   Namen zijn zoekbaar
       hoe breder de scope, hoe langer de naam
       variabelen met 1 letter enkel lokaal in korte methods
                                                                107
Naamgeving
   Vermijd coderingen
       Hongaarse notatie met type in de naam, vb.
        phoneString
       Member prefix voor onderscheid met functie-
        argumenten, vb. private int mNumerator;
       Interface prefix, vb. IShapeFactory
   Probeer niet grappig te zijn


                                                        108
Naamgeving
   Consistent: 辿辿n woord per concept
       fetch  retrieve  get
       Controller  Manager  Driver
   Namen uit oplossingsdomein (vakjargon,
    patterns, wiskundige termen, )
   Namen uit probleemdomein



                                             109
Naamgeving
   Klassenamen
       gebaseerd op zelfstandige naamwoorden, vb.
        Customer, WikiPage, AddressParser
       vermijd te algemene woorden als Manager,
        Processor, Data, Info, Controller
       geen werkwoord




                                                     110
Naamgeving
   Methodnamen
       gebaseerd op werkwoorden
       accessors/mutators beginnen met get/set
       predicaten beginnen met is
       constructor overloading  factory methods die
        argument beschrijven
            vb. Complex(double) 
             Complex.fromRealNumber(double)



                                                        111
En verder...


               112
Waarom de boeken nog
                lezen/kopen?
   Verschillende topics niet aan bod gekomen
       Concurrency (CC13 & appendix A, EJ10)
       Praktijkvoorbeelden refactoring (CC14, CC16)
       Smells and Heuristics (CC17)




                                                       113
Bedankt!


           114

More Related Content

Clean, effective java

  • 1. Clean, effective Java Bert Van Vreckem
  • 2. 2
  • 3. ? 3
  • 4. (TODO) 4
  • 5. 5
  • 6. 6
  • 8. Inhoud EJ (2nd Ed, 2008) Creatie objecten Algemene Gemeensch. methods programmeertips Klassen en interfaces Foutafhandeling Generieke klassen Concurrency Enums, annotaties Serialisatie Methods 78 items (EJ#nn) 8
  • 9. 9
  • 10. Robert 'Uncle Bob' Martin 10
  • 11. Inhoud CC (2009) Naamgeving Unit tests Functies Klassen Commentaar Systemen Formattering Emergent design Objecten & Iteratieve verfijning datastructuren Refactoring case Foutafhandeling Indicatoren van Grenzen slechte code 11
  • 12. Wat is heldere code? 12
  • 13. Doel: Disseminatie Discussie Feedback PS. Koop de boeken! (vakgroepbib?) 13
  • 14. Conventies Kleurtjes: good practice bad practice nadruk Verwijzingen: CC5 = Clean Code, hoofdstuk 5 EJ5 = Effective Java, hoofdstuk 5 EJ#5 = Effective Java, item 5 14
  • 15. Onderwerpen Klassen Functies Unit tests Ontwerp Stijl 15
  • 16. Klassen 16
  • 17. Klassen EJ4 Classes and Interfaces CC6 Objects and Data Structures CC10 Classes 17
  • 18. Richtlijnen voor klassen (CC10) Klassen moeten klein zijn Geen God-klassen (vb. DomainContoller!) Single Responsibility Principle: er is maar 1 reden om de klasse te wijzigen Cohesie: klein aantal instantievariabelen, methods manipuleren meerdere instantievariabelen 18
  • 19. Beperk mutability (EJ#15) Geen mutators Laat geen overerving toe Alle velden final Alle velden private Geen toegang tot wijzigbare componenten 19
  • 20. Voorbeeld: Breuken public class Fraction { public int numerator; public int denominator; } 20
  • 21. Breuken: Bean pattern public class Fraction { private int numerator; private int denominator; public Fraction(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; reduce(); } public int getNumerator() { return numerator; } public int getDenominator() { return denominator; } public void setNumerator(int numerator) { this.numerator = numerator; reduce(); } public void setDenominator(int denominator) { this.denominator = denominator; reduce(); } ... 21 }
  • 22. Breuken: hulpcode private void reduce() { int gcd = gcd(numerator, denominator); numerator /= gcd; denominator /= gcd); } private static int gcd(int a, int b) { if (b==0) return a; return gcd(b,a%b); } @Override public String toString() { return "" + getNumerator() + "/" + getDenominator(); } 22
  • 23. Breuken: rekenen public void add(Fraction that) { numerator = this.getNumerator() * that.getDenominator() + this.getDenominator() * that.getNumerator(); denominator = this.getDenominator() * that.getDenominator(); reduce(); } public void multiply(Fraction that) { numerator = this.getNumerator() * that.getNumerator(); denominator = this.getDenominator() * that.getDenominator(); reduce(); } 23
  • 24. Onveranderlijke Breuken public final class Fraction { private final int numerator; private final int denominator; public Fraction(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; } public int getNumerator() { return numerator; } public int getDenominator() { return denominator; } } 24
  • 25. Of misschien zelfs public final class Fraction { public final int numerator; public final int denominator; public Fraction(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; } } 25
  • 26. Terzijde: hetzelfde in Scala ;-) class Fraction(val numerator: Int, val denominator: Int) 26
  • 27. Rekenen met onveranderlijke breuken public Fraction add(Fraction that) { return new Fraction( this.numerator * that.denominator + that.numerator * this.denominator, this.denominator * that.denominator); } public Fraction multiply(Fraction that) { return new Fraction( this.numerator * that.numerator, this.denominator * that.denominator); } 27
  • 28. Wijzigbare componenten public class Farm { private Field[][] fields; public Farm(int width) { this.fields = new Field[width][width]; initFields(); } private void initFields() { } public Field[][] getFields() { return fields; } } Farm farm = new Farm(4); Field[][] fields = farm.getFields(); fields[2][3] = null; // zou niet mogen! 28
  • 29. Wijzigbare componenten Geef individuele elementen terug, vb. public Field getField(int row, int col) { return fields[row][col]; } Maak een defensieve kopie 29
  • 30. Let op! (EJ#39) public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { this.start = start; this.end = end; } public Date getStart() { return start; } public Date getEnd() { return end; } } 30
  • 31. Aanval op interne toestand Period Date start = new Date(2012, 06, 01); Date end = new Date(2012, 06, 30); Period p = new Period(start, end); end.setYear(2013); // Deze test zal falen! assertEquals(2012, p.getEnd().getYear()); 31
  • 32. Defensieve kopie public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); } 32
  • 33. Immutability voordelen Simpel: 辿辿n toestand Makkelijker testen Altijd thread-safe! Kan je hergebruiken public static final Fraction ZERO = new Fraction(0,0); public static final Fraction ONE = new Fraction(1,1); Kopies maken eigenlijk overbodig Bouwstenen voor andere objecten 33
  • 34. Immutability nadelen Veel objecten aanmaken op te lossen, bv. met static factories (zie verder) 34
  • 35. Is doorgedreven immutability mogelijk / wenselijk? 35
  • 36. Verkies compositie boven overerving (EJ#16) Overerving kan binnen zelfde package, onder controle van zelfde programmeurs van specifiek daarvoor ontworpen klassen van interfaces Overerving vermijden van gewone concrete klassen over packages heen 36
  • 37. Waarom? Overerving breekt encapsulatie Subklassen hangen af van implementatie superklasse Superklasse wijzigen problemen in subklassen Compilatie Verkeerd gedrag Beveiligingsproblemen Oplossing: wrapper class 37
  • 38. Verkies interfaces boven abstracte klassen (EJ#18) Bestaande klassen kunnen makkelijk aangepast worden om nieuwe interface te implementeren Interfaces zijn ideaal voor het defini谷ren van mixins (vgl. Scala Traits, Ruby Modules) Interfaces maken niet-hierarchische typeframeworks mogelijk Veilige manier om functionaliteit uit te breiden 38
  • 40. Nadelen Geen implementatie voorzie basisimplementatie (skeletal) kan jouw klasse niet overerven van basisimpl.? simulated multiple inheritance Eens een interface gepubliceerd is, kan je niet meer wijzigen 40
  • 42. Objecten vs Datastructuren (CC6) Objecten Verbergen data/implementatie achter abstracties Hebben functies om deze data te bewerken Datastructuren Hebben data Hebben geen functies van belang 42
  • 43. Vb: 2 implementaties voor vormen Datastructuren/procedureel public class Square { public Point topLeft; public double side; } public class Circle { public Point center; public double radius; } 43
  • 44. public class Geometry { public double area(Object shape) { if (shape instanceof Square) { Square s = (Square)shape; return s.side * s.side; } else if(shape instanceof Circle) { Circle c = (Circle) shape; return c.radius * c.radius * Math.PI; } else { throw new IllegalArgumentException( "Not a known shape"); } } } Jamaar, da's geen OO! 44
  • 45. Vb: 2 implementaties voor vormen Objectgeorienteerd public interface Shape { public double area(); } public class Square implements Shape { private Point topLeft; private double side; @Override public double area() { return side * side; } } 45
  • 46. public class Circle implements Shape { private Point center; private double radius; @Override public double area() { return Math.PI * radius * radius; } } 46
  • 47. Twee soorten refactorings Functie toevoegen (bv. perimeter()) Procedureel: enkel Geometry aanpassen Shapes en hun clients blijven ongewijzigd! OO: ALLE Shapes aanpassen Shape toevoegen (bv. Rectangle) Procedureel: ALLE functies in Geometry aanpassen OO: enkel Rectangle-klasse schrijven 47
  • 48. Is de procedurele aanpak uit het vorige voorbeeld soms toelaatbaar/aangewezen? 48
  • 49. Functies 49
  • 50. Functies / methods CC3 Functions EJ2 Creating and destroying objects EJ3 Methods common to all objects EJ5 Methods 50
  • 51. Functies mogen maar 辿辿n ding doen Ze moeten dat goed doen Ze mogen alleen dat doen 51
  • 52. Richtlijnen voor functies (CC3) Kort! => verstaanbaar geen geneste controlestructuren ingewikkelde tests in aparte functie E辿n niveau van abstractie per functie Beschrijvende namen voor functies en variabelen/parameters Leesbaar van boven naar beneden beginnen met hoofdfunctie, daarna hulpfuncties 52
  • 53. Richtlijnen voor functies (CC3) G辿辿n neveneffecten zwakkere betekenis: 辿辿n ding doen public boolean checkPwd(String user, String passwd) { if(hash.equals(storedHash)) { session.initialize(); return true; } } sterkere betekenis: geen data muteren = basisgedachte functioneel programmeren N.B. System.out.println() is een neveneffect 53
  • 54. Richtlijnen voor functies (CC3) Command/query separation ofwel iets doen, ofwel een antwoord geven niet beide G辿辿n output arguments vb. Arrays.fill(boolean[] a, boolean val) Exceptions ipv foutcodes of null (zie ook EJ#43) Don't repeat yourself 54
  • 55. Functie-argumenten (CC3) Aantal: 0 argumenten is best 1 argument (monad) is het op 辿辿n na beste 2 argumenten (dyad) is al moeilijker te begrijpen 3 argumenten (triad) is ongeveer het maximum toelaatbare aantal Zie ook EJ#40 55
  • 56. Functie-argumenten (CC3) Geen vlag-argumenten = booleans die gedrag veranderen Schrijf 2 functies! Lange argumentenlijsten Gebruik argument-objecten Circle makeCircle(double x, double y, double radius) Circle makeCircle(Point center, double radius) Varargs tellen als 辿辿n argument void monad(Integer... args) void dyad(String name, Integer... args) 56
  • 57. Cre谷ren van objecten (EJ2) Static factory methods ipv constructors (EJ#1) public static Fraction valueOf(int numerator, int denominator) { int g = gcd(numerator, denominator); return new Fraction(numerator / g, denominator / g); } private Fraction(int numerator, int denominator) { this.numerator = numerator; this.denominator = denominator; } 57
  • 58. Voordelen van static factory methods Hebben naam, returntype Cre谷ren niet noodzakelijk een nieuw object caching instance-controlled klasse, bv. Boolean laat toe om te garanderen dat bij immutable klassen geldt: a.equals(b) als en slechts als a == b Kunnen object van subtype teruggeven 58
  • 59. Nadelen van static factory methods Onmogelijk overerven van klassen zonder publieke/protected constructors misschien niet echt een nadeel niet te onderscheiden van andere static methods naamgeving: valueOf(), of(), newInstance(), getInstance() 59
  • 60. Cre谷ren van objecten (EJ2) Builder pattern: voor constructors met teveel parameters optionele/default parameters verschillende parameters van zelfde type 60
  • 61. Voorbeeld: Boerderij-object aanmaken public Farm(String farmName, String playerName, double startBudget, int gridWidth) { this.farmName = farmName; this.playerName = playerName; this.startBudget = startBudget; this.width = width; this.fields = makeEmptyFields(); } 61
  • 62. Builder (binnen Farm) public static class Builder { String farmName = ""; String playerName = ""; double startBudget = 1_000.0; int gridWidth = 4; public Builder withFarmName(String farmName) { this.farmName = farmName; return this; } public Builder withPlayerName(String playerName) { this.playerName = playerName; return this; } public Builder withStartBudget(double budget) { this.startBudget = budget; return this; } public Builder withGridWidth(int gridWidth) { this.gridWidth = gridWidth; return this; } public Farm build() { return new Farm(this); } } 62
  • 63. Constructors private Farm(String farmName, String playerName, double startBudget, int gridWidth) { this.farmName = farmName; this.playerName = playerName; this.budget = startBudget; this.gridWidth = gridWidth; this.fields = makeEmptyFields(); } private Farm(Builder builder) { this(builder.farmName, builder.playerName, builder.startBudget, builder.gridWidth); } 63
  • 64. Client code Farm farm = new Farm.Builder() .withFarmName("Carlokes") .withPlayerName("Ren辿") .withStartBudget(1_000.00) .withGridWidth(5) .build(); 64
  • 65. Voordelen van Builders Autocomplete helpt bij invullen van parameters Niet meer onthouden in welke volgorde parameters komen Vermijden verschillende ctors voor default- waarden Opleggen van invariants bij objectcreatie Verschillende varargs mogelijk Makkelijker parameters toevoegen 65
  • 66. Let op bij implementeren equals() (EJ#8) Enkel implementeren wanneer nodig Typisch voor waarde-objecten, bv. Date, Integer, Fraction Respecteer het contract van equals() 66
  • 67. equals() is een equivalentierelatie Reflexief: x null: x.equals(x) Symmetrisch: x,y null: x.equals(y) y.equals(x) Transitief: x,y,z null: x.equals(y) en y.equals(z) x.equals(z) Consistent: x,y null: x.equals(y) geeft telkens zelfde waarde terug x null: x.equals(null) geeft altijd false terug 67
  • 68. Recept voor equals(Object o) 1.Controleer of o referentie naar dit object is zo ja true 2.Controleer met instanceof of o het correcte type heeft, zo niet false zo ja, casten naar juiste type 3.Controleer of elk significant attribuut van o overeenkomt met het corresponderende attribuut van dit object 68
  • 69. vb. Fraction (gegenereerd door Eclipse!) @Override public boolean equals(Object obj) { if (this == obj) // 1 return true; if (obj == null) return false; if (getClass() != obj.getClass()) // 2 return false; Fraction other = (Fraction) obj; if (denominator != other.denominator) // 3 return false; if (numerator != other.numerator) return false; return true; } 69
  • 70. Overschrijf hashCode() als je equals() overschrijft (EJ#9) Zoniet overtreed je contract van Object.hashCode() vb. x,y null: x.equals(y) x.hashCode() == y.hashCode() Klasse zal niet werken in HashMap, HashSet, Hashtable default impl.: verschillend object verschillende hashCodes 70
  • 71. Recept voor hashCode() cfr. boek gebruik door Eclipse gegenereerde hashCode() 71
  • 72. vb. Fraction @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + denominator; result = prime * result + numerator; return result; } 72
  • 73. hashCode voor ingewikkeld immutable object Lazily initialized, cached hashCode private volatile int hashCode; @Override public int hashCode() { if(hashCode == 0) { final int prime = 31; int result = 1; result = prime * result + denominator; result = prime * result + numerator; hashCode = result; } return hashCode; } 73
  • 74. Altijd toString() overschrijven (EJ#10) Klasse makkelijker te gebruiken vb. Fraction: 3/5 ipv Fraction@163b94 Bevat zo mogelijk alle interessante info uit object Documenteer formaat in javadoc Alle info in de string is via accessors/publieke velden te verkrijgen 74
  • 75. hashCode(), equals() en toString() in Scala ;-) case class Fraction( val numerator: Int, val denominator: Int) 75
  • 76. Argumenten controleren (EJ#38) Client-code is de vijand Expliciet maken van veronderstellingen over gebruik van de method Vermijden van problemen bij geven van verkeerde/onverwachte input Sneller fouten opsporen 76
  • 77. Argumenten controleren (EJ#38) Publieke methods: Gebruik IllegalArgumentException en duidelijke foutboodschap Documenteer met Javadoc @throws Niet-publieke methods Gebruik assert Wordt enkel gecompileerd met optie -ea 77
  • 78. Schrijf nooit return null; Client-code verplicht uitzondering te behandelen null-checks vervuilen je code Aanleiding tot NullPointerException Alternatief: Exception Leeg object, bv. Collections.emptyList() Opl. in Scala: Option[T] Some[T] of None 78
  • 79. Exceptions EJ#60: bij voorkeur standaard-exceptions gebruiken EJ#62: alle mogelijke exceptions documenteren met @throws EJ#65: niet onder de mat vegen try { } catch(SomeException e) {} try { } catch(SomeException e) { e.printStackTrace(); } 79
  • 80. Checked vs Unchecked Exceptions Tegenspraak tussen EJ en CC EJ#58: Checked exceptions voor uitzonderlijke condities, runtime exceptions voor bugs daarvoor zijn ze ontworpen! CC7: The debate is over. Use Unchecked Exceptions. doorbreken encapsulatie ontbreken van checked exceptions staan robuuste code niet in de weg 80
  • 81. Checked vs Unchecked Exceptions EJ#59. Onnodig gebruik van checked exceptions vermijden lastig voor gebruiker API nodigt uit slechte foutafhandeling te schrijven EJ#64. Streven naar atomair falen Exception laat object in toestand van v坦坦r method call cfr. ACID bij databases 81
  • 83. 3 wetten van Test Driven Development (CC9) 1. Schrijf geen productiecode v坦坦r een mislukkende unit test 2. Schrijf niet meer in een unit test dan voldoende om te falen (niet compileren = falen) 3. Schrijf niet meer productiecode dan voldoende om de falende test te laten slagen 83
  • 84. Aanbevelingen voor Unit tests Hou de test-code clean, leesbaar testcode is even belangrijk als productiecode Domeinspecifieke test-taal = utility methods die testcode leesbaarder maken E辿n assert per test Niet in steen gebeiteld, maar hou minimaal E辿n concept per test Gebruik code coverage tool & streef naar 100% Private method package local maken om te kunnen testen mag! 84
  • 85. F.I.R.S.T. principe voor Unit Tests Fast: je moet tests vaak willen draaien Independent: waterval van problemen vermijden Repeatable: in ontwikkelings/QA/UA/productie- omgevingen Self-Validating: wit-zwart, geen grijs Timely: tijdig schrijven zorgt voor testbare code 85
  • 86. Ontwerpen 86
  • 87. Emergent design (CC12) Een ontwerp is eenvoudig als het volgende regels volgt: draait alle tests bevat geen duplicatie is expressief, drukt de bedoeling van de programmeur uit minimaliseert het aantal klassen en functies < Kent Beck, Extreme Programming Explained 87
  • 88. Emergent design Met deze regels ontstaat een goed ontwerp als vanzelf tijdens het programmeren Maakt het makkelijker bv. Single Responsibility Principle of Dependency Inversion Principle te volgen 88
  • 89. Alle tests draaien Een goed ontwerp produceert een systeem dat zich gedraagt zoals bedoeld was Zorgen voor testbare code zorgt voor beter ontwerp leidt tot high cohesion low coupling Code opkuisen zal functionaliteit niet breken 89
  • 90. Geen duplicatie Makkelijkst: identieke lijnen code Ook bvb. int size() vs boolean isEmpty() met aparte implementatie voor beide Template methods gebruiken Wat met identieke implementatie, maar verschillende intentie? 90
  • 91. Intentie vs implementatie (RubySlim voorbeeld) Slim methodnaam naar Ruby methodnaam: def slim_to_ruby_method(method_name) value = method_name[0..0].downcase + method_name[1..-1] value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" } end Slim packagenaam omzetten naar bestandsnaam def to_file_name(module_name) value = module_name[0..0].downcase + module_name[1..-1] value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" } end http://www.informit.com/articles/article.aspx?p=1313447 91
  • 92. Intentie vs implementatie Naar elkaar laten verwijzen? Nee: to_file_name moet niets weten van methodnamen en v.v. Hernoemen naar to_camel_case? Nee: client-code moet niets weten van implementatiedetails Aparte method to_camel_case + oorspronkelijke 2 er naar laten verwijzen = toepassing 辿辿n niveau van abstractie 92
  • 93. Intentie vs implementatie def slim_to_ruby_method(method_name) camel_to_underscore(method_name) end def to_file_name(module_name) camel_to_underscore(module_name) end def camel_to_underscore(camel_namme) value = camel_name[0..0].downcase + camel_name[1..-1] value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" } end 93
  • 94. Expressiviteit Maak systeem makkelijk begrijpbaar code drukt uit wat de programmeur bedoelt Goede naamgeving weergave van verantwoordelijkheden gestandaardiseerde naamen (bv. patterns) Goed geschreven Unit Test = documentatie a.h.v. voorbeeld 94
  • 95. Expressiviteit Voldoende aandacht besteden hieraan Niet verder doen met iets anders zodra het werkt Fierheid over je vakmanschap 95
  • 96. Minimaal aantal klassen en methods Tegenspraak met kleine klassen? kan te ver gedreven worden mag geen dogma zijn (vb. scheiden van data- & gedrag-klassen) evenwicht Tests, elimineren duplicatie, expressiviteit zijn belangrijker 96
  • 97. Stijl 97
  • 98. Commentaar (CC4) Commentaar is geen oplossing voor slechte code Druk je intentie uit in code 98
  • 99. Goede commentaar Wettelijke bepalingen (vb. licentie, copyrigth) Informatieve commentaar // Returns the numerator of this Fraction. public int getNumerator() { return numerator; } functienaam zegt het al! bv. w辿l uitleg bij ingewikkelde regexp 99
  • 100. Goede commentaar Intentie uitleggen Verduidelijking vb. betekenis argument/return-waarde kan best op andere manier in je eigen code bij API-calls geen keuze Waarschuwing consequenties bv. test die lang duurt 100
  • 101. Goede commentaar TODO worden bijgehouden in Eclipse, Netbeans Javadoc publieke API (cfr. EJ#44) Let op, Javadocs kunnen even misleidend zijn dan andere (slechte) commentaar Is dit goede commentaar? /** Returns the denominator of this Fraction. * @return the denominator of this Fraction. */ public int getDenominator() { return denominator; } 101
  • 102. Slechte commentaar Gebrabbel Redundante commentaar zegt hetzelfde als de code (maar dan minder precies) legt niets uit over intentie code Misleidende commentaar te vaag om te kloppen Verplichte commentaar vb. Javadoc van triviale methods 102
  • 103. Slechte commentaar Log van wijzigingen is werk voor versiebeheersysteem! Commentaar als vervanging van goede variabele-/methodnaam Positiemarkeringen //---------- Accessors -------------------------- Commentaar bij sluiten accolade 103
  • 104. Slechte commentaar Vermeldingen auteurs Hoort in versiebeheersysteem Code in commentaar Vervuilt de code Wat is de intentie? Waarom in commentaar? Versiebeheer! HTML commentaar 104
  • 105. Slechte commentaar Niet-lokale informatie Teveel informatie Onduidelijke link met code Functie-headers Javadocs in niet-publieke code 105
  • 106. Naamgeving (CC2) Namen geven intentie bloot int d; // elapsed time in days Vermijd desinformatie private Person[] personList; kleine L (l of 1?), hoofletter O (O of 0?) Namen zijn uitspreekbaar 106
  • 107. Naamgeving Zinvol onderscheid tussen namen variabele niet verkeerd spellen om onderscheid te maken met andere, vb. class klass geen getalseries, vb. a1, a2, a3, redundante namen, vb. denominatorVariable Namen zijn zoekbaar hoe breder de scope, hoe langer de naam variabelen met 1 letter enkel lokaal in korte methods 107
  • 108. Naamgeving Vermijd coderingen Hongaarse notatie met type in de naam, vb. phoneString Member prefix voor onderscheid met functie- argumenten, vb. private int mNumerator; Interface prefix, vb. IShapeFactory Probeer niet grappig te zijn 108
  • 109. Naamgeving Consistent: 辿辿n woord per concept fetch retrieve get Controller Manager Driver Namen uit oplossingsdomein (vakjargon, patterns, wiskundige termen, ) Namen uit probleemdomein 109
  • 110. Naamgeving Klassenamen gebaseerd op zelfstandige naamwoorden, vb. Customer, WikiPage, AddressParser vermijd te algemene woorden als Manager, Processor, Data, Info, Controller geen werkwoord 110
  • 111. Naamgeving Methodnamen gebaseerd op werkwoorden accessors/mutators beginnen met get/set predicaten beginnen met is constructor overloading factory methods die argument beschrijven vb. Complex(double) Complex.fromRealNumber(double) 111
  • 112. En verder... 112
  • 113. Waarom de boeken nog lezen/kopen? Verschillende topics niet aan bod gekomen Concurrency (CC13 & appendix A, EJ10) Praktijkvoorbeelden refactoring (CC14, CC16) Smells and Heuristics (CC17) 113
  • 114. Bedankt! 114