Aller au contenu

4. Réagir, et s'en aller

Notre extension doit savoir qu’une affaire vient d’être perdue, pour vérifier que quelqu’un a nommé le gagnant. Elle ne va pas le demander à pipeline. Elle écoute.

L’écoute

"""Reacting to ``pipeline`` without importing it.
The extension needs to know when an opportunity is lost. It does NOT call into
``pipeline`` to find out: it listens.
That is the whole difference between extending a module and forking it. The
event is a public fact; the code behind it is not.
"""
from kewos.events import subscribe
#: Emitted by the kernel on every write. We filter on the model rather than ask
#: `pipeline` for a dedicated event: a module we extend owes us nothing.
_WRITE_EVENT = "record.updated"
def note_the_winner(event: Event) -> None:
"""When an opportunity is marked lost, check that a winner was named."""
payload = event.payload or {}
if payload.get("model") != "pipeline_lead":
return
record = payload.get("record")
if record is None or getattr(record, "state", None) != "lost":
return
if getattr(record, "rivals_won_by_id", None) is None:
_log.info("opportunity %s was lost with no competitor named", record.id)
def register_listeners() -> None:
"""Subscribe on module load."""
subscribe(_WRITE_EVENT, note_the_winner)

C’est tout le contrat. Le noyau émet record.updated sur toute écriture ; nous filtrons sur le modèle. Nous ne réclamons pas à pipeline un événement dédié, parce qu’un module qu’on étend ne nous doit rien : ce qu’il publie, il le publie pour tout le monde.

Il ne corrige rien, il le dit

Le gestionnaire n’écrit pas. Il journalise l’omission pour qu’une revue la voie. Remplir le champ à la place de l’humain serait deviner, et empoisonnerait exactement le rapport que ce module existe pour produire : un gagnant inventé compte comme un gagnant.

Le même besoin, sans code

Ce que fait ce fichier peut aussi se poser dans le moteur visuel, et se livrer avec le module, comme le fait le premier parcours à l’étape « Automatiser ». La question à trancher est toujours la même : cette règle est-elle la vôtre, ou celle du client ? Ce qui relève de votre jugement de conception va dans le code ; ce que le client voudra changer sans vous va dans un flux.

Se désinstaller sans rien laisser

C’est le test qui dit si vous avez étendu ou forké. Désinstallez pipeline_rivals :

  • rivals_competitor disparaît : c’était notre table ;
  • pipeline_lead perd deux colonnes contribuées, et rien d’autre ;
  • la rustine de vue s’en va, et la vue de pipeline redevient ce qu’elle était, parce qu’elle n’a jamais été remplacée ;
  • l’abonnement disparaît avec le processus.

Rien de tout cela n’a demandé de code de désinstallation. C’est la conséquence directe des trois choix des étapes précédentes : notre modèle porte notre préfixe, nos champs aussi, et notre écran est une rustine.

Reprenez maintenant l’inverse. Si vous aviez copié pipeline_lead.form.json pour y glisser deux champs, la désinstallation vous laisserait la copie, figée à la version où vous l’avez prise.

L’extension finie, à télécharger

  • pipeline_rivals-0.1.0.kws (7 Ko) — le module de ce parcours, avec ses deux rustines de vue, son écouteur et ses données de démo.
74af7d7e9382e16b26815412a4f29d6e608a961180f416feabf0882c14f2619f pipeline_rivals-0.1.0.kws
Fenêtre de terminal
sha256sum pipeline_rivals-0.1.0.kws
kewos module install pipeline_rivals-0.1.0.kws \
--database-url "$KEWOS_DATABASE_URL" \
--modules-root "$KEWOS_MODULES_ROOT" \
--allow-unsigned
kewos reconcile --confirm

pipeline doit être installé et activé avant, sinon le gel du registre s’arrête sur la dépendance manquante, en la nommant. La marche complète, et pourquoi le paquet n’est pas signé, sont expliquées à la dernière étape du premier parcours, Livrer.

La liste de contrôle

Avant de livrer une extension, ces cinq réponses doivent être « oui » :

  1. grep -r "import modules\." mon_module/ ne renvoie rien.
  2. Tout ce que j’ai créé porte le préfixe de mon module.
  3. Mes champs ajoutés sont nullable=True.
  4. Mes écrans sur les modèles d’autrui sont des *.patch.json, pas des vues complètes.
  5. Mon manifeste déclare depends sur ce que j’étends.

Et ensuite

Vous savez construire un module et en étendre un. Ce qui reste est le même travail qu’ailleurs : l’emballer et l’installer, décrit à la dernière étape du premier parcours, Livrer.