114
Clean, effective Java Bert Van Vreckem

Clean, effective java

Embed Size (px)

DESCRIPTION

In deze presentatie die ik gaf aan collega's, licht ik enkele topics toe uit deze boeken: - Robert C. Martin, Clean Code - Joshua Bloch, Effective Java

Citation preview

Page 1: Clean, effective java

Clean, effective Java

Bert Van Vreckem

Page 2: Clean, effective java

2

Page 3: Clean, effective java

3

?

Page 4: Clean, effective java

4

(TODO)

Page 5: Clean, effective java

5

Page 6: Clean, effective java

6

Page 7: Clean, effective java

7

Josh Bloch

Page 8: Clean, effective java

8

Inhoud EJ (2nd Ed, 2008)

● Creatie objecten● Gemeensch. methods● Klassen en interfaces● Generieke klassen● Enums, annotaties● Methods

● Algemene programmeertips

● Foutafhandeling● Concurrency● Serialisatie

● 78 “items” (EJ#nn)

Page 9: Clean, effective java

9

Page 10: Clean, effective java

10

Robert 'Uncle Bob' Martin

Page 11: Clean, effective java

11

Inhoud CC(2009)

● Naamgeving● Functies● Commentaar● Formattering● Objecten &

datastructuren● Foutafhandeling● Grenzen

● Unit tests● Klassen● Systemen● “Emergent design”● Iteratieve verfijning● Refactoring case● Indicatoren van

slechte code

Page 12: Clean, effective java

12

Wat is “heldere” code?

Page 13: Clean, effective java

13

Doel:

● Disseminatie● Discussie● Feedback

PS. Koop de boeken! (vakgroepbib?)

Page 14: Clean, effective java

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

Page 15: Clean, effective java

15

Onderwerpen

Klassen

Functies

Unit tests

Ontwerp

Stijl

Page 16: Clean, effective java

16

Klassen

Page 17: Clean, effective java

17

Klassen

● EJ4 “Classes and Interfaces”● CC6 “Objects and Data Structures”● CC10 “Classes”

Page 18: Clean, effective java

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

Page 19: Clean, effective java

19

Beperk “mutability” (EJ#15)

● Geen mutators● Laat geen overerving toe● Alle velden final● Alle velden private● Geen toegang tot wijzigbare componenten

Page 20: Clean, effective java

20

Voorbeeld: Breuken

public class Fraction {

public int numerator; public int denominator; }

Page 21: Clean, effective java

21

Breuken: “Bean” patternpublic 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(); } ...}

Page 22: Clean, effective java

22

Breuken: hulpcodeprivate 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();}

Page 23: Clean, effective java

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();}

Page 24: Clean, effective java

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; }}

Page 25: Clean, effective java

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; }}

Page 26: Clean, effective java

26

Terzijde: hetzelfde in Scala ;-)

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

Page 27: Clean, effective java

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);}

Page 28: Clean, effective java

28

Wijzigbare componentenpublic 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!

Page 29: Clean, effective java

29

Wijzigbare componenten

● Geef individuele elementen terug, vb. public Field getField(int row, int col) { return fields[row][col]; }

● Maak een “defensieve kopie”

Page 30: Clean, effective java

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; }}

Page 31: Clean, effective java

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());

Page 32: Clean, effective java

32

Defensieve kopie

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

Page 33: Clean, effective java

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

Page 34: Clean, effective java

34

Immutability – nadelen

● Veel objecten aanmaken● op te lossen, bv. met static factories (zie verder)

Page 35: Clean, effective java

35

Is doorgedreven “immutability”mogelijk / wenselijk?

Page 36: Clean, effective java

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

Page 37: Clean, effective java

37

Waarom?

● Overerving breekt encapsulatie● Subklassen hangen af van implementatie superklasse

● Superklasse wijzigen problemen in subklassen● Compilatie● Verkeerd gedrag● Beveiligingsproblemen

● Oplossing: “wrapper class”

Page 38: Clean, effective java

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

Page 39: Clean, effective java

39

Niet-hierarchische typeframeworks

Page 40: Clean, effective java

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

Page 41: Clean, effective java

41

Simulated Multiple Inheritance

Page 42: Clean, effective java

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

Page 43: Clean, effective java

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;}

Page 44: Clean, effective java

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!

Page 45: Clean, effective java

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; }}

Page 46: Clean, effective java

46

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

Page 47: Clean, effective java

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

Page 48: Clean, effective java

48

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

Page 49: Clean, effective java

49

Functies

Page 50: Clean, effective java

50

Functies / methods

● CC3 Functions● EJ2 Creating and destroying objects● EJ3 Methods common to all objects● EJ5 Methods

Page 51: Clean, effective java

51

Functies mogen maar één ding doenZe moeten dat goed doenZe mogen alleen dat doen

Page 52: Clean, effective java

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

Page 53: Clean, effective java

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

