web-dev-qa-db-fra.com

Que signifie "Maintenant, vous avez deux problèmes"?

Il y a ne citation populaire de Jamie Zawinski :

Certaines personnes, confrontées à un problème, pensent "je sais, je vais utiliser des expressions régulières". Maintenant, ils ont deux problèmes.

Comment cette citation est-elle censée être comprise?

200
IQAndreas

Certaines technologies de programmation ne sont généralement pas bien comprises par les programmeurs ( expressions régulières , virgule flottante , Perl , AWK , IoC ... et autres ).

Ceux-ci peuvent être des outils incroyablement puissants pour résoudre le bon ensemble de problèmes. Les expressions régulières en particulier sont très utiles pour faire correspondre les langues régulières. Et il y a le nœud du problème: peu de gens savent comment décrire un langage ordinaire (cela fait partie de la théorie/linguistique informatique qui utilise des symboles amusants - vous pouvez le lire sur Hiérarchie Chomsky ).

Lorsque vous traitez ces choses, si vous les utilisez mal, il est peu probable que vous ayez réellement résolu votre problème d'origine. L'utilisation d'une expression régulière pour correspondre à HTML (une occurrence beaucoup trop courante) signifie que vous vous manquerez des cas Edge. Et maintenant, vous avez toujours le problème d'origine que vous n'avez pas résolu, et un autre bug subtil flottant qui a été introduit en utilisant la mauvaise solution.

Cela ne veut pas dire que les expressions régulières ne devraient pas être utilisées, mais plutôt que l'on devrait travailler pour comprendre l'ensemble des problèmes qu'elles peuvent résoudre et ne peuvent pas résoudre et les utiliser judicieusement.

La clé de la maintenance du logiciel est l'écriture de code maintenable. L'utilisation d'expressions régulières peut être contraire à cet objectif. Lorsque vous travaillez avec des expressions régulières, vous avez écrit un mini-ordinateur (en particulier un automate à états finis non déterministe ) dans un langage spécifique à un domaine spécial. Il est facile d'écrire l'équivalent de `` Hello world '' dans cette langue et d'y gagner une confiance rudimentaire, mais aller plus loin doit être tempéré par la compréhension de la langue régulière pour éviter d'écrire des bogues supplémentaires qui peuvent être très difficiles à identifier et à corriger (car ils ne font pas partie du programme dans lequel l'expression régulière se trouve).

Alors maintenant, vous avez un nouveau problème; vous avez choisi l'outil de l'expression régulière pour le résoudre (quand il est inapproprié), et vous avez maintenant deux bogues, tous deux plus difficiles à trouver, car ils sont cachés dans une autre couche d'abstraction.

220
user40980

Les expressions régulières - en particulier les expressions non triviales - sont potentiellement difficiles à coder, à comprendre et à maintenir. Il suffit de regarder le nombre de questions sur Stack Overflow marquées [regex] où l'interrogateur a supposé que la réponse à son problème est une expression régulière et s'est ensuite retrouvé coincé. Dans de nombreux cas, le problème peut (et devrait peut-être) être résolu d'une manière différente.

Cela signifie que si vous décidez d'utiliser une expression régulière, vous avez maintenant deux problèmes:

  1. Le problème d'origine que vous vouliez résoudre.
  2. Le soutien d'une expression régulière.

Fondamentalement, je pense qu'il veut dire que vous ne devriez utiliser une expression régulière que s'il n'y a pas d'autre moyen de résoudre votre problème. Une autre solution sera probablement plus facile à coder, à maintenir et à prendre en charge. Il peut être plus lent ou moins efficace, mais si ce n'est pas le cas, la facilité de maintenance et de support devrait être la préoccupation principale.

95
ChrisF

C'est surtout une blague ironique, bien qu'avec un grain de vérité.

Il existe certaines tâches pour lesquelles les expressions régulières conviennent parfaitement. Une fois, j'ai remplacé 500 lignes de code d'analyseur de descente récursif écrit manuellement par une expression régulière qui a pris environ 10 minutes pour déboguer complètement. Les gens disent que les expressions rationnelles sont difficiles à comprendre et à déboguer, mais celles qui sont correctement appliquées ne sont pas aussi difficiles à déboguer qu'un énorme analyseur conçu à la main. Dans mon exemple, il a fallu deux semaines pour déboguer tous les cas Edge de la solution non regex.

