Par , le 30 janvier 2015

Solution pour écrire de meilleurs contrôleurs : Decent Exposure

Développement | 0

Une des bonnes pratiques de la conception orientée objet repose sur un couplage faible, c’est-à-dire, des rôles et des responsabilités distincts partageant le moins de données possible.

Contrôleur et Vue ont, selon le principe du MVC (modèle-vue-contrôleur), des responsabilités différentes. Ils ne devraient donc communiquer que par quelques points de liaison bien définis.

Le problème avec les contrôleurs

Avec Rails, ces connexions se font grâce à des variables d’instance qui sont directement copiées du contrôleur à la vue.

Bien que dans la plupart des autres classes de l’application, les variables d’instance sont le plus souvent privées ; ici elles sont publiques et deviennent donc notre unique interface. Dépendre de ces données entraîne donc un couplage fort entre ces deux composants.

De plus, la particularité du contrôleur de Rails est qu’il rend ces variables inaccessibles à l’extérieur de l’action, nous obligeant ainsi à écrire plusieurs fois la même assignation ou à créer des filtres appliqués sur plusieurs actions.

Si bien que, plus le projet grandit, plus le manque d’interface et le couplage fort rendent difficiles la maintenance des contrôleurs..

Une gem à la rescousse

Chez Silicon Salad, nous utilisons une gem qui corrige en partie ce problème. Il s’agit de Decent Exposure.

Crée par Stephen Caudill, le développement a débuté en Janvier 2010 et même s’il est fortement ralenti, la gem est toujours maintenue.

Le principe est simple : Decent Exposure va exposer les données à la vue grâce à des méthodes. Remplacer les variables d’instance par celles-ci réduit le couplage entre vue et contrôleur. Il en résulte, la capacité à développer des vues à partir d’une interface.

Prenons l’exemple d’un contrôleur RESTful classique généré à partir du scaffolder :

decent-exposure-1

Comme expliqué plus haut, il n’y a pas d’interface claire, seulement des implémentations au niveau de chaque action. Afin d’éviter les répétitions, on applique un filtre pour trouver notre produit pour 4 des 7 actions. Mais il reste encore beaucoup de duplication.

Avec Decent Exposure, voici ce que devient notre contrôleur :

decent-exposure-2

Après l’ouverture de la classe, on déclare directement nos méthodes expose.

La première va initialiser ou trouver notre ressource produit en fonction de plusieurs critères, à savoir : le nom de la ressource, le verbe HTTP et la présence ou non d’un ID dans les paramètres.
Ainsi, les requêtes GET (ou DELETE) /products/42 effectuent la recherche suivante : Product.find(42)
Tandis que GET /products/new initialise un nouveau produit : Product.new
En POST, PATCH et PUT, le produit se verra assigner les attributs présents dans les paramètres.

Le deuxième expose concerne tous les produits.
En présence d’un nom de méthode au pluriel, Decent Exposure retourne toute la collection : Product.all.
Et grâce au bloc, on peut facilement appliquer le scope available pour exposer les produits disponibles.

À travers cette interface, on rend donc accessible notre produit courant ainsi que nos produits disponibles. Et ce, pour toutes vues et actions appartenant au contrôleur.

Comme vous pourrez le lire dans la documentation de la gem, Decent Exposure offre d’autres avantages :

  • toutes les méthodes exposées sont « évaluées paresseusement », ce qui signifie qu’elles ne seront définies que si elles sont appelées.
  • une configuration customisée. La méthode expose peut recevoir plusieurs paramètres, par exemple : le nom du modèle de la ressource, le nom de la méthode de recherche car on ne retrouve pas toujours une ressource par son ID.
  • extensible avec la création de Stratégie lorsque les options de configuration ne coîncident pas avec un besoin particulier et que les blocs deviennent trop imposants.

On pourra cependant noter quelques inconvénients:

  • trop de magie ! Toute la logique est cachée dans la gem et on s’écarte du comportement natif de Rails ce qui peut en rebuter certains.
  • il peut être difficile de créer une stratégie sans aller inspecter le code source de la gem. La documentation n’étant pas très fournie pour ce composant.

Pour conclure,

Au sein de l’équipe, nous utilisons cette gem sur plusieurs de nos projets, et dans chacun de nos contrôleurs. Autant dire que c’est une gem désormais éprouvée et qui nous a permis un gain de productivité non négligeable sans pour autant nous poser de problème majeur lors de son implémentation … ou presque.

En effet, cet article était prêt à être publié quand nous avons dû faire face à un petit problème que je vous présente ici.

Voici notre contrôleur :

decent-exposure-3

Nous souhaitons nous rendre à l’url suivante : monsite.com/product/42. Malheureusement, l’application indique que la ressource n’a pu être trouvée.
L’objet product existe pourtant bien en base de données :
<Product: id: 42, title: 'Deep Thought', available: false >

Comme dit précédemment, on s’attend à ce que Decent exposure utilise la requête suivante pour trouver notre resource : Product.find(42).
Hors, ce n’est pas vraiment ce qui arrive dans notre cas de figure.

Voici une version simplifiée de ce qu’il se passe au niveau de la gem :

decent-exposure-4

Notre controller répond déjà à products puisque nous l’exposons. Aussi, Decent Exposure va s’en servir pour retrouver notre ressource, exécutant ainsi Product.available.find(42). Notre produit d’ID 42 n’étant pas disponible, la ressource ne peut pas être trouvée.

Pour contourner le problème il faut renommer l’expose : :products par :available_products.

Cela renforce le point négatif concernant le comportement trop secret de la gem, beaucoup de logique est cachée au développeur et peut amener ce genre d’incompréhension.

Ceux qui veulent garder le même système d’expose peuvent se tourner vers la gem Adequate Exposure qui est plus minimaliste, légère, et donc moins obscure dans ses actions.

Partager l'article :

Vous souhaitez réagir ?

En soumettant ce commentaire vous donnez à Silicon Salad le droit de citer vos propos ainsi que votre nom/site. Tous commentaires dégradants ou hors-sujet peuvent-être supprimés par décision de l’auteur. Votre e-mail, ne sert qu’à des fins d’authentification, il ne peut-être ni partagé ni diffusé.
Vous pouvez commenter avec la syntaxe Markdown. En savoir plus

Article précédent
Et si Google Adwords était la solution naturelle pour générer du trafic qualifié sur votre e-commerce ?