Les changements dans les systèmes logiciels complexes semblent prendre une éternité, non? Même les ingénieurs pensent souvent que les changements vont au-delà de ce qui est censé être, bien que nous soyons conscients de la complexité du système!
Pour les clients, la situation est encore plus incompréhensible. Le problème est aggravé par une complexité aléatoire, qui est ajoutée au fil du temps en raison d'une mauvaise prise en charge du système. On a le sentiment que nous essayons de puiser l'eau d'un navire à mille trous.
Par conséquent, tôt ou tard, le client enverra une lettre: "Pourquoi diable cela prend-il si longtemps?" N'oublions pas que nous, en tant qu'ingénieurs logiciels, avons une fenêtre sur le monde, dont ils manquent souvent. Ils nous font beaucoup confiance, mais parfois un changement apparemment insignifiant prend vraiment beaucoup de temps. Pour cette raison, des questions se posent.
Ne soyez pas offensé par cette question; saisir l'occasion pour montrer de l'empathie et donner à une personne une image plus claire de la complexité du système. En même temps, vous pouvez suggérer des moyens d'améliorer la situation. Quand quelqu'un est bouleversé, c'est le meilleur moment pour proposer une solution!
Une lettre est publiée ci-dessous, que nous avons envoyée à plusieurs reprises au fil des ans sous une forme ou une autre. Nous espérons que cela vous aidera à répondre à ces questions.
Une lettre
Cher client,
J'ai vu votre commentaire sur la carte «Avertir avant l'expiration de la mission» et je serai heureux d'en discuter lors de notre prochaine réunion. Ici, pour référence, je vais résumer mes pensées, il n'est pas nécessaire de répondre.
Pour paraphraser votre note:
La modification du délai de réalisation des tâches d'un jour pour la notification par courrier doit prendre une ligne. Comment cela peut-il prendre 4 à 8 heures? Qu'est-ce qui me manque?D'une part, je suis d'accord avec vous. Remplacez simplement la partie demande des
tasks due <= today
par des
tasks due <= tomorrow
.
D'un autre côté, en le réduisant à une idée aussi simplifiée, nous ignorons par inadvertance la complexité inhérente et prenons un certain nombre de décisions d'ingénierie. Nous devons discuter de certains d'entre eux.
Partie 1. Pourquoi ce petit changement est-il plus qu'il n'y paraît?
Il s'agit d'une simple petite modification, une ligne de code. Passer toute la journée dessus, même une demi-journée, semble excessif.
Bien sûr, vous ne pouvez pas simplement déployer un changement dans la production sans exécuter au moins localement ou sur un serveur de test. Vous devez vous assurer que le code est exécuté correctement et si la demande change, vous devez comparer la sortie et vous assurer qu'elle semble plus ou moins correcte.
Ici, la comparaison de la sortie peut être minime, juste une petite vérification ponctuelle: assurez-vous que les résultats ont un sens, etc. Il s'agit d'une notification pour les employés internes. Si le calcul par date est incorrect (une légère erreur), nous en entendrons rapidement parler par les équipes. S'il s'agissait, par exemple, d'un e-mail pour vos clients, une étude plus approfondie serait nécessaire. Mais pour ce test et cet examen faciles, 20 à 40 minutes suffisent, selon que quelque chose d'étrange ou d'inattendu apparaît. Creuser des données peut prendre du temps. Publier des modifications sans procéder à un examen est tout simplement une négligence non professionnelle.
Ainsi, nous ajoutons du temps pour la logistique normale, comme la validation d'un code, la fusion des modifications, le déploiement, etc.: du début du travail à la mise en production, au moins une heure passe d'un ingénieur compétent et professionnel.
Bien sûr, cela suppose que vous savez exactement quelle ligne de code modifier. Le flux de travail des tâches réside essentiellement dans l'ancien système, mais certaines parties de la logique vivent dans le nouveau système. Déplacer la logique de l'ancien système est bon, mais cela signifie que la fonctionnalité de la tâche est actuellement divisée en deux systèmes.
Depuis que nous travaillons ensemble depuis si longtemps, notre équipe sait quel processus envoie un e-mail avec une tâche expirée et peut pointer vers une ligne de code dans le nouveau système qui initie le processus. Nous n'avons donc pas à perdre de temps à comprendre cela.
Mais si nous regardons le code de tâche dans l'ancien système, il existe au moins quatre façons différentes de déterminer si la tâche est due. En outre, en regardant les modèles et le comportement des e-mails, il existe au moins deux autres endroits où il semble que la logique personnalisée pour cette tâche soit implémentée.
Et puis la logique de notification est plus compliquée que vous ne le pensiez. Il distingue les tâches générales et individuelles, ouvertes et privées, répétitives, la fonction de notification supplémentaire du gestionnaire en cas de tâche en retard, etc. Mais nous pouvons rapidement découvrir qu'en fait, seules 2 définitions sur 6+ de la tâche en retard sont utilisées pour les notifications. Et une seule chose doit être changée pour atteindre l'objectif.
Un tel examen peut facilement prendre encore une demi-heure environ, peut-être moins si vous avez récemment été dans cette partie de la base de code. De plus, la complexité latente signifie que nous pouvons dépasser notre estimation pour les tests manuels. Mais ajoutons juste 30 minutes pour un effort supplémentaire.
Ainsi, nous avons atteint 1,5 heure pour être confiants que le changement se fera comme prévu.
Bien sûr, nous n'avons pas encore vérifié si d'autres processus utilisent une requête mutable. Nous ne voulons pas perturber accidentellement d'autres fonctions en changeant le concept de «délai» au jour qui précède le dernier jour pour terminer la tâche. Nous devons considérer la base de code de ce point de vue. Dans ce cas, il ne semble pas y avoir de dépendances majeures - probablement parce que la majeure partie de l'interface utilisateur est toujours sur l'ancien système. Par conséquent, vous n'avez pas à vous soucier de modifier ou de tester d'autres processus. Dans le meilleur des cas, c'est encore 15-30 minutes.
Oh, et comme la partie principale de l'interface utilisateur de la tâche se trouve toujours dans l'ancien système, nous devons vraiment faire un rapide aperçu de la fonctionnalité de la tâche dans ce système et nous assurer que les commentaires sont corrects. Par exemple, si l'interface utilisateur met en évidence les tâches dont l'échéance est arrivée, nous pouvons modifier cette logique pour correspondre à la notification. Ou au moins revenir et demander au client comment il veut le faire. Récemment, je n'ai pas regardé la fonctionnalité de la tâche dans l'ancien système et je ne me souviens pas s'il a une idée du délai / délai. Cet examen ajoute 15 à 30 minutes supplémentaires. Peut-être plus si l'ancien système avait également plusieurs définitions d'une «tâche», etc.
Ainsi, nous sommes allés dans la plage de 2 à 2,5 heures pour terminer la tâche avec la certitude que tout ira bien, sans effets secondaires imprévus ni confusion dans le travail de l'utilisateur.
Partie 2. Comment puis-je réduire ce temps?
Malheureusement, le seul résultat de ces efforts n'est que l'accomplissement de la tâche. Ce n'est pas optimal, ce qui est très décevant. Les connaissances acquises par le développeur au cours du travail sont personnelles et éphémères. Si un autre développeur (ou nous-mêmes après 6 mois) doit à nouveau apporter des modifications à cette partie du code, le processus devra être répété.
Il existe deux tactiques principales pour remédier à la situation:
- Nettoyez activement la base de code pour réduire la duplication et la complexité.
- Écrivez des tests automatisés.
Remarque: nous avons déjà discuté de la documentation, mais dans ce cas, ce n'est pas la meilleure solution. La documentation est utile pour des idées de haut niveau, telles que l'explication de la logique métier ou des processus fréquemment répétés, comme une liste de nouveaux partenaires. Mais quand il s'agit de code, la documentation devient rapidement trop volumineuse et devient obsolète à mesure que le code change.
Vous avez remarqué qu'aucune de ces tactiques n'est incluse dans nos 2 à 2,5 heures.
Par exemple, le maintien d'une base de code propre signifie qu'au lieu de simplement terminer la tâche, nous posons des questions:
- Pourquoi y a-t-il tant de façons différentes d'identifier les tâches dont le délai a approché / expiré?
- Ont-ils tous besoin d'eux et y travaillent-ils?
- Ces méthodes peuvent-elles être réduites à un ou deux concepts / méthodes?
- Si le concept est partagé entre l'ancien et le nouveau système, peut-il être consolidé?
Et ainsi de suite.
Les réponses à ces questions peuvent être assez rapides: par exemple, si nous rencontrons un code clairement mort. Ou cela peut prendre plusieurs heures: par exemple, si les tâches sont utilisées dans de nombreux processus complexes. Dès que nous aurons ces réponses, il faudra encore plus de temps pour refactoriser afin de réduire la duplication / confusion et obtenir une description unique du concept de «délai» - ou renommer les concepts dans le code pour comprendre clairement en quoi ils diffèrent et pourquoi.
Mais au final, cette partie de la base de code deviendra beaucoup plus simple, elle sera plus facile à lire et à modifier.
Une autre tactique que nous utilisons habituellement est le test automatisé. Dans un sens, les tests automatisés sont similaires à une documentation qui ne peut pas être obsolète et qui est plus facile à détecter. Au lieu d'exécuter manuellement le code et d'afficher la sortie, nous écrivons un code de test qui lance la demande et vérifie la sortie par programme. N'importe quel développeur peut exécuter ce code de test pour comprendre comment le système devrait fonctionner et pour s'assurer qu'il fonctionne toujours de cette façon.
Si vous avez un système avec une couverture de test décente, ces changements prendront beaucoup moins de temps. Vous pouvez modifier la logique, puis exécuter la suite de tests complète et vous assurer que
- le changement fonctionne correctement;
- le changement n'a rien cassé (c'est une information encore plus précieuse que dans le premier paragraphe).
Lorsque nous construisons des systèmes à partir de zéro chez Simple Thread, nous incluons toujours du temps pour écrire des tests automatisés dans l'évaluation des délais. Cela peut ralentir le développement initial, mais améliore considérablement l'efficacité du travail et de la maintenance. Ce n'est que lorsque le système se développe que vous comprenez vraiment l'importance des tests, mais à ce stade, il peut être très difficile de renvoyer les tests au système. La présence de tests simplifie également considérablement le travail des nouveaux employés, et changer le comportement du système est beaucoup plus rapide et plus sûr.
Partie 3. D'où venons-nous? Où allons-nous?
Aujourd'hui, nous indiquons rarement dans votre évaluation le temps d'effacer le code ou d'écrire des tests. Cela est dû en partie au fait que l'écriture de tests à partir de zéro est un surcoût mineur, et l'ajout de tests à l'antidatage de la base de code représente beaucoup de travail, comme la restauration des fondations sous la maison dans laquelle les gens vivent.
Cela est également dû en partie au fait que lorsque nous commençons à travailler avec vous, nous passons immédiatement en mode de réanimation. Nous avons des problèmes presque quotidiens avec la synchronisation des données tierces, des problèmes hebdomadaires avec la génération de rapports, des demandes constantes pour prendre en charge de petites modifications de données, une surveillance inadéquate et la journalisation du système, etc. La base de code se noie sous le poids des dettes techniques, et nous essayons fiévreusement de garder les systèmes sous tension flotter, tout en collant des trous avec du ruban électrique.
Au fil du temps, les systèmes deviennent plus stables et fiables, nous automatisons / fournissons une interface utilisateur pour le libre-service des demandes d'assistance fréquentes. Nous avons encore beaucoup de dettes techniques, mais nous sommes sortis du mode urgence. Mais je ne pense pas que nous nous éloignerons jamais complètement de cette mentalité de réanimation pour une mentalité plus proactive et mûre de «planifier et exécuter».
Nous essayons d'effacer le code lors de nos déplacements et nous testons toujours en profondeur. Mais être prudent et diligent n'est pas une refactorisation proactive ou la création de l'infrastructure nécessaire à de bons tests automatisés.
Si nous ne commençons pas à payer certaines dettes techniques, nous ne pourrons jamais améliorer sensiblement la situation. Les développeurs hautement qualifiés et compétents mettront des mois à naviguer et à apporter des modifications non triviales.
En d'autres termes, 4 à 8 heures pour cette tâche représentent environ 2 à 4 fois l'approvisionnement, mais cela réduira considérablement les efforts pour de tels changements à l'avenir. Si cette partie de la base de code était plus propre et avait une bonne couverture avec des tests automatiques, un développeur expérimenté compétent la compléterait en une heure ou moins. Et le point clé est que le nouveau développeur prendra un peu plus de temps.
Pour un tel changement de conditions, nous avons besoin de votre consentement. Il s'agit d'une tentative consciente d'améliorer fondamentalement les performances de votre système, pas seulement la façon dont les utilisateurs le perçoivent. Je comprends qu'il est difficile d'accepter de tels investissements précisément parce qu'il n'y a aucun avantage visible, mais nous sommes heureux de vous asseoir et de préparer des chiffres clairs qui montreront comment ces investissements seront rentables à long terme d'un point de vue technique.
Je vous remercie
Al