Les bonnes et les mauvaises critiques sur Java — Épisode 3 : Les « bonnes » pratiques

Toutes les communautés qui se forment autour d’un langage développent un certain nombre de bonnes pratiques ou de conventions. Elles n’ont rien d’obligatoire pour maîtriser le langage mais sont généralement plus ou moins suivies par les développeurs et on conseille généralement aux débutants de s’y mettre tôt. Cela peut aller du style de développement, comme la très célèbre PEP8 de Python à l’utilisation conseillée de certains design patterns. Et Java ne manque pas de ces derniers, la plupart détaillés dans le bouquin Effective Java dont je vous ai déjà parlé. Je vais être franc : je considère une bonne partie de ce qui est écrit dans ce bouquin comme étant carrément dispensable. Soit que ce sont des conseils de bon sens absolument pas exclusifs à Java, soit que se sont des stratégies pour palier aux déficiences patentes du langage, soit que ce sont tout simplement une monstrueuse pile de merde…

Autrement dit, si Java était un bon langage, au sens syntaxiquement facile et élégant, la taille de ce bouquin se réduirait à peau de balle…

Le code auto-documenté

J’ai rien contre le fait de donner des noms signifiants aux objets et méthodes, mais il y a un moment où il faut savoir s’arrêter… Voici un exemple tiré d’un projet sur lequel j’ai travaillé il y a peu : une variable représentant l’analyse du temps moyen de fonctionnement des chaudières chez les voisins d’un client sur un mois. Comment pensez-vous que les développeurs l’ont appelée ?

monthlyNeighborsBoilerUptimeAnalysis

. Ouais, même pas honte… Et en rajoutant un getter dessus :

getMonthlyNeighborsBoilerUptimeAnalysis()

41 caractères, putain ! Comment je fais pour respecter mes colonnes de 120 caractères maximum avec des noms à rallonge comme ça, moi !?

Très franchement (et je leur ai fait la remarque), vouloir à tout prix du code auto-documenté est à mes yeux une très mauvaise pratique. Le nom des variables doit évidemment avoir une certaine sémantique, mais pas à n’importe quel prix. En particulier, le nom ne devrait pas être une explication extensive de l’utilité d’une variable ou d’une méthode. Ça, c’est le rôle de la javadoc. Sur ce point, la PEP8 de Python dont je vous ai parlé plus tôt impose une bonne pratique basée sur une observation toute bête : un code source est plus souvent lu qu’il n’est écrit. Il devrait donc avant tout être conçu pour pouvoir être lisible. Lorsque le nom d’une variable dépasse une quinzaine de caractère, elle ne peut plus être considérée comme lisible. En particulier, pour moi, lorsque le nom d’une méthode se trouve être la concaténation de plus de 3 mots courants, je suis toujours obligé de faire un effort pour pouvoir la lire.

Lorsque j’ai fait la remarque, je me suis vu répondre qu’il était important de comprendre à quoi correspondait la variable rien qu’en lisant son nom. Non ! Non, non et non ! Si la variable représente un concept simple, pourquoi pas, mais si la variable représente un concept complexe, comme au-dessus, ça ne sert à rien. Le nom doit, tout au plus avoir une fonction mnémotechnique permettant à quelqu’un ayant déjà vaguement parcouru le code de se souvenir de l’utilité de la variable. Mais pas de la comprendre. Dans le pire des cas, il suffira de toutes façons de se référer à sa déclaration pour s’en souvenir si jamais il a un doute. Mais le nom ne doit jamais remplacer la documentation.

Les design pattern à la con

Java est blindé de design pattern. Ils sont toujours présentés comme une bonne pratique mais ils sont — à mes yeux — au mieux, des pratiques induites par la pauvreté syntaxique de Java, au pire, de la masturbation mentale.

Et mon préféré de tous, c’est le builder. Le builder, c’est un patron qui sert à instancier des objets à partir d’autre objets. Voilà, c’est tout. Ça n’a aucune autre utilité. Franchement, un objet qui instancie des objets, c’est pas l’idée la plus stupide du monde !? C’est pas ça, le rôle d’un constructeur ?

La justification donnée dans Effective Java, c’est que lorsque le constructeur commence à avoir beaucoup de paramètres — et en particulier des paramètres optionnels — le nombre de constructeurs à écrire augmente de manière exponentielle. Et c’est effectivement vrai en Java. Parce que Java est syntaxiquement à chier. Voici un exemple :

class Car{
  private String color = "black";
  private int wheelSize = 18;
  private String type = "berline";

  public Car(){}

  public Car(String color){
    this.color = color;
  }

  public Car(int wheelSize){
    this.wheelSize = wheelSize;
  }

  public Car(String type){
    this.type = type;
  }

  public Car(String type, int wheelSize){
    this.type = type;
    this.wheelSize = wheelSize;
  }

