- first class collections (wrapper chaque collection une classe métier)
- one level of indentation
- no else statements (même pas dans les factories).
- Wrap all primitives and string in their own class
Algodeal tourne leurs 600 classes de test et 60 classes de tests fonctionnels/intégration en moins de 4 minutes!! David n'est pas allé dans le détail des métriques, mais cela couvrirait 60.000 lignes de code.Ca fait quelque temps que j’utilise des frameworks avec une interface fluide (cf Martin Fowler Fluent Interface). Je pense à Mockito, JMock2 et Hibernate Query API entre autres. Depuis peu j’utilise fréquemment le Test Data Builder Pattern. Ces derniers sont plutôt des Domain Specific Languages, une version évoluée des interfaces fluides. Mais je n’avais jamais réalisé que ce soit un jeu d’enfant de créer sa propre interface fluide. Prenons par exemple
Math.pow(3, 2)
exponent(3).of(2)
class Exponent {
private final double exponent;
public Exponent(double exponent) {
this.exponent = exponent;
}
public static Exponent exponent(double exponent) {
return new Exponent(exponent);
}
public double of(double base) {
return Math.pow(base,exponent);
}
}
import static Exponent.exponent;
new Exponent(3).of(2)
//ou
Exponent.exponent(3).of(2)
private String digitAtPosition(int pos, int tenBaseNumber) {
int nextPos = pos+1;
long remainderOfNextPos = tenBaseNumber % nthPowerOfBase(nextPos);
long digitInTenBase = remainderOfNextPos / nthPowerOfBase(pos);
return convertSingleDigit(digitInTenBase);
}
protected final long nthPowerOfBase(int n) {
return round(pow(base,n));
}
private String digitAtPosition(int pos, int tenBaseNumber) {
int nextPos = pos+1;
long remainderOfNextPos = tenBaseNumber % exponent(nextPos).of(base);
long digitInTenBase = remainderOfNextPos / exponent(pos).of(base);
return convertSingleDigit(digitInTenBase);
}
Et si le besoin de rapidité apparait, il y a plusieurs façons d’attaquer le problème, revenir en arrière, ou introduire un cache des objets crées, ou en modifiant l’interface un poil :
exponent(3, of(2))
...
public static double of(double number) {
return number;
}
class Exponent {
double exp;
public static Exponent exponent(final double exponent) {
return new Exponent() {{
this.exp = exponent;
}};
}
public double of(double base) {
return Math.pow(base,exp);
}
}
class FluidMaths {
public static Exponent exponent(final int exponent) {
return new Exponent() {
public Long of(int base) {
return round(pow(base,exponent));
}
};
}
interface Exponent {
public Long of(int base);
}
}
Les rétrospectives dans l’équipe dans laquelle je travaille laissent beaucoup de place à l’amélioration : En fin de sprint de deux semaines on fait un tour de table pour avancer les points positifs et les points d’amélioration. Point.
On était deux dans l’équipe à souhaiter quelque chose de plus ambitieux. Alors on s’était renseigné pour avoir une personne extérieure à l’équipe, voire un coach. Pour divers raisons rien s'était passé en six semaines, alors on a décidé d’améliorer ce que nous avions déjà avec les moyens du bord. Le déclencheur a sans doute été notre présence à XP Days Suisse où nous avons assisté à une session sur les rétrospectives (compte rendu de Bruno Orsier, Luc Jeanniard)
Nous avons commencé par revoir la dernière rétrospective pour savoir s’il y avait des points importants qui n’avaient pas été adressés. Ensuite nous avons conduit la rétrospective comme avant.
Au lieu de laisser les points d’amélioration cachés dans une page au fond d’une application quelque part, nous avons priorisé les points. Chacun pouvait voter pour les deux points qu’il trouvait les plus important. L’engagement était de faire quelque chose pour les 2-3 points les plus importants dans le sprint suivant. Voici nos points :
Le point 3 étant très simple nous l’avons simplement fait le lendemain.
Pour améliorer la phase de déploiement nous avons décidé d’actions concrètes :
Ces deux actions ont été planifiées dans le sprint AVEC une priorité importante – afin d’être sûr qu’elles seront adressées.
Finalement pour adresser le premier point nous avons discuté avec tous les acteurs concernés afin d’établir un plan d’action. Le voici :
Avec des améliorations ultra simples nous allons, je pense, tirer beaucoup plus des rétrospectives qu’auparavant. C’est tellement simple que j’avais l’impression que c’était bête d’en blogger, mais à mon avis cette équipe n’est pas la seule à faire des rétrospectives bâclées. Et cette expérience montre que même avec peu de moyens en temps et en connaissance on peut faire des améliorations importantes.
Prochaines étapes :
J’aime beaucoup le feedback rapide que donne les plugins PMD, Checkstyle et Findbugs dans Eclipse. Mais il y avait certains freins à l’utilisation:
Une solution est de centraliser les règles de à travers Sonar permettant ainsi de maintenir un seul ensemble de règles. Ce que je décris ici est une suite à un billet sur Checkstyle par Freddy Mallet.
Installer les plugins CheckStyle, FindBugs et PMD
Dans Sonar aller dans Configuration => Quality Profiles. L'onglet Permalinks copier les liens vers les règles PMD/CheckStyle/Findbugs pour chacun des profiles.
Dans Eclipse => Menu Window => Preferences :
Petit plus. Je trouve les règles Checkstyle dans le profil par défaut de Sonar beaucoup plus pertinentes que celles livrées avec le plugin pour Eclipse.
Depuis peu un plugin sonar pour eclipse est disponible.
Edit 2011-04-07 :
- mis à jour l'endroit dans sonar où on trouve les liens des profiles
- ajout lien plugin sonar