Gérer les risques qui comptent vraiment
Dans une migration Netezza, les risques dangereux sont rarement ceux sur
le tableau de bord du convertisseur. Ce sont les hypothèses cachées dans
l'appliance, les données auxquelles l'entreprise fait confiance et les
transferts entre équipes. Nous avons géré un registre complet de ces
risques, et les plus instructifs sont ci-dessous. Chacun comporte le
risque, l'atténuation que nous avons appliquée et le plan de repli
lorsque l'atténuation n'était pas suffisante. Le registre complet, avec
chaque entrée notée et suivie, accompagne cet article comme un outil de
travail distinct. Accédez au registre ici pour votre propre usage.
Mappings et logique d'affaires non documentés. Le
programme avançait bien jusqu'à la couche de transformation, puis
risquait de s'enliser parce que les règles derrière les tables de
confiance n'avaient jamais été documentées. Nous avons fait des mappings
confirmés un critère d'entrée strict : le travail Silver sur un domaine
ne commençait pas avant que ses règles soient validées par les experts
métier du client. Lorsqu'un écart apparaissait en milieu de vague, nous
signalions immédiatement la reprise, redéfinissions les priorités pour
que les domaines non bloqués continuent d'avancer, et mettions en
quarantaine la logique contestée plutôt que de deviner.
Constructions sans équivalent direct. Le code
procédural écrit en NZPLSQL, les tables temporaires et les contraintes
de colonnes comme UNIQUE et DEFAULT n'existent pas sous la même forme
sur Databricks. Une conversion littérale échoue ou, pire, change
silencieusement le comportement. Nous avons refactorisé les procédures
stockées en une combinaison de notebooks SQL et Python, remplacé les
tables temporaires par des vues temporaires à portée de session, et
reconstruit les contraintes comme logique de validation explicite, en
établissant chaque pattern une fois et en le réutilisant à travers les
vagues. Les cas vraiment difficiles étaient acheminés vers une piste
manuelle pour ne jamais bloquer le flux automatisé.
Différences de comportement au niveau des fonctions.
Certains codes compilent et s'exécutent mais produisent des résultats
différents. Un exemple documenté est
add_months, qui gère les années bissextiles différemment sur les deux
plateformes. Ce type de différence passe un contrôle de syntaxe et
échoue à un audit d'affaires. Nous avons maintenu un catalogue des
différences connues et ajouté des tests ciblés pour chaque fonction qui
y figurait. Lorsqu'une différence apparaissait dans une exécution en
parallèle, nous corrigions le pattern de façon centralisée et relancions
la validation plutôt que de corriger un job à la fois.
Différences de modèle de transaction et de rollback.
Les équipes supposent que la sémantique de concurrence Netezza est
transposable. Elle ne l'est pas. Delta utilise par défaut un niveau
d'isolation write serializable, sous lequel un lecteur peut brièvement
voir un état que l'historique de la table dit n'avoir jamais existé, et
le ROLLBACK de Netezza n'a pas d'équivalent direct. Nous avons réglé
l'isolation à serializable là où la justesse de la concurrence importait
et remplacé les patterns de rollback par le versionnement Delta pour
l'audit et la récupération. Pour les pipelines les plus sensibles, nous
les avons exécutés en single thread jusqu'au basculement et n'avons levé
la concurrence qu'une fois les résultats confirmés.
Données qui ne réconcilient pas au basculement. Le
programme peut atteindre la mise en production pour se voir refuser
l'approbation parce que personne ne peut prouver que les chiffres
correspondent. Nous avons traité la validation comme continue plutôt que
comme un événement final, en exécutant des vérifications de comptage de
lignes, au niveau des colonnes, au niveau des lignes et par
sous-ensembles à chaque cycle. Lorsqu'un écart persistait, la
contingence était simple et ferme : prolonger l'exécution en parallèle
et retenir le basculement jusqu'à ce que la différence soit soit nulle,
soit expliquée et acceptée par écrit.
Consommateurs laissés sans source pendant la transition.
Décommissionner une source ou couper un pipeline avant que chaque
consommateur en aval ait migré éteint un rapport critique. Nous avons
exécuté les pipelines legacy et Databricks concurremment avec des flux
de données temporaires pour qu'aucun consommateur ne soit jamais sans
source, et nous avons échelonné le décommissionnement de Netezza
seulement après avoir confirmé le basculement de chaque consommateur. Le
chemin legacy restait chaud et réversible jusqu'à ce que le dernier
consommateur soit vérifié, ce qui faisait d'un rollback un interrupteur
plutôt qu'une reconstruction.
Deux autres risques méritent d'être mentionnés même en résumé, parce
qu'ils coulent les programmes en silence : les environnements qui
arrivent en retard, que nous avons gérés en exigeant que les
environnements de développement et d'intégration soient provisionnés
avant le début et en faisant passer tout retard par un contrôle de
changement formel pour que son impact sur le calendrier soit visible
plutôt qu'absorbé; et les budgets de calcul dimensionnés par rapport à
l'empreinte de l'appliance plutôt qu'aux patterns d'accès réels, que
nous avons détectés en validant le budget par rapport au comportement
réel des requêtes durant la découverte et en escaladant la portée tôt
plutôt qu'à l'étape clé.
Le fil conducteur à travers chaque contingence est le même. Le modèle
agile par vagues donne à un problème un endroit où exister. Un risque
qui émerge à l'intérieur d'une vague de deux semaines est un événement
gérable. Le même risque à l'intérieur d'un big bang est un échec de
programme.