Cependant, pour paraphraser l'oncle Ben:

Une grande expressivité s'accompagne d'une grande responsabilité.

En d'autres termes, les regex ajoutent de l'expressivité à votre langage, mais cela donne plus de responsabilité au programmeur pour choisir le mode d'expression le plus lisible pour une tâche donnée.

Certaines choses semblent initialement être une bonne tâche pour les expressions régulières, mais ne le sont pas. Par exemple, tout ce qui a des jetons imbriqués, comme HTML. Parfois, les gens utilisent une expression régulière lorsqu'une méthode plus simple est plus claire. Par exemple, string.endsWith("ing") est plus facile à comprendre que l'expression régulière équivalente. Parfois, les gens essaient de regrouper un gros problème en une seule expression régulière, où le diviser en morceaux est plus approprié. Parfois, les gens ne parviennent pas à créer des abstractions appropriées, répétant une expression régulière encore et encore au lieu de créer une fonction bien nommée pour faire le même travail (peut-être implémentée en interne avec une expression régulière).

Pour une raison quelconque, les regex ont une tendance étrange à créer un angle mort pour les principes normaux d'ingénierie logicielle tels que la responsabilité unique et DRY. C'est pourquoi même les gens qui les aiment les trouvent parfois problématiques.

68
Karl Bielefeldt

Jeff Atwood fait ressortir une interprétation différente dans un article de blog traitant de cette même citation: Expressions régulières: vous avez maintenant deux problèmes(merci à Euphorique pour le lien)

En analysant le texte intégral des articles de Jamie dans le fil d'origine de 1997, nous trouvons ce qui suit:

La nature de Perl encourage l'utilisation d'expressions régulières presque à l'exclusion de toutes les autres techniques; ils sont de loin le moyen le plus "évident" (du moins, pour ceux qui ne connaissent pas mieux) d'aller d'un point A à un point B.

La première citation est trop simple pour être prise au sérieux. Mais cela, je suis entièrement d'accord avec. Voici le point que Jamie essayait de faire valoir: non pas que les expressions régulières sont mauvaises, en soi, mais que la surutilisation des expressions régulières est mauvaise.

Même si vous comprenez les expressions régulières, vous rencontrez The Golden Hammer problème, en essayant pour résoudre un problème avec les expressions régulières, alors qu'il aurait été plus facile et plus clair de faire la même chose avec du code normal (voir aussi CodingHorror: utilisation de Regex contre abus de Regex ).

Il y a un autre article de blog qui examine le contexte de la citation et va plus en détail qu'Atwood: Blog de Jeffrey Friedl: source de la célèbre citation "Maintenant, vous avez deux problèmes"

52
IQAndreas

Il y a quelques choses qui se passent avec cette citation.

  1. citation est une reformulation d'une blague antérieure:

    Chaque fois que face à un problème, certaines personnes disent "Permet d'utiliser AWK." Maintenant, ils ont deux problèmes. - D. Tilbrook

    C'est une blague et une vraie fouille, mais c'est aussi un moyen de mettre en évidence l'expression régulière comme une mauvaise solution en la reliant à d'autres mauvaises solutions. C'est un grand ha ha seulement sérieux moment.

  2. Pour moi - attention, cette citation est volontairement sujette à interprétation - le sens est simple. Le simple fait d'annoncer l'idée d'utiliser une expression régulière n'a pas résolu le problème. De plus, vous avez augmenté la complexité cognitive du code en ajoutant un langage supplémentaire avec des règles qui se distinguent de la langue que vous utilisez.

  3. Bien que drôle comme plaisanterie, vous devez comparer la complexité d'une solution non regex avec la complexité de la solution regex + la complexité supplémentaire d'inclure des regex. Il peut être utile de résoudre un problème avec une expression régulière, malgré le coût supplémentaire de l'ajout d'expressions régulières.

30
Jeffery Thomas

Des expressions régulières sont désormais disponibles pour la lecture de tout autre contenu non formaté; en effet, il est probable que vous puissiez les lire ou les lire ici, mais malheureusement, ils comportent une mauvaise déclaration parce que certaines mises en œuvre ne permettent pas de mettre en forme et de reconnaître les personnes qui ne savent pas que vous devez le faire.

(Les expressions régulières ne sont pas pires à lire ou à maintenir que tout autre contenu non formaté; en effet, une expression régulière est probablement plus facile à lire que ce morceau de texte ici - mais malheureusement, elles ont une mauvaise réputation car certaines implémentations ne permettent pas le formatage et les gens en général Je ne sais pas si tu peux le faire.)


