changer pour mieux coder
DESCRIPTION
Live code by Rémy Sanlaville and Johan Martinsson at Agile Grenoble 2012TRANSCRIPT
Changer pour mieux coder
Règles pour améliorer son code source
Démo en live
Bonus : raccourcis clavier et astuces pour être plus productif
Ce que vous verrez
Ce que vous ne verrez pas Une mise en pratique du TDD (Test Driven
Development)
Bienvenue à notre réunion Développeurs Anonymes (DA)
Application
Magasin (Inn)
Articles (Items) dont la qualité se dégrade continuellement à l’approche de la date de péremption
vend
A chaque fin de journée, l’application met à jour la qualité de tous les articles (Inn.updateQuality())
SellIn = nombre de jour restant avant la date de péremption
Quality = correspond à la valeur de l’objetArticle (Item)
ApplicationSellIn = nombre de jour restant avant la date de péremption
Quality = correspond à la valeur de l’objetArticle (Item)
Une fois la date de péremption dépassée, la qualité se dégrade 2 fois plus vite.
“Aged Brie” = la qualité augmente avec le temps qui passe
“Sulfuras” = article légendaire dont la qualité ne décroit jamais et qui n’a pas de date de péremption.
“Backstage passes” = la qualité augmente avec le temps de la manière suivante :
6 ≤ sellIn ≤ 10 → la qualité augmente par 20 ≤ sellIn ≤ 5 → la qualité augmente par 3sellIn < 0 → la qualité = 0
La qualité n’est jamais négative et ne dépasse jamais 50 : 0 ≤ quality ≤ 50.
Contraintes
Entrainons-nous !
Emmanuel Chenu
9 règles pour votre gymnastique objet
1. Use one level of indentation per method
2. Don't use the else keyword
3. Wrap all primitives and strings
4. Use only one dot per line
5. Don't abbreviate
6. Keep all entities small
7. Don't use any classes with more than two instance variables
8. Use first class collections
9. Don't use any getters, setters or propertiesObject Calisthenics by Jeff Bay tiré du livre ThoughtWorks Anthology
1. Use one level of indentation per method
2. Don’t use the else keyword
Early Return
Utiliser une map
Polymorphisme
– Stratégie
– Null Object Empty lists
…
3. Wrap all primitives and strings
public class Money {
private Integer amountInCents;
public Money(Integer amountInCents) { this.amountInCents = amountInCents; }
[…]}
public class Discounter {
private Money discount;
[…]}
public class Discounter {
private Integer discount;
[…]}
4. Use only one dot per line
Loi de Demeter« Ne parlez pas aux inconnus »
5. Don’t abbreviate
Répétition signifie souvent un concept commun à faire émerger
6. Keep all entities small
Pas de classe > 50 lignes
Pas de paquet > 10 classes
« Single Responsibility Principle »
7. Don't use any classes with more than two instance variables
Cohésion
Emergence de model à grain fin
Ex OrangeForge : User & Project => Permissions?
8. Use first class collections
Le pendant Wrap all primitives
Centralise traitements sur la collection
9. Don't use any getters, setters or properties
q.setQuality(q.getQuality() - 1);
q.decrease();
q.quality = 0; q.dropToZero();
« Tell don’t ask »
Bilan
Nécessité des tests pour le refactoring.
Règles 2. Don't use the else keyword3. Wrap all primitives and strings9. Don't use any getters, setters or properties
cela a été une aide
code plus lisible, maintenable et évolutif
Acteurs
Johan MARTINSSONIndépendant [email protected]@johan_alps
Le Parrain
Rémy SANLAVILLEDéveloppeur [email protected]@sanlaville
Le Filleul
Discussions
Update Quality for BackstageUpdate Backstage
passes[sellIn ≥ 11]
qualité += 1
Cas 1
Update Quality for BackstageUpdate Backstage
passes[sellIn ≥ 11]
qualité += 1
Cas 1
Update Quality for BackstageUpdate Backstage
passes[sellIn ≥ 11]
qualité += 1
Cas 1
[10 ≥ sellIn ≥ 6]qualité += 2
Cas 2
[5 ≥ sellIn ≥ 0]qualité += 3
Cas 3
[0 > sellIn]qualité = 0
Cas 4
Solution 1 : ifUpdate Backstage passes
[getSellIn() < 11]quality.increase();
if
quality.increase();
demo-live
Solution 1 : ifUpdate Backstage passes
[getSellIn() < 11]quality.increase();
if
quality.increase();
demo-live
Solution 1 : ifUpdate Backstage passes
[getSellIn() < 11]quality.increase();
if
quality.increase();
demo-live
Solution 1 : ifUpdate Backstage passes
[getSellIn() < 11]quality.increase();
if
[getSellIn() < 0]quality.dropToZero();
if
quality.increase();
[getSellIn() < 6]ifquality.increase();
setSellIn(getSellIn() - 1);
demo-live
Solution 2 : if - elseUpdate Backstage passes
Tag : backstageWithElseIf
[daysBefore > 10]quality.increaseBy(1)
if
Solution 2 : if - elseUpdate Backstage passes
Tag : backstageWithElseIf
[daysBefore > 10]quality.increaseBy(1)
if
Solution 2 : if - elseUpdate Backstage passes
Tag : backstageWithElseIf
[daysBefore > 10]quality.increaseBy(1)
if
[daysBefore > 5]quality.increaseBy(2)
else if
[daysBefore > 0]quality.increaseBy(3)
else if
quality.resetToZero()
else
Solution 3 : Range MapUpdate Backstage passes
Tag : rangeMap
strategies = new TreeMap<Integer, IncreaseStrategy>() {{ put(Integer.MIN_VALUE, new ResetToZero()); put(0, new IncreaseBy(3)); put(5, new IncreaseBy(2)); put(10, new IncreaseBy(1));}};
Initialisation de la Map
Solution 3 : Range MapUpdate Backstage passes
Tag : rangeMap
strategies = new TreeMap<Integer, IncreaseStrategy>() {{ put(Integer.MIN_VALUE, new ResetToZero()); put(0, new IncreaseBy(3)); put(5, new IncreaseBy(2)); put(10, new IncreaseBy(1));}};
Initialisation de la Map
Solution 3 : Range MapUpdate Backstage passes
Tag : rangeMap
strategies = new TreeMap<Integer, IncreaseStrategy>() {{ put(Integer.MIN_VALUE, new ResetToZero()); put(0, new IncreaseBy(3)); put(5, new IncreaseBy(2)); put(10, new IncreaseBy(1));}};
Initialisation de la Map
Récupération de la stratégiestrategies.lowerEntry(daysBefore).getValue();
Appliquer la stratégie
strategy().applyTo(quality);
Solution 4 : DSLUpdate Backstage passes
Tag : backstageUpdateDSL
quality.doIncreaseBy(1).when(daysBefore, greaterThan(10));
Solution 4 : DSLUpdate Backstage passes
Tag : backstageUpdateDSL
quality.doIncreaseBy(1).when(daysBefore, greaterThan(10));
Solution 4 : DSLUpdate Backstage passes
Tag : backstageUpdateDSL
quality.doIncreaseBy(1).when(daysBefore, greaterThan(10));
quality.doIncreaseBy(2).when(daysBefore, between(5, 10));
quality.doIncreaseBy(3).when(daysBefore, between(0, 5));
quality.doResetToZero().when(daysBefore, lessThanOrEqualTo(0));
Conclusion
Les règles peuvent-être vues comme une chance pour sortir du cadre et réfléchir autrement plutôt que comme des contraintes.
Pour s’améliorer, il faut savoir prendre du temps pour s’exercer.
En savoir plus
Thoughtworks Anthology by PragProg http://pragprog.com/book/twa/thoughtworks-anthology
Object Calisthenicshttp://www.bennadel.com/resources/uploads/2012/ObjectCalisthenics.pdf
How object oriented are you feeling today? Krzysztof Jelski - Software Craftsmanship 2011 Conference http://fr.slideshare.net/KrzysztofJelski/how-object-oriented-are-you-feeling-today
LiensPlugins Eclipse
Infinitest (http://infinitest.github.com)MoreUnit (http://moreunit.sourceforge.net/)EclEmma (http://www.eclemma.org/)
Clipboard ManagerDitto (http://ditto-cp.sourceforge.net/)
Code sous GitHub
https://github.com/sanlaville/AgileGrenoble2012.githttps://github.com/martinsson/AgileGrenoble2012.git
Ctrl + 1
Raccourcis clavier Eclipse
Alt + Shift + T
N’oubliez pas de remplir les feedbacks !