it-swarm.dev

L'utilisation des expressions LINQ et Lambda conduit-elle à un code moins lisible?

J'ai une discussion avec un collègue sur Linq, je vais copier ici:

Collègue: Soyons honnêtes ici. La syntaxe Linq craint. C'est déroutant et non intuitif.

Moi: oh allez, plus déroutant que T-SQL?

Collègue: euh, oui.

Moi: il a les mêmes parties de base, sélectionnez, où et à partir de

Co-Worker: Linq, pour moi, est une bastardisation du relationnel + OO. Collègue: Ne vous méprenez pas - c'est incroyablement puissant, mais ils ont réorienté SQL pour utiliser à nouveau des collections d'objets.

Je suis d'avis que l'utilisation de Linq + Lamda est très puissante (il est d'accord), et rend également le code plus facile à lire (il n'est pas d'accord sur ce point):

pickFiles = from f in pickFolder.GetFiles("*.txt")
where ValidAuditFileName.IsMatch(f.Name)
select f;

ou

var existing = from s in ActiveRecordLinq.AsQueryable<ScannedEntity>()
where s.FileName == f.FullName && s.DocumentType != "Unknown"
select s;

ou (code VB ici)

   Dim notVerified = From image In images.AsParallel
     Group Join verifyFile In verifyFolder.GetFiles("*.vfy").AsParallel.Where(
      Function(v) v.Length > 0
      ).AsParallel
   On image.Name.Replace(image.Extension, ".vfy") Equals verifyFile.Name
     Into verifyList = Group
    From verify In verifyList.DefaultIfEmpty
    Where verify Is Nothing
    Select verify

Pour moi, c'est propre et facile (au moins plus facile que les alternatives) à lire, quelles sont vos opinions à ce sujet?

43
BlackICE

Je ne trouve plus le bon post, mais Eric Lippert (et peut-être plusieurs autres softies) ont exprimé à plusieurs reprises comment Linq est déclaratif, ce qui, pour plusieurs classes de problèmes, est beaucoup plus intuitif que impératif syntaxe.

Linq vous permet d'écrire du code qui exprime l'intention , pas le mécanisme .

Vous me dites ce qui est plus facile à lire. Cette:

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    List<Customer> results = new List<Customer>();
    foreach (Customer c in source)
    {
        if (c.FirstName == "Aaron")
        {
            results.Add(c);
        }
    }
    results.Sort(new LastNameComparer());
    return results;
}

class LastNameComparer : IComparer<Customer>
{
    public int Compare(Customer a, Customer b)
    {
        return x.LastName.CompareTo(b.LastName);
    }
}

Ou ca?

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    return from c in source
           where c.FirstName == "Aaron"
           orderby c.LastName
           select c;
}

Ou même ça?

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    return source.Where(c => c.FirstName == "Aaron").OrderBy(c => c.LastName);
}

Le premier exemple est juste un tas de passe-partout inutiles afin d'obtenir les résultats les plus simples. Quiconque pense qu'il est plus plus lisible que les versions Linq doit faire examiner sa tête. Non seulement cela, mais le premier gaspille de la mémoire. Vous ne pouvez même pas l'écrire en utilisant yield return à cause du tri.

Votre collègue peut dire ce qu'il veut; personnellement, je pense que Linq a amélioré la lisibilité de mon code incommensurablement.

Linq n'a rien de "relationnel" non plus. Il peut avoir des similitudes superficielles avec SQL mais il n'essaye en aucune façon de mettre en œuvre le calcul relationnel. Ce n'est qu'un tas d'extensions qui facilitent l'interrogation et la projection de séquences. "Requête" ne signifie pas "relationnel", et il existe en fait plusieurs bases de données non relationnelles qui utilisent une syntaxe de type SQL. Linq est purement orienté objet, il se trouve qu'il fonctionne avec des bases de données relationnelles via des frameworks tels que Linq to SQL en raison de certains arbres d'expression vaudou et d'une conception intelligente de l'équipe C #, rendant les fonctions anonymes implicitement convertibles en arborescences d'expression.

74
Aaronaught

Collègue: Soyons honnêtes ici. La syntaxe Linq craint. C'est déroutant et non intuitif.

Vous ne pouvez pas contester cette critique. Pour votre collègue, ça craint . Nous n'avons pas réussi à concevoir une syntaxe claire et intuitive pour eux. C'est notre échec, et vous pouvez transmettre mes excuses à votre collègue. Je suis heureux de prendre des suggestions sur la façon de l'améliorer; qu'est-ce que votre collègue trouve spécifiquement déroutant ou peu intuitif?