Voici un exemple trivial:

^(?:[^,]*+,){21}[^,]*+$


Ce qui n'est pas vraiment difficile à lire ou à entretenir de toute façon, mais c'est encore plus facile quand cela ressemble à ceci:

(?x)    # enables comments, so this whole block can be used in a regex.
^       # start of string

(?:     # start non-capturing group
  [^,]*+  # as many non-commas as possible, but none required
  ,       # a comma
)       # end non-capturing group
{21}    # 21 of previous entity (i.e. the group)

[^,]*+  # as many non-commas as possible, but none required

$       # end of string

C'est un peu un exemple exagéré (commentant $ revient à commenter i++) mais clairement il ne devrait pas y avoir de problème de lecture, de compréhension et de maintien.


.

21
Peter Boughton

En plus de réponse de ChrisF - que les expressions régulières "sont difficiles à coder, à comprendre et à maintenir", il y a pire: elles sont juste assez puissantes pour inciter les gens à essayer de les utiliser pour analyser les choses qu'ils peuvent ' t, comme HTML. Voir les nombreuses questions sur SO sur "comment puis-je analyser HTML?" Par exemple, la réponse la plus épique dans tout SO!

14
Frank Shearar

Les expressions régulières sont très puissantes, mais elles ont un petit et un gros problème; ils sont difficiles à écrire et presque impossibles à lire.

Dans le meilleur des cas, l'utilisation de l'expression régulière résout le problème, vous n'avez donc que le problème de maintenance du code compliqué. Si vous n'obtenez pas l'expression régulière juste, vous avez à la fois le problème d'origine et le problème avec du code illisible qui ne fonctionne pas.

Parfois, les expressions régulières sont appelées code en écriture seule. Face à une expression régulière à corriger, il est souvent plus rapide de partir de zéro que d'essayer de comprendre l'expression.

14
Guffa

Le problème est que regex est une bête compliquée, et vous ne résolvez votre problème que si vous utilisez parfaitement regex. Si vous ne le faites pas, vous vous retrouvez avec 2 problèmes: votre problème d'origine et regex.

Vous prétendez qu'il peut faire le travail d'une centaine de lignes de code, mais vous pouvez également faire valoir que 100 lignes de code clair et concis valent mieux qu'une ligne de regex.

Si vous avez besoin d'une preuve de cela: vous pouvez vérifier cela SO Classic ou simplement passer au peigne le SO Regex Tag

10
Ampt

Le sens a deux parties:

  • Tout d'abord, vous n'avez pas résolu le problème d'origine.
    Cela fait probablement référence au fait que les expressions régulières offrent souvent solutions incomplètes aux problèmes courants.
  • Deuxièmement, vous avez maintenant ajouté une difficulté supplémentaire associée à la solution que vous avez choisie.
    Dans le cas des expressions régulières, la difficulté supplémentaire fait probablement référence à la complexité, à la maintenabilité ou à la difficulté supplémentaire associée à l'adaptation des expressions régulières à un problème qu'elle n'était pas censée résoudre.
7
tylerl

Comme vous le demandez en 2014, il serait intéressant de se concentrer sur les idéologies des langages de programmation du contexte de 1997 par rapport au contexte d'aujourd'hui. Je n'entrerai pas dans ce débat ici, mais les opinions sur Perl et Perl lui-même ont considérablement changé.

