betagouv / mon-entreprise

L'assistant officiel des entrepreneurs
https://mon-entreprise.urssaf.fr
MIT License
257 stars 72 forks source link

Édition de la base par différence #156

Closed laem closed 6 years ago

laem commented 6 years ago

Édition de la base par différence

Je mets ici des idées sur le (vaste) sujet de l'ouverture de la contribution.

Aujourd'hui on a dans le moteur du simulateur d'embauche une grande partie des règles des cotisations sociales d'un salarié en CDI ou CDD : une trentaine de règles, et une centaines de variables en tout. Les règles intègrent par exemple les variations statut cadre, effectif entreprise, association à but non lucratif etc.

Aujourd’hui on veut ajouter le statut assimilé salarié , qui permettra notamment à un gérant de SASU de calculer les cotisations sociales sur sa rémunération, qui sont légèrement différentes.

Quelles règles sont impactées par ce statut et comment ? Une recherche sur le Web nous donne ça :

Si le salarié a le statut d'assimilé salarié...

Ces éléments ne sont pas applicables :
- cotisation chômage
- cotisation AGS
- réductions de cotisation : réduction générale sur les bas salaires et réduction de la cotisation d'allocations familiales
- CICE
- le salaire minimum

Et puis : 
- le statut cadre est obligatoire
- son contrat est un CDI

On a donc une liste de règles si assimilé salarié, alors ... .

Comment on encode ça ?

Tout dans la règle

La solution la plus simple, c'est d'enrichir la partie calcul de nos règles (ajouter une exception qui désactive la cotisation chômage) ou la partie contrôle (désactiver la contrainte du SMIC) correspondantes, par exemple avec une ligne non applicable si assimilé salarié . En d'autres termes, on introduit un switch , un aiguillage .

