L’homme orchestre, partie 2 : écrire du code (en Java)

Depuis 4 ans, j’écris un MAM libre en Java. Comment arriver à ne pas se laisser dépasser par l’immensité du travail à fournir ? Un article en deux parties très subjectives et relèvent de l’expérience que j’ai pu tirer avec le temps (je ne suis pas développeur de métier ni de formation).

Publié le

Précédemment : la partie 1, les casquettes

Les bon outils

Pour travailler, il faut de bons outils. Vos bons outils. Ceux que vous connaissez, que vous aimez. Toute l’énergie employée à lutter contre ses outils de travail, ne sera pas récupérée ailleurs.

Si vous avez un IDE, tunez le à fond. Police, couleurs, macros, plugins, tout doit être à vos goûts. Vos outils sont vos mains, ils doivent être naturels et logique. Votre logique. Et attention aux mises à jours qui peuvent casser ça : faites des backups de votre environnement de dev.

Pas de temps à perdre à apprendre

Je conçois mon développement de code selon une simple maxime : un nain sur des épaules de géant. Je repose sur des technologies réputés et fiables. Pas sur des bidouilles qui montrerons leurs limites (en terme de stabilité ou performance) au moment où ça sera trop tard. Pour cela je prends du temps pour choisir ces technologies. Il m’a fallu plus d’un an pour valider ElasticSearch, Cassandra, Play et Git.

Mais je ne perd pas de temps à les faire fonctionner. Pas de tutoriel ? Pas d’exemple ? Next ! Galère à installer ? Next ! Limité dans les plateformes ? Next ! Complètement abandonné ? Next ! Si l’équipe qui a écrit ce framework, ce serveur, cette API, cette bibliothèque, n’a pas pris le temps de faire un travail de présentation pour aider le néophyte, alors pourquoi je devrai faire cet effort ?

Je me limite donc qu’aux technologies qui me sont accessibles sans trop d’efforts. Et ça fini par payer : il m’a fallu assez peu de temps pour utiliser React ou Gson. Il m’en a fallu pas mal pour les utiliser correctement, mais au moins je n’ai pas mis un mois pour juste pour les découvrir, les essayer et voir qu’ils me convenaient.

Avancer pas à pas sur de bonnes bases mais abstraire ce qu’il faut

Un bon développeur fait un code lisible, avec le moins d’instructions possible, en allant directement au but. C’est l’idéal quand vous écrivez un script. Mais pas forcément quand vous devez construire une grosse application. Vous devez avoir un coup d’avance sur ce que vous allez peut-être avoir besoin, et le prévoir en amont. Mais attention, uniquement jusqu’a la prochaine itération ! Quand on dessine les plans d’un avion, on prévoit que l’on aura des passagers à « stocker » avant de prévoir la couleur du robinet des toilettes, mais on oublie pas que l’on aura aussi des toilettes à « stocker » dans l’avion, à côté des passagers, même si eux restent plus importants !

Autre exemple plus concret, je prévois l’analyse de documents bureautique dans MyDMAM. Je sais comment je vais procéder. J’ai besoin pour cela de l’analyse de PDF. Cette analyse à besoin d’une API pour abstraire le type de document et choisir moteur à employer pour le traiter. Je dispose actuellement d’une API pour traiter les fichiers graphique, audio et vidéo. J’ai prévu dans mon code la possibilité d’étendre cette API à autre chose et fait attention à ne pas trop mettre en dur les différents formats gérés. Quand je devrais gérer les PDF, je sais que je ne devrais pas casser grand chose pour y arriver. Et a ce moment là, je penserai à gérer les documents bureautique. Mais pour le moment, ce n’est pas prévu. C’est notamment ça le travail « d’architecte logiciel » que je parlais plus tôt.

La rigueur

Quand on part dans une direction, on s’y tient, ou alors on recule et on change de direction, on casse du code et on repart au propre. Le bricolage tout moche pour que « ça marche » est à bannir. Votre code est libre et publique ? Evitez d’écrire une rustine qui vous fera honte une fois que git blame vous dira que l’imbécile qui à écrit ça il y a bien longtemps, c’était vous.

