How To : Concevoir une API Fluent – Partie 1

Je suis tombé récemment sur le très intéressant framework lambdaj. En creusant un peu, ce qui m’a attiré le plus dans ce framework, c’est cette manière d’enchaîner les méthodes pour avoir un code clair et concis. Ce framework met en pratique la notion de Fluent interface.

Cela m’a donné à réfléchir et je me suis lancé le défi de concevoir une petite API qui serait elle aussi Fluent afin de comprendre le mécanisme qui se cache derrière cette pratique.

L’inspiration m’est venue du projet sur lequel je travail. Nous avons pris le choix de ne pas utiliser Hibernate et de nous tourner vers MyBatis qui est un framework de persistance beaucoup plus léger qu’Hibernate et qui à une prise en main / configuration très simple. Mais voila, la simplicité n’a pas que des avantages, l’API de Criteria de MyBatis est un casse-tête pour créer des critères pour nos recherches pour peu qu’ils soient un peu compliqué avec de nombreuses conditions et une imbrication de OR et de AND.

Je me suis donc inspiré de ce problème pour mon proof-of-concept : nous allons concevoir un mini-framework capable de faire des critères de recherche SQL de manière facile en m’inspirant de lambdaj et son style fluent. Loin de moi l’idée de faire un framework qui serait un jour utilisé, l’idée est de réfléchir à la manière dont on écrit une API fluent sur un cas concret : la génération de code SQL.

Fluent interface c’est quoi ?

Si on pouvait résumer, Fluent, c’est ça : pouvoir écrire du code pratiquement en language humain qui se comprend aussi facilement qu’il ne se lit (et qui s’écrit aussi facilement).

Cela reprend en partie le design pattern Builder :

En java, on a l’habitude d’écrire :

  1. Utilisateur user = new Utilisateur();
  2.  
  3. user.setNom("Kent");
  4. user.setPrenom("Clarc");
  5. user.setAge(99);

Le design pattern builder nous permet d’écrire le code de manière plus condensée. On voit qu’ici, l’écriture du code est simplifiée par la posibilité d’enchainer les méthodes les une après les autres.

  1. UtilisateurBuilder builder = new UtilisateurBuilder();
  2.  
  3. builder.setNom("Kent").setPrenom("Clarc").setAge(99);
  4.  
  5. Utilisateur user = builder.build();

Notre API Fluent reprendra pleinnement ce principe. Ce qui nous donnera un code de ce type :

  1. Criteria c = UtilisateurCriteria.getNom().isEquals("Kent")
  2.     .and(UtilisateurCriteria.getPrenom().isEquals("Clarc"));

Qui peut facilement se lire à haute voix : je veux les utilisateurs dont le nom est « Kent » et dont le prenom est « Clarc ».

Première étape : lister nos besoins

Notre POC doit satisfaire les besoins suivant, il devra :
* Gerer les AND et les OR
* Gerer les types de données : Integer, String, Boolean, Date, …
* Gérer les opérations : =, <>, <, <=, >, >=
* Gérer les opérations unaires : is null, is not null
* Pas de constantes dans le code

Le dernier point me tient beaucoup à coeur : les frameworks ont tendance à exposer des API ou le développeur est amené à nommer les champs qu’il manipule avec des constantes de type chaîne de caractères. Mais cela masque des erreurs potentielles en cas de renommage de champs en base par exemple, ou tout simplement d’erreur de frappe. Je partirai donc sur l’approche de MyBatis qui génère des classes pour refléter la structure de la base de données.

Bien, maintenant que nous savons quoi faire, rendez-vous page suivante pour suivre la réalisation du POC :

How To : Concevoir une API Fluent – Partie 2

Le commentaires sont fermés.