Categories
Agile Development Programming Software Architecture

Pratiques du génie logiciel

Gergely Orosz a lancé une conversation sur Twitter en posant des questions sur les “pratiques d’ingénierie logicielle” recommandées pour les équipes de développement.

(J’aime vraiment son rejet du terme « meilleures pratiques » ici : j’ai toujours l’impression qu’il est normatif et erroné d’annoncer quelque chose comme étant « la meilleure ».)
J’ai décidé d’étoffer certaines de mes réponses dans un article plus long.

Gergely Orosz a lancé une conversation sur Twitter en posant des questions sur les “pratiques d’ingénierie logicielle” recommandées pour les équipes de développement.

(J’aime vraiment son rejet du terme « meilleures pratiques » ici : j’ai toujours l’impression qu’il est normatif et erroné d’annoncer quelque chose comme étant « la meilleure ».)

J’ai décidé d’étoffer certaines de mes réponses dans un article plus long.

  • Documentation dans le même référentiel que le code
  • Mécanismes de création de données de test
  • Migrations de bases de données solides comme le roc
  • Modèles pour les nouveaux projets et composants
  • Formatage de code automatisé
  • Processus testé et automatisé pour les nouveaux environnements de développement
  • Environnements de prévisualisation automatisés

Documentation dans le même référentiel que le code

La caractéristique la plus importante de la documentation interne est la confiance : les gens ont-ils confiance dans le fait que la documentation existe et est à jour ?

S’ils ne le font pas, ils ne le liront pas ou n’y contribueront pas.

La meilleure astuce que je connaisse pour améliorer la fiabilité de la documentation est de la placer dans le même référentiel que le code qu’elle documente, pour plusieurs raisons :

  1. Vous pouvez appliquer les mises à jour de la documentation dans le cadre de votre processus de révision du code. Si un PR modifie le code d’une manière qui nécessite des mises à jour de la documentation, l’examinateur peut demander que ces mises à jour soient incluses.
  2. Vous obtenez une documentation versionnée. Si vous utilisez une ancienne version d’une bibliothèque, vous pouvez consulter la documentation de cette version. Si vous utilisez la branche principale actuelle, vous pouvez consulter la documentation correspondante, sans confusion sur ce qui correspond à la version « stable » la plus récente.
  3. Vous pouvez intégrer votre documentation à vos tests automatisés ! J’ai écrit à ce sujet dans Documentation unit tests , qui décrit un modèle d’introspection du code, puis s’assure que la documentation a au moins un en-tête de section qui correspond à des concepts spécifiques, tels que les crochets de plug-in ou les options de configuration.

Mécanismes de création de données de test

Lorsque vous travaillez sur de gros produits, vos clients trouveront inévitablement des moyens surprenants de stresser ou de casser votre système. Ils peuvent créer un événement avec plus d’une centaine de types de tickets différents, par exemple, ou un fil de discussion avec un millier de commentaires.

Ceux-ci peuvent exposer des problèmes de performances qui n’affectent pas la majorité de vos utilisateurs, mais peuvent néanmoins entraîner des interruptions de service ou d’autres problèmes.

Vos ingénieurs ont besoin d’un moyen de reproduire ces situations dans leurs propres environnements de développement.

Une façon de gérer cela consiste à fournir des outils pour importer des données de production dans des environnements locaux. Cela a des implications sur la confidentialité et la sécurité : que se passe-t-il si un ordinateur portable de développeur est volé alors qu’il contient une copie des données de votre client le plus important ?

Une meilleure approche consiste à mettre en place un système robuste pour générer des données de test, qui couvre une variété de scénarios différents.

Vous pourriez avoir un bouton quelque part qui crée un fil de discussion avec mille faux commentaires, avec une note faisant référence au bogue que cela aide à imiter.

Chaque fois qu’un nouveau cas marginal apparaît, vous pouvez ajouter une nouvelle recette à ce système. De cette façon, les ingénieurs peuvent reproduire les problèmes localement sans avoir besoin de copies des données de production.

Migrations de bases de données solides comme le roc

La partie la plus difficile de la maintenance logicielle à grande échelle est inévitablement la partie où vous devez modifier le schéma de votre base de données.

(Je suis convaincu que l’une des principales raisons pour lesquelles les bases de données NoSQL sont devenues populaires au cours de la dernière décennie était la douleur que les gens avaient associée aux bases de données relationnelles en raison des changements de schéma. Bien sûr, les modifications de schéma de base de données NoSQL sont toujours nécessaires, et souvent elles sont même plus douloureux!)

Vous devez donc investir dans un très bon mécanisme de contrôle de version pour gérer les modifications de schéma. Et un moyen de les exécuter en production sans temps d’arrêt.

Si vous ne l’avez pas, vos ingénieurs réagiront en craignant les changements de schéma. Ce qui signifie qu’ils trouveront des hacks de plus en plus complexes pour les éviter, ce qui accumule la dette technique.

C’est un sujet profond. J’utilise principalement Django pour de grandes applications basées sur des bases de données, et Django possède le meilleur système de migration que j’aie jamais expérimenté personnellement. Si je travaille sans Django, j’essaie de reproduire son approche aussi fidèlement que possible :

  • La base de données sait quelles migrations ont déjà été appliquées. Cela signifie que lorsque vous exécutez la commande « migrate », elle peut exécuter uniquement celles qui sont encore nécessaires, ce qui est important pour la gestion de plusieurs bases de données, par exemple les environnements de production, de transfert, de test et de développement.
  • Une seule commande qui applique les migrations en attente et met à jour les lignes de la base de données qui enregistrent les migrations exécutées.
  • Facultatif : restaurations. Les migrations Django peuvent être annulées, ce qui est idéal pour itérer dans un environnement de développement, mais l’utiliser en production est en fait assez rare : j’expédie souvent une nouvelle migration qui annule le changement plutôt que d’utiliser une annulation, en partie pour conserver l’enregistrement de l’erreur dans le contrôle de version.

