Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Clean, effective java

1,047 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
  • Be the first to comment

  • Be the first to like this

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

×