Cependant, vous ne pouvez pas plaire à tout le monde. Mon opinion personnelle, et l'opinion de la plupart des personnes à qui j'ai parlé à ce sujet, est que la syntaxe de compréhension des requêtes est beaucoup plus claire que la syntaxe impérative équivalente. De toute évidence, tout le monde n'est pas d'accord, mais heureusement, nous ne demandons pas le consensus de tous les millions de nos clients lorsque nous faisons de la conception linguistique.

Au sujet de ce qui est "intuitif" cependant, je me souviens de l'histoire du linguiste anglais qui a étudié de nombreuses langues différentes et a finalement conclu que l'anglais était la meilleure de toutes les langues car en anglais, les mots viennent dans le même ordre que vous les pensez. Contrairement au français, où ils disent constamment des choses comme "le chien blanc mange la viande rouge". Combien il doit être difficile pour les Français de penser les mots du correct et ensuite dire dans l'ordre français ! Le français est tellement peu intuitif! C'est incroyable que les Français réussissent à le parler. Et l'allemand? où ils pensent "le chien mange de la viande" mais doivent ensuite dire "le chien la viande mange"!?! Si peu intuitif.

Souvent, ce qui est "intuitif" n'est qu'une question de familiarité. Il m'a fallu mois pour travailler avec LINQ avant d'arrêter de commencer mes requêtes avec la clause "select". Maintenant, c'est une seconde nature, et l'ordre SQL semble bizarre.

C'est ça! Les règles de portée sont toutes gâchées dans SQL. Vous voudrez peut-être signaler à votre collègue que LINQ a été soigneusement conçu pour que (1) l'introduction des variables et des étendues se fasse de gauche à droite (*) et (2) l'ordre d'apparition de la requête sur la page soit l'ordre dans lequel il est exécuté. Autrement dit, lorsque vous dites

from c in customers where c.City == "London" select c.Name

le c apparaît dans la portée à gauche et reste dans la portée à droite. Et l'ordre dans lequel les choses se passent sont: les premiers "clients" sont évalués. Ensuite, le "où" est évalué pour filtrer la séquence. Ensuite, la séquence filtrée est projetée par le "select".

SQL n'a pas cette propriété. Si tu le dis

SELECT Name FROM Customers WHERE City = 'London'

puis "Nom" est mis à portée par quelque chose à sa droite, pas à sa gauche, et la requête est exécutée dans un ordre complètement foiré; la clause du milieu est évaluée en premier, puis la dernière clause, puis la première clause. Cela me semble maintenant fou et peu intuitif, ayant travaillé uniquement avec LINQ depuis si longtemps maintenant.


(*) Les règles de portée sont un peu bizarres dans LINQ avec des clauses de jointure. Mais à part cela, les portées se nichent bien.

69
Eric Lippert

Comme toute autre chose dans le monde de la programmation, vous devez vous habituer à la syntaxe, puis elle est (potentiellement) plus facile à lire.

Comme toute autre chose dans le monde de la programmation, il existe un risque de code spaghetti ou d'autres abus.

Comme toute autre chose dans le monde de la programmation, vous pouvez le faire de cette façon ou d'une autre manière.

Comme toute autre chose dans le monde de la programmation, votre kilométrage peut varier.

22
Wonko the Sane

J'ai vu un commentaire/remarque où il indiquait quelque chose - par rapport à LINQ/lambda - dans le sens de: "Écrivez du code lisible pour les humains, plutôt que lisible pour votre ordinateur".

Je pense que cette déclaration a beaucoup de mérite, cependant, considérez le développeur (comme moi) qui a parcouru toute la gamme des langages de développement d'Assembly, via les procédures, via OO, via managé, en exploitant des solutions parallèles de tâches à haut débit .

Je suis fier de rendre mon code aussi lisible et réutilisable que possible et d'adopter de nombreux principes de modèle de conception GOF afin de fournir des systèmes et des services de qualité de production dans un grand nombre de secteurs d'activité disparates.

La première fois que j'ai rencontré l'expression lambda, j'ai pensé: "Qu'est-ce que c'est que ça!?!" C'était immédiatement contre-intuitif à ma syntaxe déclarative explicite familière (et donc confortable). Les plus jeunes <5 ans dans le travail les gars l'ont cependant léché comme si c'était la manne du ciel!

En effet, pendant des années, penser comme un ordinateur (au sens syntaxique) s'est traduit très facilement en syntaxe de codage direct (quelle que soit la langue). Lorsque vous avez eu cet état d'esprit de calcul pendant environ 20 ans (30+ dans mon cas), vous devez comprendre que le choc syntaxique initial de l'expression lambda peut facilement se traduire par la peur et la méfiance.