Encore plus difficile est le défi de faire des changements de schéma sans aucun temps d’arrêt. Je suis toujours intéressé à en savoir plus sur les nouvelles approches pour cela – le gh-ost de GitHub est une solution intéressante pour MySQL.

Une considération intéressante ici est qu’il est rarement possible que les modifications du code d’application et du schéma de la base de données soient effectuées exactement au même moment. Par conséquent, pour éviter les temps d’arrêt, vous devez concevoir chaque changement de schéma en gardant cela à l’esprit. Le processus doit être :

  1. Concevez une nouvelle modification de schéma pouvant être appliquée sans modifier le code d’application qui l’utilise.
  2. Expédiez ce changement en production, en mettant à niveau votre base de données tout en gardant l’ancien code en état de marche.
  3. Expédiez maintenant le nouveau code d’application qui utilise le nouveau schéma.
  4. Expédiez une nouvelle modification de schéma qui nettoie tout le travail restant, en supprimant les colonnes qui ne sont plus utilisées, par exemple.

Ce processus est une douleur. C’est difficile d’avoir raison. La seule façon de devenir bon dans ce domaine est de le pratiquer beaucoup au fil du temps.

Ma règle est la suivante : les changements de schéma doivent être ennuyeux et courants , au lieu d’être passionnants et rares.

Modèles pour les nouveaux projets et composants

Si vous travaillez avec des microservices, votre équipe devra inévitablement en créer de nouveaux.

Si vous travaillez dans un monorepo, vous aurez toujours des éléments de votre base de code avec des structures similaires – des composants et des implémentations de fonctionnalités de quelque sorte.

Assurez-vous d’avoir de très bons modèles en place pour les créer “de la bonne manière” – avec la bonne structure de répertoires, un fichier README et une suite de tests avec un seul test de réussite stupide.

J’aime utiliser l’outil Python cookiecutter pour cela. J’ai également utilisé des référentiels de modèles GitHub, et j’ai même une astuce pour combiner les deux fichiers .

Ces modèles doivent être maintenus et mis à jour. La meilleure façon d’y parvenir est de s’assurer qu’ils sont utilisés. Chaque fois qu’un nouveau projet est créé, vous avez l’occasion de réviser le modèle et de vous assurer qu’il reflète toujours la manière recommandée de faire les choses.

Formatage de code automatisé

Celui-ci est facile. Choisissez un outil de formatage de code pour votre langage, comme Black pour Python ou Prettier pour JavaScript (je suis tellement jaloux de la façon dont Go a intégré gofmt ) et exécutez son mode « vérification » dans votre flux CI.

Ne contestez pas ses valeurs par défaut, engagez-vous simplement à les respecter.

Cela permet de gagner un temps incroyable à deux endroits :

  • En tant qu’individu, vous récupérez toute cette énergie mentale que vous aviez l’habitude de dépenser pour réfléchir à la meilleure façon de formater votre code et vous pouvez la dépenser pour quelque chose de plus intéressant.
  • En équipe, vos révisions de code peuvent entièrement ignorer les arguments pédants sur le formatage du code. Énorme gain de productivité !

Processus testé et automatisé pour les nouveaux environnements de développement

La partie la plus pénible de tout projet logiciel est inévitablement la mise en place de l’environnement de développement initial.

Au moment où votre équipe grandit au-delà de quelques personnes, vous devez investir pour améliorer ce travail.

À tout le moins, vous avez besoin d’un processus documenté pour créer un nouvel environnement – et il doit être connu pour fonctionner, donc chaque fois que quelqu’un est intégré à l’utiliser, il doit être encouragé à résoudre tout problème dans la documentation ou les scripts d’accompagnement comme ils les rencontrent.

Un processus automatisé est bien meilleur : un seul script qui met tout en place et fonctionne. Des outils comme Docker ont rendu cela BEAUCOUP plus facile au cours de la dernière décennie.

Je suis de plus en plus convaincu que la meilleure solution ici est les environnements de développement basés sur le cloud. La possibilité de cliquer sur un bouton sur une page Web et d’avoir un nouvel environnement de développement opérationnel quelques secondes plus tard change la donne pour les grandes équipes de développement.

Gitpod et Codespaces sont deux des outils les plus prometteurs que j’ai essayés dans cet espace.

J’ai vu des développeurs perdre des heures par semaine à cause de problèmes avec leur environnement de développement. Éliminer cela dans une grande équipe équivaut à embaucher plusieurs nouveaux ingénieurs à temps plein !

Environnements de prévisualisation automatisés

L’examen d’une demande d’extraction est beaucoup plus facile si vous pouvez réellement essayer les modifications.

La meilleure façon d’y parvenir est d’utiliser des environnements de prévisualisation automatisés, directement liés au PR lui-même.

Ceux-ci sont de plus en plus faciles à proposer. Vercel , Netlify , Render et Heroku ont tous des fonctionnalités qui peuvent le faire. Construire un système personnalisé sur quelque chose comme Google Cloud Run ou Fly Machines est également possible avec un peu de travail.

C’est une autre de ces choses qui nécessite un investissement initial, mais qui se rentabilisera plusieurs fois grâce à une productivité et une qualité des avis accrues.

Leave a Reply Cancel reply