Je viens d'écrire une fonction qui couvre environ 100 lignes. En entendant cela, vous êtes probablement tenté de me parler des responsabilités individuelles et de m'exhorter à refactoriser. C'est aussi mon instinct, mais voici le problème: la fonction fait une chose. Il effectue une manipulation de chaîne complexe, et le corps de la fonction se compose principalement d'une expression régulière verbeuse, divisée en plusieurs lignes documentées. Si je divisais l'expression régulière en plusieurs fonctions, je sens que je perdrais en fait la lisibilité, car je change effectivement de langue et je ne serai pas en mesure de profiter de certaines fonctionnalités qu'offrent les expressions régulières. Voici maintenant ma question:
En ce qui concerne la manipulation de chaînes avec des expressions régulières, les grands corps de fonction sont-ils toujours un anti-modèle? Il semble que les groupes de capture nommés servent un objectif très similaire aux fonctions. Soit dit en passant, j'ai des tests pour chaque flux à travers l'expression régulière.
la source
Réponses:
Ce que vous rencontrez est la dissonance cognitive qui provient de l'écoute de personnes qui favorisent l'adhésion servile aux directives sous le couvert de «meilleures pratiques» par rapport à une prise de décision raisonnée.
Vous avez clairement fait vos devoirs:
Si l'un de ces points n'était pas vrai, je serais le premier à dire que votre fonction a besoin de travail. Il y a donc un vote pour laisser le code tel quel.
Le deuxième vote vient de l'examen de vos options et de ce que vous obtenez (et perdez) de chacune:
Cette décision revient à laquelle vous accordez le plus d'importance: la lisibilité ou la longueur. Je tombe dans le camp qui croit que la longueur est agréable mais la lisibilité est importante et prendra ce dernier au cours de la première semaine.
Conclusion: s'il n'est pas cassé, ne le réparez pas.
la source
Honnêtement, votre fonction peut "faire une chose", mais comme vous l'avez dit vous-même
ce qui signifie que votre code ex reg fait beaucoup de choses. Et je suppose qu'il pourrait être décomposé en unités plus petites et testables individuellement. Cependant, si c'est une bonne idée, il n'est pas facile de répondre (surtout sans voir le code réel). Et la bonne réponse peut être ni "oui" ni "non", mais "pas encore, mais la prochaine fois vous devrez changer quelque chose dans cette exp reg".
Et c'est le point central - vous avez un morceau de code écrit en langage ex reg . Ce langage ne fournit pas de bon moyen d'abstraction en soi (et je ne considère pas les "groupes de capture nommés" comme un remplacement pour les fonctions). Donc, la refactorisation "dans la langue reg ex" n'est pas vraiment possible, et l'entrelacement de plus petites exp reg avec la langue hôte peut ne pas réellement améliorer la lisibilité (au moins, vous le sentez , mais vous avez des doutes, sinon vous n'auriez pas posté la question) . Voici donc mon conseil
montrez votre code à un autre développeur avancé (peut-être sur /codereview// ) pour vous assurer que les autres pensent la lisibilité comme vous le faites. Soyez ouvert à l'idée que d'autres ne trouveront peut-être pas une exp de 100 lignes aussi lisible que vous. Parfois, la notion de «ce n'est pas facilement cassable en petits morceaux» peut être surmontée par une deuxième paire d'yeux.
observez l’évolutivité réelle - votre exp brillant est-il toujours aussi beau lorsque de nouvelles exigences arrivent et vous devez les implémenter et les tester? Tant que votre exp exp fonctionne, je ne le toucherais pas, mais chaque fois que quelque chose doit être changé, je reconsidérerais si c'était vraiment une bonne idée de tout mettre dans ce gros bloc - et (sérieusement!) Repenser si la scission en des morceaux plus petits ne seraient pas une meilleure option.
observer la maintenabilité - pouvez-vous déboguer efficacement le reg exp dans la forme actuelle très bien? Surtout après avoir changé quelque chose, et maintenant vos tests vous disent que quelque chose ne va pas, avez-vous un débogueur reg exp vous aidant à trouver la cause première? Si le débogage devient difficile, ce serait également l'occasion de reconsidérer votre conception.
la source
Parfois, une fonction plus longue qui fait une chose est la façon la plus appropriée de gérer une unité de travail. Vous pouvez facilement accéder à des fonctions très longues lorsque vous commencez à traiter une requête dans une base de données (en utilisant votre langage de requête préféré). Rendre une fonction (ou méthode) plus lisible tout en la limitant à son objectif déclaré est ce que je considérerais comme le résultat le plus souhaitable d'une fonction.
La longueur est une "norme" arbitraire en ce qui concerne la taille du code. Lorsqu'une fonction de 100 lignes en C # peut être considérée comme longue, elle serait minuscule dans certaines versions d'assemblage. J'ai vu des requêtes SQL qui étaient bien dans la plage de 200 lignes de code qui ont renvoyé un ensemble de données très compliqué pour un rapport.
Un code pleinement fonctionnel , c'est aussi simple que vous pouvez raisonnablement en faire l'objectif.
Ne le changez pas simplement parce qu'il est long.
la source
Vous pouvez toujours diviser l'expression régulière en sous-expressions rationnelles et composer progressivement l'expression finale. Cela pourrait aider à la compréhension d'un très grand modèle, en particulier si le même sous-modèle est répété plusieurs fois. Par exemple en Perl;
la source
Je dirais le casser s'il est cassable. du point de vue de la maintenabilité et peut-être de la reproductibilité, il est logique de la casser, mais bien sûr, vous devez tenir compte de la nature de votre fonction et de la façon dont vous obtenez des informations et de ce qu'elle va rendre.
Je me souviens que je travaillais sur l'analyse de streaming de données en morceaux dans des objets, donc ce que j'ai fait essentiellement, je l'ai divisé en deux parties principales, l'une construisait une unité complète de String à partir du texte codé et dans la deuxième partie, analysait ces unités dans un dictionnaire de données et organisait eux (pourrait être une propriété aléatoire pour un objet différent) et que la mise à jour ou la création d'objets.
De plus, je pouvais diviser chaque partie principale en plusieurs fonctions plus petites et plus spécifiques.A la fin, j'avais 5 fonctions différentes pour faire le tout et je pouvais réutiliser certaines des fonctions à différents endroits.
la source
Une chose que vous avez peut-être ou non envisagée est d'écrire un petit analyseur dans la langue que vous utilisez au lieu d'utiliser une expression régulière dans cette langue. Cela peut être plus facile à lire, à tester et à maintenir.
la source
Les regex géants sont un mauvais choix dans la plupart des cas. D'après mon expérience, ils sont souvent utilisés parce que le développeur n'est pas familier avec l'analyse (voir la réponse de Thomas Eding ).
Quoi qu'il en soit, supposons que vous souhaitiez vous en tenir à une solution basée sur les regex.
Comme je ne connais pas le code réel, j'examinerai les deux scénarios possibles:
Le regex est simple (beaucoup de correspondance littérale et peu d'alternatives)
Dans ce cas, les fonctionnalités avancées offertes par une seule expression régulière ne sont pas indispensables. Cela signifie que vous bénéficierez probablement de la scission.
Le regex est complexe (beaucoup d'alternatives)
Dans ce cas, vous ne pouvez pas avoir une couverture de test complète, car vous avez probablement des millions de flux possibles. Donc, pour le tester, vous devez le diviser.
Je pourrais manquer d'imagination, mais je ne peux penser à aucune situation du monde réel où une expression régulière de 100 lignes est une bonne solution.
la source