Aller au contenu

Hexagone · épisode 01

Trois notes pour un seul restaurant

Architecture hexagonale : donner une seule maison à une règle métier

Houssem Blibech 4 min de lecture

épisode 01 · Trois notes pour un seul restaurant · la version animée
Écouter l'épisode · version audio

Hexagone, épisode 1 sur 8 : O, développeur chez AJLabs, remet d'aplomb la plateforme de RestoSafe, qui publie les contrôles d'hygiène de 207 000 restaurants. Chaque épisode se lit seul.

Le premier lundi de la mission, Daly accueille O dans les locaux d’AJLabs avec un café et une phrase qu’il répétera souvent : « RestoSafe, c’est notre plus beau client. Ne le casse pas. » Il lui montre l’écran : un tableau de bord avec des courbes de trafic qui montent, et une liste de tickets qui monte encore plus vite.

À 10 h, Hajer appelle en visio. Elle n’a pas l’air de bonne humeur. Un restaurateur de Lyon vient de la contacter, furieux : sur le site, son établissement affiche « Satisfaisant ». Dans l’application mobile, « À améliorer ». Et dans l’e-mail d’alerte que ses clients ont reçu ce matin, « Très satisfaisant ». Trois notes différentes pour le même restaurant, le même jour. Il parle d’avocat.

O passe l’après-midi à suivre le parcours d’une note. Ce qu’il découvre ressemble à un jeu de piste. Le site web calcule le niveau d’hygiène au moment de générer les pages, dans un script de build. L’API utilisée par l’application le recalcule à chaque requête, dans un contrôleur. Le job qui envoie les alertes, lui, le relit dans une colonne de la base mise à jour… quand quelqu’un pense à lancer la commande.

// api/src/restaurants/restaurants.controller.ts
@Get(':id')
async findOne(@Param('id') id: string) {
  const restaurant = await this.repo.findOne({ where: { id }, relations: ['inspections'] });
  const last = restaurant.inspections.sort((a, b) => b.date.getTime() - a.date.getTime())[0];
  // TODO: align with the website rules (2023)
  restaurant.level = last.score > 3 ? 'TO_IMPROVE' : last.score > 1 ? 'SATISFACTORY' : 'VERY_SATISFACTORY';
  return restaurant;
}

La règle n’est pas fausse partout. Elle est écrite trois fois, de trois façons, par trois personnes, à trois époques. Le site ignore les inspections de plus d’un an, l’API ne les ignore pas. L’application arrondit un score que le site tronque. Personne n’a menti : chacun a codé ce qu’il croyait être la règle.

Le soir, Adam passe la tête par la porte. « Tu as trouvé ? On aligne le contrôleur sur le site et on ferme le ticket. »

« On peut, répond O. Mais dans six mois, Hajer changera la règle, et quelqu’un oubliera l’un des trois endroits. »

Adam hausse les épaules. « C’est la vie d’un projet. »

O ne répond pas tout de suite. Il prend un feutre et dessine un hexagone au milieu du tableau blanc. Au centre, il écrit un seul mot : Inspection. Puis il ajoute, autour, tout ce qui touche le métier : un restaurant, ses inspections, la règle qui en déduit un niveau d’hygiène. Enfin, à l’extérieur de l’hexagone, il range tout le reste : le script de build Astro, l’API, l’application Flutter, la base de données, le job d’alertes, l’open data.

« Le centre, c’est le domaineDomaine La partie du code qui décrit le métier et ses règles, sans aucune dépendance technique.. Il ne connaît personne : ni la base, ni le web, ni le mobile. C’est l’extérieur qui vient lui demander les choses. Si la règle du niveau d’hygiène vit au centre, elle n’existe qu’une fois. »

Jana, qui était restée tard pour finir un ticket, s’approche du tableau. « Et les trois applications, elles font comment pour l’utiliser ? »

« Elles passent par des portes. On en reparlera. Pour l’instant, retiens juste ça : les flèches vont toujours de l’extérieur vers l’intérieur, jamais l’inverse. »

C’est l’idée de l’architecture hexagonaleArchitecture hexagonale Organisation du code où le métier est au centre et ne dépend de rien ; bases de données, interfaces et services externes s'y branchent depuis l'extérieur. : le métier ne dépend de rien, et c’est tout le reste qui dépend de lui. La forme d’hexagone n’a rien de magique. Elle sert juste à montrer qu’il y a plusieurs côtés, plusieurs façons d’entrer et de sortir, et qu’aucun n’est plus important que les autres.

Le lendemain, O écrit la règle une seule fois, dans un fichier qui n’importe aucun framework :

// domain/hygiene-level.ts
export type HygieneLevel = 'VERY_SATISFACTORY' | 'SATISFACTORY' | 'TO_IMPROVE' | 'URGENT_CORRECTION';

export function currentHygieneLevel(inspections: Inspection[], today: Date): HygieneLevel | null {
  const oneYearAgo = new Date(today);
  oneYearAgo.setFullYear(today.getFullYear() - 1);
  const recent = inspections.filter(i => i.date >= oneYearAgo);
  if (recent.length === 0) return null;
  return recent.reduce((latest, i) => (i.date > latest.date ? i : latest)).level;
}

Il la fait valider à Hajer, ligne par ligne. Elle découvre au passage qu’une inspection de plus d’un an ne doit plus être affichée comme note courante : c’est la règle officielle, et seul le site la respectait. Puis O branche les trois applications sur cette fonction. Le site au build, l’API à la requête, le job d’alertes à l’envoi. Les trois notes du restaurant lyonnais redeviennent une seule.

Daly passe voir le résultat à la fin de la semaine. Il ne regarde pas le code, il regarde le ticket fermé et le message de Hajer : « Merci, enfin cohérent. » Puis il demande la seule chose qui l’intéresse : « Tu vas tout réécrire comme ça ? »

« Non, répond O. Je vais commencer par la prochaine fonctionnalité qui touche aux inspections, et la construire au centre. Le reste suivra quand on y touchera. »

Ce que O retient

  • Un bug qui apparaît à trois endroits est rarement trois bugs : c’est une règle métier qui n’a pas de maison.
  • L’architecture hexagonale commence par une question : qu’est-ce qui est le métier, et qu’est-ce qui ne l’est pas ?
  • On ne réécrit pas tout. On choisit un endroit, et on y construit autrement.