Clean, effective java

869 views
768 views

Published on

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

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
869
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Clean, effective java

  1. 1. Clean, effective Java Bert Van Vreckem
  2. 2. 2
  3. 3. ? 3
  4. 4. (TODO) 4
  5. 5. 5
  6. 6. 6
  7. 7. Josh Bloch 7
  8. 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. 9
  10. 10. Robert Uncle Bob Martin 10
  11. 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. 12. Wat is “heldere” code? 12
  13. 13. Doel:● Disseminatie● Discussie● FeedbackPS. Koop de boeken! (vakgroepbib?) 13
  14. 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. 15. Onderwerpen Klassen Functies Unit tests Ontwerp Stijl 15
  16. 16. Klassen 16
  17. 17. Klassen● EJ4 “Classes and Interfaces”● CC6 “Objects and Data Structures”● CC10 “Classes” 17
  18. 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. 19. Beperk “mutability” (EJ#15)● Geen mutators● Laat geen overerving toe● Alle velden final● Alle velden private● Geen toegang tot wijzigbare componenten 19
  20. 20. Voorbeeld: Breukenpublic class Fraction { public int numerator; public int denominator;} 20
  21. 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(); } ... 21}
  22. 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();} 22
  23. 23. Breuken: rekenenpublic 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. 24. Onveranderlijke Breukenpublic 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. 25. Of misschien zelfspublic 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. 26. Terzijde: hetzelfde in Scala ;-)class Fraction(val numerator: Int, val denominator: Int) 26
  27. 27. Rekenen met onveranderlijke breukenpublic 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. 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! 28
  29. 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. 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. 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. 32. Defensieve kopiepublic Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime());} 32
  33. 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. 34. Immutability – nadelen● Veel objecten aanmaken ● op te lossen, bv. met static factories (zie verder) 34
  35. 35. Is doorgedreven “immutability” mogelijk / wenselijk? 35
  36. 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. 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. 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
  39. 39. Niet-hierarchische typeframeworks 39
  40. 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
  41. 41. Simulated Multiple Inheritance 41
  42. 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. 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. 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, das geen OO! 44
  45. 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. 46. public class Circle implements Shape { private Point center; private double radius; @Override public double area() { return Math.PI * radius * radius; }} 46
  47. 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. 48. Is de “procedurele” aanpak uit het vorige voorbeeld soms toelaatbaar/aangewezen? 48
  49. 49. Functies 49
  50. 50. Functies / methods● CC3 Functions● EJ2 Creating and destroying objects● EJ3 Methods common to all objects● EJ5 Methods 50
  51. 51. Functies mogen maar één ding doen Ze moeten dat goed doen Ze mogen alleen dat doen 51
  52. 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. 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. 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)● Dont repeat yourself 54
  55. 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. 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. 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. 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. 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. 60. Creëren van objecten (EJ2)● Builder pattern: voor constructors met ● teveel parameters ● optionele/default parameters ● verschillende parameters van zelfde type 60
  61. 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. 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. 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);} 63
  64. 64. Client codeFarm farm = new Farm.Builder() .withFarmName("Carlokes") .withPlayerName("René") .withStartBudget(1_000.00) .withGridWidth(5) .build(); 64
  65. 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. 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. 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. 68. Recept voor equals(Object o)1.Controleer of o referentie naar dit object is ● zo ja true2.Controleer met instanceof of o het correcte type heeft, ● zo niet false ● zo ja, casten naar juiste type3.Controleer of elk “significant” attribuut van o overeenkomt met het corresponderende attribuut van dit object 68
  69. 69. vb. Fraction (gegenereerd door Eclipse!)@Overridepublic 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. 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. 71. Recept voor hashCode()● cfr. boek● gebruik door Eclipse gegenereerde hashCode() 71
  72. 72. vb. Fraction@Overridepublic int hashCode() { final int prime = 31; int result = 1; result = prime * result + denominator; result = prime * result + numerator; return result;} 72
  73. 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. 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. 75. hashCode(), equals() en toString() in Scala ;-) case class Fraction( val numerator: Int, val denominator: Int) 75
  76. 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. 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. 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. 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. 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. 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
  82. 82. Unit tests 82
  83. 83. 3 wetten van Test Driven Development (CC9)1. Schrijf geen productiecode vóór een mislukkende unit test2. 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. 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. 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. 86. Ontwerpen 86
  87. 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. 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. 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. 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. 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. 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. 93. Intentie vs implementatiedef slim_to_ruby_method(method_name) camel_to_underscore(method_name)enddef to_file_name(module_name) camel_to_underscore(module_name)enddef 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. 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. 95. Expressiviteit● Voldoende aandacht besteden hieraan ● Niet verder doen met iets anders zodra het “werkt”● Fierheid over je vakmanschap 95
  96. 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. 97. Stijl 97
  98. 98. Commentaar (CC4)● Commentaar is geen oplossing voor slechte code● Druk je intentie uit in code 98
  99. 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. 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. 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. 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. 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. 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. 105. Slechte commentaar● Niet-lokale informatie● Teveel informatie● Onduidelijke link met code● Functie-headers● Javadocs in niet-publieke code 105
  106. 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. 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. 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. 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. 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. 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. 112. En verder... 112
  113. 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. 114. Bedankt! 114

×