  public Car(String type, String color){
    this.type = type;
    this.color = color;
  }

  public Car(int wheelSize, String color){
    this.wheelSize = wheelSize;
    this.color = color;
  }

  public Car(String type, int wheelSize, String color){
    this.wheelSize = wheelSize;
    this.color = color;
    this.type = type;
  }
}

Je viens de créer une classe avec trois paramètres facultatifs. Pour ceux qui ont fait un peu de combinatoire, afin de pouvoir instancier l’objet avec n’importe quelle combinaison de paramètre, il m’a fallu écrire, donc, 8 constructeurs. Pour seulement 3 paramètres facultatifs.

Pour palier à ça, Python, Ruby, Groovy, C♯, ont introduit la notion d’arguments par défaut (ou arguments optionnels). Cette notion permet d’initialiser une variable directement dans la signature, rendant facultatif le fait de passer une valeur à la méthode. Le code poubelle ci-dessus s’écrirait donc en Groovy :

class Car{
  private String color
  private int wheelSize
  private String type

  public Car(String color="black", int wheelSize=18, String type="berline"){
    this.color = color
    this.type = type
    this.wheelSize = wheelSize
  }
}

Et je pourrais passer les argument que je veux dans l’ordre que je veux, parce que les arguments sont nommés :

def car = new Car(color="black")

Si je voulais, je pourrais même les passer sous la forme d’un dictionnaire :

class Car{
  private String color
  private int wheelSize
  private String type

  public Car(Map args){
    args.color = color
    args.type = type
    args.wheelSize = wheelSize
  }
}
def car = new Car(color: "black", wheelSize: 18)

Si vous vous posez la question de l’utilité de ça, la réponse est simple : ça permet de raccourcir les méthodes avec beaucoup de paramètres obligatoires. Par exemple pour une connexion à une base de données :

class Connection{
  private String URL
  private String user
  private String pass
  private String database
  private String port
  private String name

  public Connection(Map args)
  {
    this.URL = args.URL
    this.user = args.user
    this.pass = args.pass
    this.database = args.database
    this.port = args.port
    this.name = args.name
  }
}

def params = [
  URL: "localhost",
  port: "3306",
  user: "root",
  pass: "chats",
  database: "diaspora",
  name: "d*"
]

def conn = new Connection(params)

Beaucoup plus lisible comme ça, n’est-ce pas !?

Mais ça, en Java, vous pouvez faire une croix dessus…

Les interfaces

On va trouver que je radote, mais les interfaces sont pour moi l’invention la plus nocive introduite dans la programmation ces 30 dernières années. Je ne vais pas m’étendre sur le sujet, j’ai déjà écrit cet article sur la question.

Conclusion

Java est un très mauvais langage. J’entends par là que c’est un langage inélégant, inutilement verbeux et stupidement bridé. Je suis vraiment étonné qu’il rencontre encore autant de succès en entreprise surtout depuis la création de langages clairement supérieurs pour la JVM — au premier rang desquels Groovy et Scala. Je comprends que les entreprises ne se soient pas ruées sur Jython ou JRuby, que la grande quantité d’outils généralistes en Java pour les entreprises et les gros projets (Spring, JEE, Maven, etc.) ai été un frein à leur adoption. Mais Scala est apparu en 2003, Groovy en 2005. Ces deux langages sont désormais matures et entièrement compatibles avec Java. J’ai moi-même développé un projet en Groovy pour Android et un plugin Maven pour mon entreprise. Si Scala est un langage purement fonctionnel et, donc, difficile d’accès, Groovy présente une rétrocompatibilité avec la syntaxe Java presque totale donc une courbe d’apprentissage quasi-plate. Plus rien, aujourd’hui, ne justifie que l’on fasse encore du Java pur en entreprise et que l’on l’enseigne encore à l’école. Java est saloperie legacy qu’il convient désormais d’éliminer.

La bonne nouvelle, c’est que Groovy tend à s’imposer de plus en plus en entreprise avec des frameworks de très grande qualité comme Grails pour le développement de sites web ou d’API REST, Griffon pour le développement d’applications lourdes, Gradle, un très bon moteur de compilation prenant des concepts de Maven ou encore GVM, un outils de gestion de version pour les outils pré-cités.

Déjà 4 avis pertinents dans Les bonnes et les mauvaises critiques sur Java — Épisode 3 : Les « bonnes » pratiques

  • test
    Salut,
    Je ne suis pas trop d’accord avec ce qui est écrit, mais il n’y avait pas de commentaire, et j’aime bien la photo de chat :-)
  • ica
    J’aime bien tes sujets sur Java, continue d’écrire (ou commence à faire des vidéos) là dessus.
    Tes critiques ont du sens, mais Java a fait beaucoup de progrès depuis la version 8 je trouve.

    cdt,

Les commentaires sont fermés.