La situation
Un groupe médical de quinze cliniques fonctionnait avec huit outils qui s'ignoraient : un site, un widget de prise de rendez-vous séparé, un tableur pour les stocks, un deuxième tableur pour le laboratoire, un logiciel de comptabilité, une application de pointage, un tableau de bord publicitaire et une boîte de réception partagée. Chaque chiffre qui comptait existait dans au moins deux endroits, et quand les valeurs ne concordaient pas, personne ne pouvait dire laquelle était la bonne.
Ce n'est pas un problème technique. C'est un problème métier qui prend l'apparence d'un problème technique, et c'est exactement le type de travail que je fais le mieux.
Ce que j'ai construit
Une seule plateforme Django, qui sert les quinze sites : le site public, la prise de rendez-vous, les dossiers patients, le CRM, la logistique de laboratoire, les stocks sur plusieurs entrepôts, la comptabilité fiscale, les RH et le reporting sur les dépenses publicitaires. Le tout derrière une seule interface d'administration, avec un cloisonnement par clinique et par région pour neuf rôles du personnel, de sorte qu'une réceptionniste d'une ville ne peut pas voir les patients d'une autre ville et n'a même pas à se demander pourquoi.
Les fonctionnalités sont la partie banale. Trois des systèmes en dessous méritent d'être décrits, parce que ce sont eux qui font la différence entre un logiciel qui marche le jour du lancement et un logiciel auquel on fait encore confiance deux ans plus tard.
Un flux de consentement qui tiendrait devant un tribunal
Le consentement médical sous le RGPD n'est pas une case à cocher avec un horodatage. Ce qu'il faut pouvoir produire, plus tard, c'est exactement le document qu'une personne donnée a accepté à un moment donné - pas votre version actuelle.
Le flux génère donc le document, l'affiche à l'écran, confirme l'identité avec un code envoyé par SMS et stocke le PDF rendu avec le texte, la langue dans laquelle il a été affiché, l'adresse depuis laquelle il a été signé et une chaîne de hash qui le relie au dossier. Si vous modifiez le modèle ensuite, cela change ce que voit le patient suivant et rien à ce qu'ont accepté les précédents.
La règle sous-jacente : le consentement porte sur une phrase, pas sur
un booléen. Si votre système stocke true, il a stocké la mauvaise
chose.
Le stock comme registre, pas comme nombre
La plupart des systèmes de stock gardent une colonne quantity
dans laquelle le code écrit. Cette colonne finit par être fausse - une race condition, un retry, un clic de travers, un transfert appliqué à moitié - et une fois qu'elle
est fausse il n'y a plus moyen de savoir pourquoi, parce que la preuve a été
écrasée par la réponse.
Ici, la quantité n'est pas stockée. Chaque réception, transfert, consommation et correction est une entrée immuable et signée, et le solde de n'importe quel entrepôt est la somme des entrées qui le touchent. Les corrections ajoutent l'inverse au lieu de modifier l'historique. Cela fait du rapprochement une propriété de la conception plutôt qu'une tâche mensuelle, et cela veut dire que la réponse à « pourquoi en avons-nous onze ? » est toujours disponible et toujours complète.
Vous trouverez plus bas sur la page une version fonctionnelle de cette idée.
Un calendrier qui ne peut pas réserver deux fois le même créneau
Les rendez-vous de quinze cliniques se chevauchent en permanence, et l'accueil doit voir une journée entière d'un coup d'œil, sans que deux rendez-vous occupent jamais le même créneau. C'est le problème classique d'ordonnancement par intervalles : on trie par heure de début, puis on place chaque rendez-vous dans le premier couloir dont le rendez-vous précédent est déjà terminé.
Ce qui justifie de le faire correctement plutôt qu'approximativement, c'est que la version gloutonne est optimale, et on peut le prouver - le nombre de couloirs qu'elle produit est exactement le plus grand nombre de rendez-vous qui se chevauchent à un instant donné, c'est-à-dire une borne inférieure stricte qu'aucun algorithme ne peut battre. Vous pouvez le vérifier sur la démo ci-dessous.
La réalité roumaine
Facturation, journal de caisse et pilotes pour les imprimantes fiscales exigées par la loi. Prothèses suivies par coursier entre la clinique et le laboratoire. Pointage avec un petit client desktop qui envoie un heartbeat. Rien de tout cela n'est de l'ingénierie intéressante, et tout cela fait la différence entre un système que les cliniques utilisent et un système qu'elles contournent.
La décision que je défendrais le plus fermement
Chaque dépendance externe de la plateforme est en fail open. Si le fournisseur de SMS est en panne, si l'API publicitaire limite les requêtes ou si le service de facturation part en timeout, le rendez-vous se finalise quand même, et le travail restant est mis en file d'attente et signalé à un humain.
L'alternative - refuser un rendez-vous parce qu'un tiers n'est pas disponible - revient à faire dépendre votre chiffre d'affaires de la disponibilité de quelqu'un d'autre. Les protections internes fonctionnent à l'inverse : les rate limits, la validation et le honeypot sont en fail closed, parce qu'il n'y a là aucun tiers à blâmer.
Ce que je ferais autrement
Je construirais la couche de reporting plus tôt. J'ai conçu le registre et la planification correctement dès le début et j'ai laissé le reporting se construire au fil de l'eau, si bien que pendant les trois premiers mois, les questions de la direction ont eu pour réponse des requêtes que j'écrivais à la main. Correct, mais lent, et j'aurais dû le voir venir.