Je suis lent à avancer dans l’écriture de mon code pour cette cause. Vu le temps que j’y ai passé, MyDMAM devrait couter l’équivalent d’une fortune en terme de temps de travail ! Mais je suis globalement fier du code déjà écrit. Les parties les plus anciennes sont à opposer aux parties récentes qui me montrent que j’ai progressé en terme de qualité et de rigueur.

N’oubliez pas que le problème avec une installation en carton, c’est quand les scotchs lâchent.

Bien nommer

Si vous ne savez pas noter une variable, une classe, une fonction, c’est qu’elle n’a pas a exister de la façon d’où vous la pensez. Quand vous avez le bon nom, c’est bon, continuez avec. Je suis maniaque des noms. J’utilise de longs noms, et je passe beaucoup de temps à y réfléchir. J’essaye de garder une grande cohérence dans les variables : si une variable s’appelle « toto » dans un coin du code, une fois passé dans une autre partie du code, elle ne doit pas s’appeler « tata ». C’est le meilleur moyen de s’embrouiller quand votre code fait 50 000 lignes. C’est très contraignant, mais Eclipse m’aide beaucoup avec ses fonctions de refactoring.

Java

Quand j’ai découvert Java, j’en ai eu très peur, moi qui « venait » du PHP, et qui avait écrit plein de bouses dans ce langage. Les fonctions de refactoring intégrés à Éclipse m’on sauvé. Sauvé car mon IDE est devenu omniscient. Il me déchargeait d’un tat de choses que je n’avais plus à penser. La mise en page, la vérification de d’erreurs de syntaxe, de cohérence entre les objets, l’auto complétion… c’est magique !

Après il y a des façons de faire en Java qui sont enseignées / conseillés et qui par expérience alourdissent le code.

En utilisant Play! Framework, la v1 (c’est à dire la version Java/Groovy), et avec mon expérience personnelle, j’ai appliqué de nouvelles façon de travailler :

  • Prioriser le static, le plus possible. Si quelque chose est polyvalent pour tout le code, et n’a pas besoin d’être libéré/détruit alors il sera static.
  • Cacher les champs par défaut, et les ouvrir au besoins, bref, réduire le plus possible la visibilité.
  • Eviter les get/set de vos variables privés (sauf dans le cas ou vous avez besoin de faire un check en entrée ou une transformation en sortie) et remplacez les get/set par un accès direct à la variable.
  • Bannir les génériques en cascade comme des Map de List de List
  • Ne pas hésiter à créer des classes pour étaler ses idées simplement, puis tout factoriser dans le moins de classes possible une fois que la logique est là.
  • Les annotations et la Reflexion sont très puissants, mais ça échappera à l’IDE omniscient. À utiliser pour simplifier des parties de code bien lourdes et répétitives et rendre le code « magique ». Je m’en sert notamment pour transformer une fonction Java en Contrôleur pour des dialogues avec JavaScript coté client, et en abstrayant les (dé) serialisations json avec des vrai objets Java.
  • Fabriquer ses propres génériques, c’est souvent casse gueule et parfois inutile. Au final, c’est rare que j’en ai eu une bon raison d’en faire. Ce qui existe déjà est très bien.
  • Si on ne peut pas déterminer à quoi sert quelque chose par son nom ou par l’IDE (avec la recherche de dépendance) alors il faut mettre un commentaire. Sinon commenter, c’est une perte de temps. Oui, j’assume cette phrase.
  • Des très long noms de variables et de classes sont autorisés… pourquoi s’en priver ?
  • Bien choisir son système de log ! Et apprendre à s’en servir !
  • Les threads permettent d’avoir des sous systèmes indépendants dans un seul processus. Il est fondamental de comprendre comment marche la synchronisation entre Threads (ce n’est pas très méchant, mais c’est pas évident de prime abord). D’autre part les Threads servent aussi à monter en performance en faisant des calculs en parallèles, mais ça demande d’avoir un très gros niveau technique pour y arriver, car si c’est mal fait, ce ne sera pas plus rapide ou alors ça fera boom ! Quand j’ai besoin de prefs, j’utilise toujours une librairie qui le fait mieux que moi.
  • Je n’écris pas de tests unitaires. Je comprends le principe, mais je n’y adhère pas. J’ai 0 tests, et mon dev se porte très bien. Je travaille le plus proprement possible, et le travail conjoint entre mon IDE et mon historique Git m’a permis de ne quasiment jamais à avoir d’effets de bords lors de mes itérations d’implémentations et de corrections de bug. Maintenant, je travaille seul et sans contraintes extérieures.
  • Design pattern : c’est indispensable d’en connaître quelqu’uns ou au moins de connaître quelques principes. C’est comme ça que mon code est passé d’un tas de scripts pourris à une vraie structure de code. C’est une forme de maths, ça fait mal à la tete, mais ça permet de débloquer tellement de choses.
  • Les regex, c’est mal. Je les évite le plus possible. Une fois j’ai remarqué qu’un for sur les caractères d’une chaine avec plein de if allait 11 fois plus vite qu’une petite regex qui m’a pris des heures à écrire. Ça ma mis en rage quand j’ai découvert ça. Et puis en terme de lisibilité, on ne fait pas plus cryptique d’une regex. Le mal de tête quand on se dit que l’on va devoir en modifier une…