Peut-être que le collègue de l'OP était issu d'un milieu similaire à moi (c'est-à-dire qu'il avait été quelques fois dans le quartier) et que c'était contre-intuitif pour eux à ce moment-là? Ma question est: qu'avez-vous fait à ce sujet? Avez-vous essayé de rééduquer vos pairs à comprendre les avantages de la syntaxe en ligne, ou les avez-vous mis au pilori/ostracisé pour ne pas "être avec le programme"? Le premier aurait probablement vu votre collègue revenir à votre ligne de pensée, le second les inciterait probablement à se méfier encore plus de la syntaxe LINQ/lambda et exacerberait ainsi l'opinion négative.

Pour moi, j'ai dû rééduquer ma propre façon de penser (comme Eric le déduit ci-dessus, ce n'est pas un changement d'esprit insignifiant, et j'ai dû programmer à Miranda dans les années 80, donc j'ai eu ma part d'expérience de programmation fonctionnelle) mais une fois que j'ai traversé cette douleur, les avantages étaient évidents, mais - plus important encore - où son utilisation était surutilisée (c'est-à-dire utilisée pour le plaisir de l'utiliser) ), trop complexe et répétitif (compte tenu du principe DRY dans ce cas).

En tant que personne qui non seulement écrit encore beaucoup de code mais qui doit également réviser techniquement beaucoup de code, il était impératif que je comprenne ces principes afin de pouvoir examiner les éléments de manière impartiale, indiquer où l'utilisation d'une expression lambda peut être plus efficace/lisible, et aussi pour amener les développeurs à considérer la lisibilité des expressions lambda en ligne très complexes (où un appel de méthode rendrait - dans ces cas - le code plus lisible, maintenable et extensible).

Alors, quand quelqu'un dit qu'ils "ne reçoivent pas de lambda?" ou la syntaxe LINQ, plutôt que de les qualifier de luddite essayez de les aider à comprendre les principes sous-jacents. Après tout, ils peuvent avoir une formation "à l'ancienne" comme moi.

6
CWC

Les expressions Lambda entraînent un code moins lisible si les requêtes sont trop longues. Cependant, c'est beaucoup mieux que trop boucles imbriquées.

C'est mieux avec un mélange des deux.

Écrivez-le dans Lambda s'il est plus rapide (vous avez besoin qu'il soit rapide) ou plus facile à lire.

4
Amir Rezaei

Je pense que cela dépend dans la plupart des cas (sauf lorsque vous faites quelque chose de très bizarre) si vous voulez dire "lisible" lorsque quelqu'un a une idée de ce qui se passe ou s'il peut facilement trouver tous les petits détails.

Je pense que le lien aide les premiers, mais souvent (surtout lors du débogage) fait mal aux seconds.

À mon humble avis, lorsque je regarde le code, je ne suis pas familier avec le premier est extrêmement plus important que le second, donc je le trouve beaucoup plus lisible.

1
Bill

Je trouve la syntaxe LINQ intuitive et facile à lire, d'autant plus qu'ils mettent le FROM au début où il appartient plutôt qu'au milieu comme dans SQL. Mais les lambdas de l'OMI prêtent à confusion et rendent le code plus difficile à lire.

1
Mason Wheeler

Je suis d'accord avec vous que la syntaxe Linq n'est pas significativement différente de T-SQL. Je pense que votre collègue pourrait vraiment s'opposer à ce que les choses relationnelles soient mélangées dans lesquelles son code Nice et brillant OO. D'un autre côté, la programmation fonctionnelle prend un peu de temps pour s'y habituer et une volonté de Habituez-vous.

1
Larry Coleman

Ça dépend. De toute évidence, T-SQL fournit de manière unique certaines solutions relationnelles DB. De toute évidence, LINQ fournit de manière unique des solutions OO.

Toutefois; "plus déroutant que T-SQL?" - est discuté/demandé dans la question initiale. Cela implique clairement certaines fonctionnalités qu'aucune des réponses existantes ne traite, au lieu d'accuser le critique (manifestement familier de SQL) d'être coincé dans le passé.

Donc, bien que j'apprécie LINQ pour certaines qualités et que je ne sois pas en désaccord avec les réponses existantes ici, je pense que le contrepoint mérite d'être représenté:

Des années après m'être familiarisé avec LINQ, effectuer certains types d'opérations de groupe, jointures externes et non-équijointures, travailler avec des clés composites et d'autres opérations dans LINQ me font toujours grincer des dents. (Surtout lorsque vous ciblez un back-end relationnel avec des questions sensibles aux performances.)

from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()

Si vous pensez que c'est intuitif, plus de puissance pour vous. ;)

0
shannon