XXP

mai 2016

lun. mar. mer. jeu. ven. sam. dim.
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

« Fluent Interfaces (do you speak API ?) | Accueil | Fluent Interfaces (do you speak API ?) »

15 juillet 2008

Fluent Interfaces (do you speak API ?)

Pour l'essentiel, le pattern des interfaces dites "fluentes" consiste à proposer aux développeurs d'écrire du code dont le phrasé ressemble au langage naturel.

Par exemple ce phrasé fluide (exemple tiré du site de Martin Fowler):

	TimeInterval meetingTime = fiveOClock.until(sixOClock);

exprime la même chose que cette version plus classique :

TimeInterval meetingTime = new TimeInterval(fiveOClock, sixOClock);

L'usage du mot 'until' (jusqu'à), courant dans la vraie vie, plutôt rare en programmation, fait la différence. De façon générale, les Fluent Interfaces privilégient l'emploient de méthodes au nom simples et issus du langage courant.

Deux exemples pour fixer les idées.

1. Rhino Mocks, framework open-source de mocks dynamiques développé par l'inévitable Ayende, permet d'écrire ça dans un test unitaire :

	Expect.Call(myObject.Concat("a","b")).Return("ab");

Joli non ?

Si on portait cette Fluent Interface en français, ça donnerait quelque chose comme :

 	JeMAttendsACeQue.CetAppel(monObjet.Concat("a","b")).Retourne("ab");

2. ReadableRex, API qui encapsule la complexité des expressions régulières :

    Regex socialSecurityNumberCheck = new Regex(Pattern.With.AtBeginning

            .Digit.Repeat.Exactly(3)

            .Literal("-").Repeat.Optional

            .Digit.Repeat.Exactly(2)

            .Literal("-").Repeat.Optional

            .Digit.Repeat.Exactly(4)

            .AtEnd);


Implémentation

Dans les grandes lignes, l'implémentation d'une Fluent Interface en elle-même n'a rien de sorcier et consiste souvent à retourner dans les méthodes et accesseurs le contexte en construction. Par exemple :

	public class Configuration
{
string color;
int height;
Configuration Color(string color)
{
this.color = color;
return this;
}
Configuration Height(int height)
{
this.height = height;
return this;
}
}

Dans le détail, développer une Fluent Interface peut s'avérer extrémement complexe. La complexité tient à l'inconsistance fréquente du langage naturel. Qu'il s'agisse de l'anglais ou du français, la grammaire qui le définit regorge de contradictions, d'exceptions et d'effets de contexte.

Défi

Pour vous en convaincre, essayez d'implémenter une API fluente d'expression des nombres littéraux tel celui suggéré par Michael Feathers, et dont voici un aperçu des spécifications :

  Assert.AreEqual(1, (int)FluentNumber.One);
  Assert.AreEqual(23, (int)FluentNumber.Twenty.Three);
  Assert.AreEqual(912, (int)FluentNumber.Nine.Hundred.And.Twelve);
  Assert.AreEqual(777000, (int)FluentNumber.Seven.Hundred.And.Seventy.Seven.Thousand);

Ce que ne dit pas cet essemble de tests à faire réussir, c'est que l'autocompletion doit aussi fonctionner au mieux : taper 'Twenty' doit déclencher les propositions 'One', 'Two', ... 'Thousand" et 'Hundred', mais ni "Twenty" et autres dizaine, ni 'Thirteen' et autres 'teens'. C'est sûrement un excellent exercice pour appréhender les difficultés de développement d'une Fluent Interface.

Serez-vous capable de développer une API robuste vis-à-vis des tournures aberrantes telles que

	FluentNumber.One.Thousand.One.Thousand

Un vrai travail de linguiste...

Liens :

TrackBack

URL TrackBack de cette note:
https://www.typepad.com/services/trackback/6a00d8341c871f53ef00e553ad0d1c8834

Listed below are links to weblogs that reference Fluent Interfaces (do you speak API ?):

Commentaires

L'utilisation des commentaires est désactivée pour cette note.