En détail

Commentaires/recherche de code

Je commente donc très peu. Mon code est écrit de tel façon que tout soit le plus clair possible. Les fonctions de refactoring/recherche de dépendances d’Eclipse sont là pour aider à comprendre une structure facilement. Et quand ce n’est pas suffisant, là, je met un commentaire.

Petites itérations

Mon cycle d’implémentations/debug/releases est très lent. Trop lent. Je devrais me contenter de faites des choses plus petites et d’incrémenter plus souvent mes versions, car plus les changements sont importants plus la transition est difficile. Je pense que ça viendra avec le temps.

Améliorez, progressez, réécrivez !

Tout ne peut pas être parfait du premier coup mais peut le devenir ! Je cherche toujours à améliorer les portions de code maladroites, afin d’éviter le plus possible de le compenser avec d’autres maladresses, et de me retrouver avec un tas de bazar ingérable. Ce qui fait qu’il m’arrive de récrire et d’améliorer plusieurs fois certains éléments pour arriver à quelque chose de plus propre, stable et évolutif. Par exemple, le code qui gère le service de Broker/Jobs/Queue distribué via Cassandra à été réécrit 4 fois et est maintenant plus stable et aboutit qu’il ne l’a jamais été.

Pas compile, pas commit

Une règle de base : garder son repository propre. Si ça ne compile pas, on corrige avant de commiter. Car sinon on ne saura pas si l’erreur qui arrivera au prochain pull viendra de son environnement de dev ou du nouveau code que l’on vient de pull. Une fois ça m’est arrivé, j’ai compris la leçon.

S’oxygéner l’esprit

On est pas des machines. J’ai remarqué qu’en codant pendant un bloc de 3 heures, mon code était « meilleur » que pendant 6 heures. La fatigue dégrade la qualité du code. 3 heures par jour, ce n’est pas beaucoup, mais au final j’avance plus vite que 4 jours à 6 heures et rien la semaine d’après. Cette phrase n’a pas de sens, mais je suis sur que vous l’avez compris.

Et régulièrement faire des pauses de l’esprit comme travailler un visuel pour le site du projet, fouiller du côté de nouvelles technologies, réfléchir à l’avenir et aux nouvelles fonctions géniales que l’on aimerait faire…

Enfin tout ce qui ne consiste à ne pas taper sur un clavier.

Et sortir. Parler de ce que l’on fait à d’autres humains « en vrai ». C’est toujours instructif car on peut avoir des « questions bêtes » dont la réponse semble évidente. On m’a demandé si ça marchait sous Windows (potentiellement oui, c’est du Java), mais en y réfléchissant je me suis rendu compte que j’avais jamais testé l’interface web sous IE… et qui ne c’est avérée pas du tout fonctionnelle !

Bref, on pourrai en parler pendant des heures, chaque développeur à ses envies et ses préférences. Et encore plus quand l’on est pas développeur comme moi, et que l’on pas eu la « chance » d’avoir eu une formation formatant l’esprit de comment on doit faire et ne pas faire. Mais ça, c’est une autre histoire.