Cependant, pour rester dans un contexte 2013 ( de l'eau à coulé sous les ponts depuis), je suggère de me concentrer sur la reconstitution entre guillemets en utilisant ne célèbre bande dessinée XKCD qui est une citation directe de celle de Jamie Zawinski :

A comic from XKCD about regexes, Perl and problems

J'ai d'abord eu des problèmes pour comprendre cette bande dessinée car c'était une référence à la citation de Zawinski, et une citation des paroles d'une chanson de Jay-z, et une référence de GNU program --help -z flag 2 , donc, c'était trop de culture pour moi de le comprendre.

Je savais que c'était amusant, je le ressentais, mais je ne savais pas vraiment pourquoi. Les gens font souvent des blagues sur Perl et les expressions rationnelles, d'autant plus que ce n'est pas le langage de programmation le plus branché, je ne sais pas vraiment pourquoi il est censé être amusant ... Peut-être parce que les marchands Perl font des choses stupides .

La citation initiale semble donc être une blague sarcastique basée sur des problèmes réels (douleur?) Causés par la programmation avec des outils qui font mal. Tout comme un marteau peut blesser un maçon, programmer avec des outils qui ne sont pas ceux qu'un développeur choisirait s'il pouvait blesser (le cerveau, les sentiments). Parfois, de grands débats sur quel outil est le meilleur se produisent, mais c'est presque sans valeur car c'est un problème de votre goût ou votre goût de l'équipe de programmation, culturel ou économique raisons. Une autre excellente bande dessinée XKCD à ce sujet:

A comic from XKCD about programming tools debates

Je peux comprendre que les gens ressentent de la douleur à propos des regex, et ils croient qu'un autre outil est mieux adapté à ce pour quoi les regex sont conçues. Comme @ karl-bielefeldt répond à votre question avec une grande expressivité vient une grande responsabilité, et les regex sont particulièrement concernés par cela. Si un développeur ne se soucie pas de la façon dont il traite les expressions rationnelles, cela finira par être pénible pour les personnes qui conserveront le code plus tard.

Je terminerai par cette réponse sur la reconstitution des citations par une citation montrant un exemple typique de Damian Conw ay'sPerl Best Practices (un livre de 2005 ).

Il explique que écrire un modèle comme celui-ci:

m{'[^\\']*(?:\\.[^\\']*)*'}

... n'est pas plus acceptable que d'écrire un programme comme celui-ci:

sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;

Mais il peut être réécrit, c'est toujours pas joli, mais au moins il est maintenant survivable.

# Match a single-quoted string efficiently...
m{ '            # an opening single quote
    [^\\']*     # any non-special chars (i.e., not backslash or single quote)
    (?:         # then all of...`
    \\ .        # any explicitly backslashed char
    [^\\']*     #    followed by any non-special chars
    )*          # ...repeated zero or more times
    '           # a closing single quote
}x

Ce type de code de forme rectangulaire est le deuxième problème et non les regex qui peuvent être formatés de manière claire, maintenable et lisible.

7
smonff

S'il y a une chose que vous devez apprendre de l'informatique, c'est Hiérarchie Chomsky . Je dirais que tous les problèmes avec les expressions régulières proviennent de tentatives d'analyse syntaxique sans contexte avec elle. Lorsque vous pouvez imposer une limite (ou pensez que vous pouvez imposer une limite) aux niveaux d'imbrication dans CFG, vous obtenez ces expressions régulières longues et complexes.

6
Juha Autero

Les expressions régulières conviennent mieux à la tokenisation qu'à l'analyse complète.

Mais, un ensemble étonnamment important de choses que les programmeurs doivent analyser sont analysables par un langage normal (ou pire, presque analysables par un langage ordinaire et si vous écrivez seulement un peu plus de code ...).

Donc, si l'on est habitué à "aha, j'ai besoin de séparer le texte, je vais utiliser une expression régulière", il est facile de suivre cette voie, lorsque vous avez besoin de quelque chose qui est plus proche d'un automate Push-down, d'un analyseur CFG ou grammaires encore plus puissantes. Cela se termine généralement en larmes.

Donc, je pense que la citation n'est pas tellement des expressions rationnelles claquantes, elles ont leur utilisation (et bien utilisées, elles sont très utiles en effet), mais la dépendance excessive à l'égard des expressions régulières (ou, plus précisément, le choix non critique d'entre elles) .

5
Vatine

jwz est tout simplement hors de son rocker avec cette citation. les expressions régulières ne sont pas différentes de toutes les fonctionnalités linguistiques - faciles à bousculer, difficiles à utiliser avec élégance, puissantes parfois, inappropriées parfois, souvent bien documentées, souvent utiles.

la même chose pourrait être dite pour l'arithmétique à virgule flottante, les fermetures, l'orientation des objets, les E/S asynchrones ou tout autre nom que vous pouvez nommer. si vous ne savez pas ce que vous faites, les langages de programmation peuvent vous rendre triste.

si vous pensez que les expressions rationnelles sont difficiles à lire, essayez de lire l'implémentation de l'analyseur équivalent pour consommer le modèle en question. souvent, les regex gagnent parce qu'elles sont plus compactes que les analyseurs complets ... et dans la plupart des langues, elles sont aussi plus rapides.

ne soyez pas découragé d'utiliser des expressions régulières (ou toute autre fonctionnalité linguistique) car un blogueur auto-promotionnel fait des déclarations sans réserve. essayez par vous-même et voyez ce qui fonctionne pour vous.

3
Brad Clawsie

Ma réponse préférée et approfondie à cela est donnée par le célèbre Rob Pike dans un article de blog reproduit à partir d'un commentaire interne du code Google: http://commandcenter.blogspot.ch/2011/08/regular-expressions- in-lexing-and.html

Le résumé est que ce n'est pas qu'ils sont mauvais , mais ils sont fréquemment utilisés pour des tâches pour lesquelles ils ne sont pas nécessairement adaptés, surtout quand il s'agit de lexing et analyser une entrée.

Les expressions régulières sont difficiles à écrire, difficiles à bien écrire et peuvent être coûteuses par rapport à d'autres technologies ... Les Lexers, en revanche, sont assez faciles à écrire correctement (sinon de manière aussi compacte) et très faciles à tester. Pensez à trouver des identificateurs alphanumériques. Il n'est pas trop difficile d'écrire l'expression rationnelle (quelque chose comme "[a-ZA-Z _] [a-ZA-Z_0-9] *"), mais vraiment pas beaucoup plus difficile à écrire sous forme de boucle simple. Les performances de la boucle, cependant, seront beaucoup plus élevées et impliqueront beaucoup moins de code sous les couvertures. Une bibliothèque d'expressions régulières est une grande chose. Utiliser un pour analyser les identifiants, c'est comme utiliser une Ferrari pour aller au magasin pour le lait.

Il en dit beaucoup plus que cela, arguant que les expressions régulières sont utiles, par exemple correspondance jetable des modèles dans les éditeurs de texte, mais devrait rarement être utilisée dans le code compilé, etc. Cela vaut la peine d'être lu.

3
dan mackinlay

Les expressions rationnelles sont largement utilisées pour une analyse de texte rapide et sale. Ils sont un excellent outil pour exprimer des motifs un peu plus complexes qu'une simple correspondance de chaîne simple.

Cependant, à mesure que les regex deviennent de plus en plus complexes, des problèmes de serveur se posent.

  1. La syntaxe des expressions rationnelles est optimisée pour une correspondance simple, la plupart des caractères se correspondent. C'est idéal pour les modèles simples, mais une fois que vous vous retrouvez avec plus de deux niveaux d'imbrication, vous vous retrouvez avec quelque chose qui ressemble plus à du bruit de ligne qu'à du code bien structuré. Je suppose que vous pouvez écrire une expression régulière sous la forme d'une série de chaînes concaténées avec indentation et commentaires entre les deux pour montrer la structure du code, mais il semble rare que cela se produise réellement.
  2. Seuls certains types de correspondance de texte sont bien adaptés aux expressions rationnelles. Souvent, vous vous retrouvez à obtenir un analyseur basé sur des expressions rationnelles rapide et sale pour une sorte de langage de balisage, mais vous essayez de couvrir plus de cas d'angle et vous trouvez que les expressions régulières deviennent de plus en plus complexes et de moins en moins lisibles
  3. La complexité temporelle d'une expression régulière peut être non évidente. Il n'est pas si difficile de se retrouver avec un modèle qui fonctionne très bien quand il correspond mais a une complexité O (2 ^ n) dans certains cas de non-correspondance .

Ainsi, il est trop facile de commencer par un problème de traitement de texte, de lui appliquer des expressions régulières et de se retrouver avec deux problèmes, le problème d'origine que vous tentiez de résoudre et le traitement des expressions régulières qui tentent de résoudre (mais pas correctement) le problème d'origine.

0
Peter Green

Ceci est lié à l'épigramme n ° 34 d'Alan Perlis:

La chaîne est une structure de données austère et partout où elle est transmise, il y a beaucoup de duplication de processus. C'est un véhicule parfait pour cacher des informations.

Donc, si vous choisissez la chaîne de caractères comme structure de données (et, naturellement, le code basé sur regex comme algorithmes pour la manipuler), vous avez un problème, même si cela fonctionne: mauvaise conception autour d'une représentation inappropriée des données qui est difficile à étendre et inefficace.

Cependant, souvent cela ne fonctionne pas: le problème d'origine n'est pas résolu, et dans ce cas, vous avez deux problèmes.

0
Kaz