Subjectivement: le refactoring est une «maladie» juvénile. Selon des observations personnelles, quelque part après 26 ans commence à lâcher prise. Comme dans cette vieille phrase: «Celui qui n'était pas révolutionnaire dans sa jeunesse - il n'a pas de cœur, celui qui ne devient pas conservateur à maturité - il n'a pas d'esprit. Par conséquent, jusqu'à ce que je lâche enfin prise, j'essaierai de décrire les cas d'utilisation du refactoring et les objectifs possibles qui peuvent être atteints avec.
Inspirateurs
J'ai commencé à écrire après la prochaine visualisation de la demande de pull pour plus de 150 fichiers, où de nouvelles fonctionnalités et une refactorisation de celles existantes étaient farouchement impliquées. Le refactoring n'était pas seulement esthétique, mais aussi logique, ce qui causait la plus grande douleur. Par exemple, dans Ruby, le amount == 0
hardiment remplacé par le amount.zero?
sans considérer que pour le cas d'un amount
nil
amount
ces constructions ne sont pas équivalentes. Tout cela a été expliqué approximativement comme suit: "mais selon le code, la norme est tellement supposée!" À la question logique "quel est le but de suivre le code à la norme et en général, quel est votre objectif en tant que développeur?" l'homme s'est enfermé et a répété un peu coupable "mais selon la norme du code, vous devez écrire comme ça ..." et ressemblait à une blonde dans un magasin de vêtements qui ne pouvait pas faire face au désir refactor acheter tout.
Définition
Le sujet est sensible, vous devez donc porter une attention particulière à la question "qui est qui?" Ainsi, selon le wiki , la refactorisation est un processus de changement de la structure interne d'un programme qui n'affecte pas son comportement externe et vise à faciliter la compréhension de son travail.
Pour ma part, je veux réduire les limites et définir le refactoring (au pire sens du terme) comme tout changement qui n'est pas directement lié au problème résolu et qui ne change pas le comportement externe du système, mais qui est effectué dans le cadre de la tâche d'origine.
Autrement dit, je ne veux pas parler du changement prévu dans la base de code, pour lequel la portée du travail a été définie et des objectifs spécifiques ont été fixés, mais des modifications spontanées qui se produisent pendant le développement.
Valeur du produit
Je vais maintenant partir de loin. Le code source n'est ni un objectif ni une valeur. Bien sûr, esthétiquement ou artistiquement, cela peut présenter un certain intérêt, mais ce sont des exceptions. En général, le code est un outil pour créer un produit logiciel que n'importe qui utilise. Par conséquent, pour commencer, il serait bon de déterminer quelles sont les valeurs du produit.
Valeurs directes des produits
Ici, tout est simple. Ils utilisent le produit, donc les valeurs directes sont ce que l'utilisateur ressent / voit / ressent clairement. À savoir:
- toutes sortes de fonctionnalités du produit;
- utilisabilité (UI / UX, performances, tolérance aux pannes, etc.).
Le deuxième point peut susciter quelques discussions. Après tout, beaucoup pensent que ce n'est pas l'essentiel. Puisque si la fonctionnalité est bonne, peu importe dans quoi elle est enveloppée. Bons exemples de fonctionnalités sans UI / UX sensées : Redmine et SAP . Cependant, je suis en désaccord avec ce regard et de plus près dans l'opinion du camarade Alan Cooper et de son «hôpital psychiatrique entre les mains des patients».
Valeurs indirectes des produits
Ce sont des valeurs qui en elles-mêmes n'affectent pas l'utilisateur. Mais ils peuvent «tirer» ou «s'accumuler» et avoir un impact (de gravité variable) sur le produit ou ses fonctionnalités.
- Bugs. Un cas limite de valeurs. Ils sont secondaires parce que les valeurs elles-mêmes ne portent pas, mais les empruntent aux caractéristiques voisines.
- Propreté. Il s'agit de lisibilité, de modularité, de minimisation des composants entrants, de standardisation et d'unification des interfaces, etc.
- La documentation Il s'agit de code et d'explications pour les développeurs, pas de descriptions d'entreprise ou de comptes d'utilisateurs. Elle est bien illustrée par la phrase d'un paysan gai d'une des interviews: "La logique dans la base de données est écrite comme un livre."
- Évolutivité / sécurité / sécurité. L'utilisateur ne les voit que lorsque quelque chose de grave se produit.
Valeurs du développeur
Une catégorie très importante que beaucoup négligent, mais qui affecte toujours le résultat.
- Code par norme.
- Indentation sur le feng shui.
- Autres transactions avec conscience. Après tout, le code a été écrit, donc il y a un résultat pour la journée, et donc il y a un avantage.
- Conformité du code avec le monde intérieur.
Mais soyons honnêtes. Tout cela ne concerne pas les valeurs associées au produit et à l'utilisateur final. Il s'agit de psychologie et de cafards personnels.
Vue du côté des affaires
Par souci d'exhaustivité, il faudrait considérer tout cela du côté de l'entreprise, et non d'un produit logiciel. Dans ce cas, la division en valeurs directes et indirectes devient assez banale: directe - apporte évidemment de l'argent et vous pouvez donner une évaluation quantitative sans ambiguïté; indirect - ils n'apportent pas d'argent et / ou il est très difficile à quantifier; les valeurs pour le développeur n'apportent pas d'argent sous aucune forme (peut-être même l'enlever).
Par exemple.
- Une nouvelle fonctionnalité avec le vissage OAuth a augmenté le nombre d'inscriptions de 10% et nous avons obtenu + 1k $.
- Nous avons divisé le module de facturation en plusieurs parties indépendantes, selon le modèle de responsabilité unique. Il semble que cela soit devenu plus facile à entretenir, mais ce n'était pas possible de mesurer.
- Nous avons aligné la base de code sur la norme de code et ... n'avons rien reçu.
Il convient de noter qu'à partir des estimations ci-dessus, les jambes se développent à l'accélération commerciale bien-aimée, à la hâte générale et à la réticence à consacrer du temps à autre chose que la fonctionnalité et, éventuellement, un bug. En effet, les valeurs directes peuvent être estimées et «vendues», et les valeurs indirectes sont très difficiles, voire impossibles. Et il s'avère que les valeurs indirectes sont réalisées soit en vertu d'une formation d'ingénieur, soit comprises au niveau intuitif, ou rejetées comme «sans valeur».
En toute justice, nous devons ici rappeler le concept d'activateur, qui "ouvre la voie" à la mise en œuvre de la fonctionnalité souhaitée, mais ne présente pas de bénéfice évident pour l'utilisateur. Mais c'est une autre histoire.
Et qu'en est-il du refactoring?
Du moins malgré le fait qu'il ne peut influencer que les valeurs indirectes du produit. Par conséquent, l'utilisateur ne se sentira pas mieux de toute refactorisation.
Il est également important de se souvenir de l'entropie. Le refactoring le minimise toujours. Pour réduire l'entropie, idéalement, vous avez besoin d'une équipe d'architectes qui minimisent l'entropie au stade de la conception. Pour citer une pièce du Mythical Man-Month:
La programmation système est un processus qui réduit l'entropie, et donc la métastabilité lui est inhérente. La maintenance de programme est un processus qui augmente l'entropie, et même sa maintenance la plus habile ne fait que retarder le système de tomber dans une obsolescence désespérée.
Par conséquent, si nous considérons que la refactorisation fait partie du processus de maintenance du programme, moins il y a de refactorisation, plus le code vivra sans réécriture.
Quels objectifs peut avoir la refactorisation?
Permettez-moi de vous rappeler que je parle d'un changement spontané lors de la mise en œuvre des fonctionnalités, et non des changements prévus. Dans ce cas, la définition de l'objectif incombe entièrement au développeur. Il doit se poser la question principale «pourquoi?», Y répondre et ensuite se diriger vers l'objectif visé.
Pour l'entropie!
C'est difficile de le faire soi-même. Et passer à travers l'examen est généralement irréaliste. L'objectif est certainement bon: dégager la tête de pont pour de nouvelles réalisations, ainsi que pour éliminer les toxines et les toxines accumulées pendant la durée du support produit. Mais pelleter quelques modules à partir de zéro sans rien perdre en cours de route n'est pas une tâche facile. Il doit être résolu en collaboration avec des analystes commerciaux et des architectes, le cas échéant. Si peu de gens risquent de le faire sur une base volontaire.
Pour la documentation!
C'est déjà plus simple. Renommez les variables / fonctions selon le principe «ce qui est sur la boîte, puis dans la boîte», simplifiez la conception grâce aux capacités du langage et des bibliothèques, ajoutez des commentaires dans des endroits non évidents, etc. Cela peut se faire seul et, avec la bonne approche, cela peut être bien fait à la fois pour soi-même pour l'avenir et pour les collègues voisins.
Pour la vitesse!
Pour être honnête, ce travail doit être souligné comme une tâche distincte. Étant donné que les capacités actuelles du système vous suffisent et que vous n'avez rien à faire, ou que vous savez exactement quoi et combien vous devez accélérer.
Tout rentre dans cette catégorie: de la correction inoffensive de N + 1 à de sérieuses accélérations dues aux changements d'algorithmes de fonctionnement. Tout le problème est que la «parité» des bogues est toujours rapide. Voici un exemple: dans une transaction, les données de la base de données sont transmises et dans la même transaction, une tâche est définie dans Sidekiq; La file d'attente de Sidekiq dans Redis et la transaction ne s'y applique pas; lorsque la vitesse de la file d'attente augmente, la tâche est parfois exécutée avant la validation des données; Vous pouvez imaginer vous-même les conséquences et le processus de débogage.
Pour refactoring!
Imaginez que vous utilisiez le service de nettoyage d'appartement. Ils sont venus et ont commencé à nettoyer, mais, en chemin, ils ont déplacé tous les meubles de l'appartement et ont décrit les rideaux du salon à la baignoire avec l'argument «dans de telles conditions, la femme de ménage était plus agréable de faire son travail.» Image de "WTF?!" vous pouvez l'imaginer vous-même.
J'espère que vous comprenez que vous devez penser non pas à vous-même, mais à qui vous le faites.
Humilité et acceptation
En conclusion, il est nécessaire de donner un «manuel» sur ce qu'il faut faire avant la refactorisation. Certes, ce n'est pas une liste TODO, mais plutôt une liste de faits avec lesquels vous devez vous réconcilier et accepter ou ne pas agir.
- J'augmente le nombre de bogues dans le projet et je peux obtenir un tambourin pour cela.
- Je deviens propriétaire du code refactorisé et toutes les questions à ce sujet me seront d'abord envoyées.
- Par mes actions, je ne produis rien de valeur pour l'utilisateur final.
Une petite explication.
- Toute modification du code a une chance non nulle de générer un bogue. Et puisque cette action n'est pas liée à la fonctionnalité ultime, vous produisez simplement des bugs sans générer de valeurs fondamentales. Il est bon d’être conscient de cela et de ne pas prétendre être des tuyaux quand ils vous posent des questions.
- Des excuses comme "anotate previous" et similaires sont très misérables, car dans le même github / gitlab il n'y a pas une telle fonctionnalité. De plus, l'auteur précédent a confirmé que tout fonctionne dans sa configuration, et il n'est pas responsable de vos modifications et perd une partie de l'image de ce qui se passe. Plus précisément, vous le lui enlevez avec la responsabilité.
- L'utilisateur ne se soucie vraiment pas de la refactorisation, il s'intéresse à la stabilité et aux fonctionnalités, et la refactorisation ne concerne pas cela.
Et encore: si vous n'êtes pas d'accord avec au moins un des points - ne commencez pas la refactorisation. Mieux lire Habr, Lurk, boire du thé ou, au pire, entailler la prochaine fonctionnalité du tableau de bord.
La fin
Ne jugez pas strictement. Si possible, critiquez de manière constructive. Et pensez toujours au but de vos actions. Je vous remercie