Page 54: Clean, effective java

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

Page 55: Clean, effective java

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

Page 56: Clean, effective java

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 argumentvoid monad(Integer... args)void dyad(String name, Integer... args)

Page 57: Clean, effective java

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;}

Page 58: Clean, effective java

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

Page 59: Clean, effective java

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()

Page 60: Clean, effective java

60

Creëren van objecten (EJ2)

● Builder pattern: voor constructors met● teveel parameters● optionele/default parameters● verschillende parameters van zelfde type

Page 61: Clean, effective java

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();}

Page 62: Clean, effective java

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); }}

Page 63: Clean, effective java

63

Constructorsprivate 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);}

Page 64: Clean, effective java

64

Client code

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

Page 65: Clean, effective java

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

Page 66: Clean, effective java

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()

Page 67: Clean, effective java

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

Page 68: Clean, effective java

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

Page 69: Clean, effective java

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; }

Page 70: Clean, effective java

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

Page 71: Clean, effective java

71

Recept voor hashCode()

● cfr. boek● gebruik door Eclipse gegenereerde hashCode()

Page 72: Clean, effective java

72

vb. Fraction

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

Page 73: Clean, effective java

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;}

Page 74: Clean, effective java

74

Altijd toString() overschrijven (EJ#10)

● Klasse makkelijker te gebruikenvb. 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

Page 75: Clean, effective java

75

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

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

Page 76: Clean, effective java

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

Page 77: Clean, effective java

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

Page 78: Clean, effective java

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

Page 79: Clean, effective java

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(); }

Page 80: Clean, effective java

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

Page 81: Clean, effective java

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

Page 82: Clean, effective java

82

Unit tests

Page 83: Clean, effective java

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

Page 84: Clean, effective java

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!

Page 85: Clean, effective java

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

Page 86: Clean, effective java

86

Ontwerpen

Page 87: Clean, effective java

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”

Page 88: Clean, effective java

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

Page 89: Clean, effective java

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

Page 90: Clean, effective java

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?

Page 91: Clean, effective java

91

Intentie vs implementatie(RubySlim voorbeeld)

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

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

● “Slim” methodnaam naar Ruby methodnaam:

● “Slim” packagenaam omzetten naar bestandsnaam

http://www.informit.com/articles/article.aspx?p=1313447

Page 92: Clean, effective java

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

Page 93: Clean, effective java

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

Page 94: Clean, effective java

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

Page 95: Clean, effective java

95

Expressiviteit

● Voldoende aandacht besteden hieraan● Niet verder doen met iets anders zodra het “werkt”

● Fierheid over je vakmanschap

Page 96: Clean, effective java

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

Page 97: Clean, effective java

97

Stijl

Page 98: Clean, effective java

98

Commentaar (CC4)

● Commentaar is geen oplossing voor slechte code● Druk je intentie uit in code

Page 99: Clean, effective java

99

Goede commentaar

● Wettelijke bepalingen (vb. licentie, copyrigth)● Informatieve commentaar

● functienaam zegt het al!● bv. wél uitleg bij ingewikkelde regexp

// Returns the numerator of this Fraction.public int getNumerator() { return numerator;}

Page 100: Clean, effective java

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

Page 101: Clean, effective java

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; }

Page 102: Clean, effective java

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

Page 103: Clean, effective java

103

Slechte commentaar

● “Log” van wijzigingen● is werk voor versiebeheersysteem!

● Commentaar als vervanging van goede variabele-/methodnaam

● Positiemarkeringen//---------- Accessors --------------------------

● Commentaar bij sluiten accolade

Page 104: Clean, effective java

104

Slechte commentaar

● Vermeldingen auteurs● Hoort in versiebeheersysteem

● Code in commentaar● Vervuilt de code● Wat is de intentie? Waarom in commentaar?● Versiebeheer!

● HTML commentaar

Page 105: Clean, effective java

105

Slechte commentaar

● Niet-lokale informatie● Teveel informatie● Onduidelijke link met code● Functie-headers● Javadocs in niet-publieke code

Page 106: Clean, effective java

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

Page 107: Clean, effective java

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

Page 108: Clean, effective java

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

Page 109: Clean, effective java

109

Naamgeving

● Consistent: één woord per concept● fetch retrieve get↔ ↔● Controller Manager Driver↔ ↔

● Namen uit oplossingsdomein (vakjargon, patterns, wiskundige termen, …)

● Namen uit probleemdomein

Page 110: Clean, effective java

110

Naamgeving

● Klassenamen● gebaseerd op zelfstandige naamwoorden, vb.

Customer, WikiPage, AddressParser● vermijd te algemene woorden als Manager,

Processor, Data, Info, Controller● geen werkwoord

Page 111: Clean, effective java

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)

Page 112: Clean, effective java

112

En verder...

Page 113: Clean, effective java

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)

Page 114: Clean, effective java

114

Bedankt!