Slides remis en forme d'une conférence "Coder propre" afin de montrer que c'est possible, à la portée de chacun et, surtout, INDISPENSABLE pour profiter de son code !
Bref, l'idée est de convaincre et de donner les premières pierres pour que tout un chacun puisse construire son paradis :)
3. Raisons traditionnelles
● On lit + le code qu'on ne l'écrit
● Évolutivité de l'application
● Développer la prochaine version plutôt que de corriger
l'actuelle
● Respecter la norme ou les règles de développements
imposées
5. Code sale...
● fragile
● compliqué
● plein de (mauvaises) surprises
● effets de bord inattendus
● duplication
● illisible
● peu performant
● dur à améliorer
● ...
6. Dégâts perceptibles à tous les niveaux
● Chaque évolution est une nouvelle galère
● Développement laborieux, répétitif et aléatoire
● Délais et surprises pour la moindre modification (gestion
de projet peu agréable)
● Expérience utilisateur mauvaise (régressions & bugs
fréquents)
7. Le code sale tue...
● Les développeurs qui s'arrachent les cheveux..
● Les produits quand on ne parvient plus à les maintenir ou
faire évoluer.
● Les entreprises derrière tout cela..
La réécriture complète n'est pas la solution :
● absence de nouvelles fonctionnalités pendant l'intervalle,
● recommencer pareil donnera la même chose,
● l'existant est certainement plus riche que vous ne le
pensez..
● La concurrence sera bien plus loin d'ici là.
8. Coder propre ou ne pas faire d'informatique !
=> coder propre : voie de salut pour le développeur, la
gestion de projet et les utilisateurs
9. Comment ?
Savez vous coder propre ?
Coder sale n'apprend pas comment coder propre...
10. Faire complexe est facile, faire simple est difficile.
Situation paradoxale.
Mais la complexité se paie très vite...
11. De l'envie et le reste suivra !
Nécessité d'envie du développeur : il est seul face au
clavier !
Se poser des questions sur code, réfléchir, essayer…
Mais aussi :
Discuter, lire, écouter !
12. You can't dictate software quality -- quality
development has to be grown.
Bruce Eckel
Le code propre ne s'impose pas. Il s'apprend, se nourrit et
se développe.
C'est un travail d'équipe qui nécessite l'adhésion (ou la
prise de conscience) de tous.
Les chefs de projet sont généralement bien plus réceptifs
qu'on ne le croit : dur de faire pire bien souvent...
13. De l'engrais intellectuel pour démarrer !
Maintenant que la nécessité de code propre est partagée
(espérons!), voyons pour aider à son démarrage.
Attention : des pistes, des conseils, pas de dogmes
religieux.
Chaque langage/framework/équipe/développeur a ses
propres bonnes pratiques : se renseigner, discuter et se
mettre d'accord avec son équipe.
14. Pour commencer… on se détend !
La suite évoque des pistes, des conseils, pas de dogmes
religieux.
Il n'y a pas de définition précise du code propre.
Chaque langage/framework/équipe/développeur a ses
propres bonnes pratiques : se renseigner, discuter et se
mettre d'accord avec son équipe.
A chacun de trouver sa voie.
15. Juste des exemples
Exemples de code à venir : mise en avant de points, pas
code parfait...
Utilisation fréquente des termes « Foo » et « Bar », pour
se concentrer sur le code et non le fonctionnel. Par
exemple :
public class Foo {
public Bar doBar() {
return new Bar();
}
}
(snip) : indique que plein de code non relevant pour
l'exemple devrait être présent
=> on ne sait rien du fonctionnel, on peut parler du code
18. // @author setUpYourName
public class BadCodeWithComments {
private Bar var1 ;
/** Takes a bar then foo **/
public void foo() {
// on testte l'état
if( var1.state == null ||
var1.state == 0
/* foo.state == 1 || */
) {
(snip)
}
}
}
Auteur du code : manifestement faux, inutile, n'apporte rien.
Le commentaire sur la méthode semble référer à une
version antérieure, car évoque un argument plus présent.
Le commentaire sur le test décrit le détail du test : aucune
valeur ajoutée. Faute de français : distraction en plus...
Noms et valeurs d'aucune aide : var1, state, entier 0 et 1...
Génériques, interchangeables à volonté => vides de sens :
on ignore de quel « state » on parle ainsi que le sens des
valeurs testées
Qu'indique la ligne commentée ci dessous ?
/* foo.state == 1 || */
La valeur 1 n'est plus présente ?
La valeur 1 n'est plus à tester ?
Quelqu'un a fait un test et a oublié de dé commenter ?
=> soulève de nombreuses questions, alors qu'elle ne fait
rien !!
19. Mort aux commentaires !
Le moins possible de commentaires
● Signes d'un manque d'expressivité du code
● Faciles à bâcler, dur à écrire proprement, quasi
impossible à maintenir
- commentaires alors trompeurs et erronés
● Ne PAS commenter le code modifié
- on a un gestionnaire de source pour cela
On réessaie
20. public class BadCode {
private Bar var1 ;
public void foo() {
if( var1.state == null ||
var1.state == 0
) {
(snip)
}
}
}
On voit plus vite qu'on ne voit rien...
21. Des commentaires ne sauvent pas du mauvais
code.
Tentative d'expliciter très dure à réaliser
S'attaquer à la cause plutôt que de tenter de l'enjoliver
23. public class BetterCode {
private Bar last;
public void foo() {
if (last.isInProgress()) {
(snip)
}
}
}
Nommage explicite des classes, méthodes et variables
Pas de « bruit » inutile.
Bon niveau de détail :
● si on veut savoir comment est fait le test, on va voir
dans la méthode.
● Sinon on peut continuer à explorer le code actuel sans
surcharge cognitive.
Et aucun commentaire :)
26. Le pourquoi pas le comment
-
Le code indique le comment
Dans tout ce qu'on utilise indiquer le pourquoi (une liste,
des noms) plutôt que le comment (une liste chainées, des
chaines de caractères).
Le code permet toujours de voir le comment (quelque part).
Pas le pourquoi.
Evite également les redites et donc le risque de décalage à
terme.
28. Nommer même si court
● Même une méthode d'une ligne est mieux
● Petites méthodes bien plus réutilisables
● Méthodes surchargeables…
● Méthode évolutive
30. Faciliter la lecture
-
Pas de double négation
Un ordinateur parvient à lire de l'assembleur : on code pas
pour lui mais pour les autres humains.
Aussi, le code doit pouvoir être lu.
Par exemple nommer positivement est préférable à la
double négation
32. Faciliter la prononciation
-
Noms longs pas un problème
Le code lu est une bonne chose, mais c'est encore mieux
quand on en discute. Pour cela, on doit pouvoir prononcer
les éléments du code.
Si plus clair, recherche également plus aisée.
34. Acronymes en camel case
-
Facilite la recherche via l'IDE
Plus lisible
La convention Sun/Oracle et Microsoft
Permet la recherche de type dans l'éditeur via camel case :
FXD → FoXmlData
Sinon :
FOXMLD → FOXMLData
Ne « crie » pas au milieu code
36. Typer
Les entiers sont communément utilisés : si vous voyez un
entier quelque part, cela sera t il pour autant l'identifiant
que vous cherchez ?
Si l'identifiant a des contraintes particulières, impossible de
le voir avec un entier : besoin de regarder autour/en base
pour comprendre les valeurs autorisées et le
fonctionnement.
A l'inverse, une classe dédiée :
● permet de voir tous les usages de l'identifiant en
question (via les références dans le code)
● Permet d'aisément ajouter ou supprimer des
comportements
● N'importe où dans le code où ce type est présent, on
sait de suite de quoi il s'agit ou, au pire, il suffit d'aller
voir la classe en question pour avoir le détail
44. public void doStuff() {
(snip)
sendEmail("admin@acme.com", "Stuff done",
"Details");
}
private void sendEmail(String to, String subject, String
text) {
String from = "system@acme.com";
String host = "smtp.acme.com";
Properties props = new Properties();
props.put("mail.smtp.host", host);
Session session = Session.getInstance(props);
Message msg = new MimeMessage(session);
(snip)
Transport.send(msg);
}
2 choses différentes au même endroit : le but initial de la
classe, doStuff, et l'envoi de mail
Conséquences
● Longueur de la classe
● Détails et mises en œuvre très différents
Plein de problèmes latents :
● Réutilisation difficile
● Changements difficiles car plein de valeurs codées en
dur
● Si le code de l'envoi de mail est copié ailleurs, sera t il
bien iso fonctionnel ?
● Quid en cas d'erreur/exception lors de l'envoi du mail ?
Impacts sur doStuff() ?
=> mauvais
45. private final Mailer mailer;
public Good(Mailer mailer) {
this.mailer = mailer;
}
public void doStuff() {
(snip)
mailer.sendEmail("admin@acme.com", "Stuff done",
"Details");
}
Rendre indépendant au maximum les différents modules
les uns des autres
● le service d'envoi de mail ne doit faire que ça, sans
dépendre ou appliquer des logiques relevant d'autres
choses
● Pas de logique en fonction du contexte (utilisateur
courant par exemple)
● Utilisation possible du service en dehors d'un contexte
web
=> Augmente la réutilisation
Se concentrer sur l'essentiel d'une fonctionnalité permet de
la traiter correctement
● Notamment le traitement des cas d'erreurs
● En proposant différentes méthodes correspondant aux
différents besoins d'appels
=> meilleur
46. Faire une chose à la fois
-
Permet de faire une fois bien
Lorsqu'on ne duplique pas la même chose plusieurs fois,
on n'a qu'un seul endroit à améliorer pour améliorer tous
les usages de la chose en question.
Qui plus est, en faisant une fois, on est plus incité à faire
bien, alors qu'une recopie de plus n'incite guère à l'effort.
Au demeurant, toutefois, il n'est pas nécessaire de faire
forcément mieux qu'on aurait fait initialement. En effet, une
énorme valeur ajoutée est de pouvoir faire mieux plus tard,
lorsqu'on aura commencé à rencontrer des problèmes.
47. private final Notifier notifier;
public Better(Notifier notifier) {
this.notifier = notifier;
}
public void doStuff() {
(snip)
notifier.notify(userAcme, "Details", "Stuff done");
}
48. Découpler
-
Tant entre classes que de l'implémentation
Bien réfléchir au nommage et au périmètre des services
● L'envoi de mails n'est qu'une des façons de notifier
● L'idée était de notifier, pas d'envoyer un mail
● Permet de généraliser : on passe désormais
l'utilisateur et non plus directement l'adresse
Ne pas hésiter à séparer la déclaration de l'implémentation
● Initialement peut être que seul l'envoi de mail marche
● Distingue bien le comment du pourquoi
=> encore meilleur
49. Le code doit être auto descriptif
Etat d'esprit de ce qui a été présenté.
Tout doit tendre vers cela.
50. final String CHRISTMAS_DAY = "25/12";
final String NEW_YEAR_DAY = "01/01";
final String FRENCH_NAT_DAY = "14/07";
final String workersDay = "1/1";
Quelle ligne a ajouté le nouveau venu dans l'équipe ?
51. Respecter le style en vigueur
Uniformité du style => lecture plus aisée
Code résultat d'une action collective
● par défaut, respecter le style en place
● si besoin, discuter et décider en équipe du nouveau
style et des modalités de transition
Evite de se faire haïr... et accessoire : le style en vigueur
n'a pas d'effet sur la qualité du code.
52. Commenter uniquement en dernier recours
Mettre des commentaires quand toutes les tentatives pour
rendre intelligible le code ont échoué.
C'est par exemple souvent requis pour des contraintes
externes.
De même une explication générale est souvent dure à
rendre uniquement par le code, même si cette explication
générale ne retire rien à bien nommer son API, des
méthodes aux exceptions.
54. Refactoring
-
Renommer, extraire avec l'IDE
Actualiser le code existant
● noms mis à jour
● évolutions de la structure même si besoin
=> le code doit refléter l'état actuel des connaissances
métier
Pas de connaissance en dehors du code
59. De la première ligne après 1000 lignes...
Lors de tests manuels de son code, on exécute les bouts
qu'on vient d'écrire.
Aussi, on exécute au début le code initial, mais comment
s'assurer à la fin que ce dernier soit toujours fonctionnel ?
63. Etre le premier utilisateur de son code
Soyez le premier utilisateur de votre code via les tests
● Avant même que le code ne soit écrit : permet de voir
si l'utilisation correspond aux attentes
● Changer d'avis ne coute alors rien !
64. Améliore le code
Tester son code implique de s'en servir dans un contexte
un peu différent que celui de son exécution normale.
Aussi, cela nous amène souvent à découpler et rendre le
code modulaire, ce qui est un gage de pérennité.
79. Tests de performance
-
L'optimisation prématurée est la source de tous
les maux.
(Premature optimization is the root of all evil)
-
Tester quand tout va bien
Les problèmes de performances doivent être avérés,
mesurés et reproductible avant leur correction.
Bien cibler un problème de performance est primordial pour
le régler (cf outils comme JMH).
Bien souvent nos hypothèses concernant les causes de
problèmes de performances sont fausses ou non
déterminantes. La réalité est bien plus complexe, le
fonctionnement des systèmes actuels bien plus riches que
nous le supposons..
A l'inverse, tant qu'aucun problème n'est présent prendre
divers raccourcis sous prétexte de performance au
détriment du code propre n'est qu'une excuse.
Enfin, tester les performances en non régression permet de
voir au plus tôt l'introduction de code pénalisant celles ci.
82. Maîtrisez votre IDE !
Votre IDE peut faire beaucoup, apprenez ses capacités,
notamment :
● génération de code
● via des templates pour des éléments récurrents (le
logger par exemple)
● en écrivant un code minimal, qui ne compile pas, et
en le laissant créer le reste
● découverte/lecture du code
● liste des appelants
● références
● hiérarchie des classes
● propositions de refactoring
● renommage & déplacements
● création de méthode
● formatage automatique
● plus simple pour relire le code du collègue
● analyse de la qualité du code
Surtout : apprenez ses raccourcis pour être efficace
84. Première loi de la qualité logicielle
errors = (more code)2
e=mc2
Moins il y a de code à maintenir, mieux c'est
Du code non fréquemment exercé tend à devenir
rapidement obsolète ou contenir des erreurs
Mieux peu qui tourne que beaucoup qui plante
85. 2000 options de configuration
vs
code facile à modifier
But : avoir du code simple facile à changer, pas du code
complexe "qui fait tout" dur à modifier.
Les besoins de demain seront différents des prévisions
d'aujourd'hui
Eviter les usines à gaz de paramétrage avec 2000 choix,
mais (généralement) pas celui désiré
Si code propre, alors modification aisée.
=> KISS (Keep It Simple Stupid)
Les 2000 options sont autant d'aveux de faiblesse quant au
comportement que doit avoir le logiciel.
86. Egoless programming
Critique du code != critique de soi
=> les discussions et critiques autour du code sont
primordiales. Elles ne doivent pas être prises comme des
attaques personnelles.
Etre accessible et prêt à discuter
87. Règle du Boy Scout
Laisser le code plus propre qu'en arrivant
Préoccupez vous du code !
88. Améliorer le métier du client
Objectif d'un codeur ?
- Coder ?
- Livrer un ensemble de code cohérent ?
- Livrer un produit, incluant sa vie opérationnelle ?
- Améliorer le métier du client ?
Améliorer le métier du client est la seule façon d'apporter
de la valeur via le code. Et est crucial pour un éditeur !
90. Coût du coder propre
Coût intellectuel
● Remise en cause
● Changement
Coût initial
● Premières lignes codées propres laborieuses
● Beaucoup de réflexions (salutaire)
Coût au quotidien
● Léger surcoût au premier dév d'une fonctionnalité
● Gain dès qu'on a besoin de relire, retoucher ou
réutiliser
=> arrive généralement bien plus tôt qu'on ne le pense
Mieux vaut passer un peu plus de temps au début pour
bien faire que de supporter ensuite longtemps quelque
chose de mal fait !
91. Distribution de quasiment toutes les compétences
que nous savons mesurer…
Il n'y a pas que deux niveaux de développeurs, les
mauvais et les ninjas !
L'immense majorité d'entre nous est quelque part au
milieu de l'image.
92. Améliorons nous !
Lecture
● De livres, par exemple Clean code
● De code "propre" -> nombreux projets Open Source
(mais pas tous, souvent un signe de maturité, ex lucene,
wicket, jquery)
Ateliers/conférences
● Qu'ils soient dédiés au code propre (tests...)
● Ou sur un autre sujet : les échanges avec du code sont
toujours très instructifs, tout comme voir un autre coder
(et se servir de son environnement)
Ensemble
● Revue de code
● Pair programming : toujours très instructif
96. Coder propre sous partie d'un tout bien plus
vaste !
Autres points à considérer :
- programmation fonctionnelle,
- capture du métier,
- ergonomie,
- prise en compte de l'opérationnel,
- ...