View
751
Download
1
Category
Preview:
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
Clean, effective Java
Bert Van Vreckem
2
3
?
4
(TODO)
5
6
7
Josh Bloch
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)
9
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
12
Wat is “heldere” code?
13
Doel:
● Disseminatie● Discussie● Feedback
PS. Koop de boeken! (vakgroepbib?)
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
15
Onderwerpen
Klassen
Functies
Unit tests
Ontwerp
Stijl
16
Klassen
17
Klassen
● EJ4 “Classes and Interfaces”● CC6 “Objects and Data Structures”● CC10 “Classes”
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
19
Beperk “mutability” (EJ#15)
● Geen mutators● Laat geen overerving toe● Alle velden final● Alle velden private● Geen toegang tot wijzigbare componenten
20
Voorbeeld: Breuken
public class Fraction {
public int numerator; public int denominator; }
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(); } ...}
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();}
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();}
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; }}
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; }}
26
Terzijde: hetzelfde in Scala ;-)
class Fraction(val numerator: Int, val denominator: Int)
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);}
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!
29
Wijzigbare componenten
● Geef individuele elementen terug, vb. public Field getField(int row, int col) { return fields[row][col]; }
● Maak een “defensieve kopie”
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; }}
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());
32
Defensieve kopie
public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime());}
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
34
Immutability – nadelen
● Veel objecten aanmaken● op te lossen, bv. met static factories (zie verder)
35
Is doorgedreven “immutability”mogelijk / wenselijk?
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
37
Waarom?
● Overerving breekt encapsulatie● Subklassen hangen af van implementatie superklasse
● Superklasse wijzigen problemen in subklassen● Compilatie● Verkeerd gedrag● Beveiligingsproblemen
● Oplossing: “wrapper class”
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
39
Niet-hierarchische typeframeworks
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
41
Simulated Multiple Inheritance
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
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;}
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!
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; }}
46
public class Circle implements Shape { private Point center; private double radius; @Override public double area() { return Math.PI * radius * radius; }}
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
48
Is de “procedurele” aanpak uit het vorige voorbeeld soms toelaatbaar/aangewezen?
49
Functies
50
Functies / methods
● CC3 Functions● EJ2 Creating and destroying objects● EJ3 Methods common to all objects● EJ5 Methods
51
Functies mogen maar één ding doenZe moeten dat goed doenZe mogen alleen dat doen
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
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
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
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
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)
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;}
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
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()
60
Creëren van objecten (EJ2)
● Builder pattern: voor constructors met● teveel parameters● optionele/default parameters● verschillende parameters van zelfde type
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();}
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); }}
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);}
64
Client code
Farm farm = new Farm.Builder() .withFarmName("Carlokes") .withPlayerName("René") .withStartBudget(1_000.00) .withGridWidth(5) .build();
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
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()
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
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
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; }
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
71
Recept voor hashCode()
● cfr. boek● gebruik door Eclipse gegenereerde hashCode()
72
vb. Fraction
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + denominator; result = prime * result + numerator; return result; }
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;}
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
75
hashCode(), equals() en toString() in Scala ;-)
case class Fraction( val numerator: Int, val denominator: Int)
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
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
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
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(); }
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
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
82
Unit tests
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
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!
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
86
Ontwerpen
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”
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
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
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?
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
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
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
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
95
Expressiviteit
● Voldoende aandacht besteden hieraan● Niet verder doen met iets anders zodra het “werkt”
● Fierheid over je vakmanschap
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
97
Stijl
98
Commentaar (CC4)
● Commentaar is geen oplossing voor slechte code● Druk je intentie uit in code
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;}
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
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; }
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
103
Slechte commentaar
● “Log” van wijzigingen● is werk voor versiebeheersysteem!
● Commentaar als vervanging van goede variabele-/methodnaam
● Positiemarkeringen//---------- Accessors --------------------------
● Commentaar bij sluiten accolade
104
Slechte commentaar
● Vermeldingen auteurs● Hoort in versiebeheersysteem
● Code in commentaar● Vervuilt de code● Wat is de intentie? Waarom in commentaar?● Versiebeheer!
● HTML commentaar
105
Slechte commentaar
● Niet-lokale informatie● Teveel informatie● Onduidelijke link met code● Functie-headers● Javadocs in niet-publieke code
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
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
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
109
Naamgeving
● Consistent: één woord per concept● fetch retrieve get↔ ↔● Controller Manager Driver↔ ↔
● Namen uit oplossingsdomein (vakjargon, patterns, wiskundige termen, …)
● Namen uit probleemdomein
110
Naamgeving
● Klassenamen● gebaseerd op zelfstandige naamwoorden, vb.
Customer, WikiPage, AddressParser● vermijd te algemene woorden als Manager,
Processor, Data, Info, Controller● geen werkwoord
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)
112
En verder...
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)
114
Bedankt!
Recommended