Sauf qu'on va ensuite continuer à enrichir le modèle : après le statut d'assimilé salarié, viendront le régime Alsace-Moselle (qui va impacter la cotisation maladie, les contrôles sur la complémentaire santé et la taxe d'apprentissage), puis peut-être les particularités du régime agricole.

Et puis on arrivera aux conventions collectives et accords de branche, qui multiplieront pas une centaine, voir un millier, le nombre de jeux de changements tel que celui décrit plus haut.

À cela, il faut ajouter les évolutions temporelles de toutes ces règles. En général, on peut dire que la plupart des ~30 éléments changent une fois tous les 2 ans.

Bref, ça en fait des changements, variations, exceptions. Le risque de cette approche est clairement de rendre trop complexe chaque règle de notre base, en intégrant tout ça dans un bloc. C'est un risque pour le contributeur, qui devra se frayer un chemin parmi du code qu'il ne comprend pas avant d'y insérer sa modification, qu'il devrai articuler soigneusement avec le reste.

Une base, et des jeux de différences

L'autre approche, c'est de garder le jeu de règles énoncé plus haut, et le formaliser pour qu'il puisse modifier le modèle. C'est une approche plus distribuée.

Mais comment en pratique allons-nous écrire ces jeux de changements ? Le plus simple est de permettre au contributeur d' éditer directement la base elle-même, sur le Web . Donc pas d'écrire un jeu de changements, mais de simplement éditer l'existant. Une fois les changements faits, et la description du cas dans lequel ces changements s'appliquent, un clic permet d'enregistrer les changements sous forme d'un diff, un jeu de différence pour la machine (c'est le système qui s'en charge).

Ça ne marchera que si c'est simple à faire directement sur le Web.

Dans certains cas cependant, le contributeur modifiera une règle sans vouloir créer une extension, donc sans stocker de différence à conserver : par exemple le taux de la base est erroné ou sa référence (ex. URL vers la fiche URSSAF) est obsolète. Attention : si c'est par exemple un mécanisme de calcul qu'on renomme, c'est-à-dire qu'on modifie le langage, il faut bien sûr faire évoluer chaque jeu de changements en conséquence.

Dans certains cas, on aura affaire à une extension en étoile. Par exemple, chaque convention collective peut augmenter le taux minimum de la complémentaire santé à payer par l'employeur, fixé de base à 50%. Toutes ces conventions sont perpendiculaires, elles vivent leur vie sans s'influencer.

Dans d'autres cas, par exemple les évolutions temporelles, on aura plutôt affaire à des changements chaînés à partir d'une base, qui est soit l'apparition de la règle, soit sa plus vieille version connue.

La "forme" des différences dépend type de la variable qui s'applique. Booléen (statut cadre : deux branches), catégories (liste de conventions collectives : étoile), variable "continue" (date, effectif entreprise : changements chaînés).

Évidemment, on pourrait simplement dire à notre contributeur Syntec : prend la base de règles, copie-la chez toi, édite-la et voila. Ou encore, prend juste la cotisation de complémentaire santé (et les autres éléments impactés dans ton cas), et fais tes modifications. Sauf que dans la base comme dans la règle de complémentaire santé elle-même, il y a de la donnée en commun, non impactée par la modification de Syntec : comment le panier minimal est défini, l'assiette de la cotisation etc.

Il faut donc que le jeu de changements ne touche qu'à la donnée précise qu'il modifie, et que le reste soit gardé en commun, notamment pour que les utilisateurs Syntec puissent profiter des mises à jour de ce commun sans effort.

Et donc, techniquement, cela exclut un stockage de la différence à la git, sous forme de modifications des lignes de code d'un fichier. Il faut qu'une différence puisse cibler un élément précis d'une règle pour le surcharger.

Ça ne vous rappelle rien ? C'est comme ça que fonctionne le CSS pour surcharger le style des éléments du DOM.

Dans certains cas évidemment, il y aura des conflits. Mon accord de branche lui aussi a son mot à dire sur le taux de complémentaire santé. Une autre règle devra définir la priorité entre les jeux de changement, tout comme en CSS un #id sera prioritaire sur une .classe.

Pour résumer, on peut voir dans cette approche les avantages suivants.

Difficulté : les changements croisés

À développer avec des exemples plus précis, complexes et réels. On voit déjà bien les complexités.

Pourquoi c'est mieux que l'inverse ?

Évidemment, on peut aussi se dire qu'en restant dans la première approche, celle des grosses règles complexes, un éditeur sur le Web pourrait cacher cette complexité au contributeur (ex. lui montrer seulement la partie valable en 2018 si c'est les versions récentes qui l'intéressent).

Pourquoi choisir l'approche décentralisée ? À développer avant de commencer quoi que ce soit.

Proposition concrète pour le cas de l'assimilé salarié

À continuer après avoir développé le point précédent.

Mettre tout dans un fichier unique.

Cliquer sur un bouton pour commencer une édition. On choisit entre 2 modes : édition simple et par différenciation. Explication de ce que ça veut dire : quand il y a une base et des exceptions.

Si édition différentiée, donner le cas : la variable et sa valeur. Booléen et catégorie. On verra le temps et les nombres plus tard.

A priori, les changement de l'assimilé salarié c'est surtout ajouter des "non applicable".

Ctrl-P pour naviguer de variable en variable. On peut revenir en arrière pour naviguer par espace de nom. Si c'est pas suffisant, implémentation d'onglets LRU, mais c'est louds en termes de développement d'UI.

Ctrl-T pour créer une variable.

Une fois fini, 🆗 → PR github. Sans la plomberie dans un 1er temps, juste copier coller le diff généré.

Il faut définir le format du diffo (diff d' o bjets). En-tête, la variable, et la liste des modifications espace . Il y a des libs qui diff des JSON "sémantiquement", les tester. Pour l'édition des YAML, on a le Monaco editor qui fait tourner VSCode.

laem commented 6 years ago

@Anna-Livia je t'en ai parlé hier

laem commented 6 years ago

La lib deep-diff semble très intéressant pour créer les diffs d'objets. Pendant l'édition, une vue visuelle de diff ligne par ligne peut-être intéressante. Monaco en propose une avec support du yaml (application/x-yaml) et il en existe d'autres.