¿El uso de LINQ y Lambda Expressions lleva a un código menos legible? [cerrado]

41

Estoy teniendo una discusión con un compañero de trabajo en Linq, lo copiaré aquí:

  

Compañero de trabajo: Seamos honestos aquí. Linq   la sintaxis apesta. Es confuso y   no intuitivo

     

Yo: oh vamos, más   confuso que el T-SQL?

     

Compañero de trabajo: uh,   sí.

     

Yo: tiene el mismo básico   partes, seleccione, desde dónde, y desde

     

Compañero de trabajo: Linq, para mí, es un   Bastardización de la relación + OO.   Compañero de trabajo: No me malinterpretes, es   increíblemente poderosos, pero ellos   SQL reutilizado para usar el objeto nuevo   colecciones.

Soy de la opinión de que usar Linq + Lamda's es muy poderoso (está de acuerdo), y también hace que el código sea más fácil de leer (no está de acuerdo con ese punto):

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

o

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

o (código VB aquí)

   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

Para mí, esto es limpio y fácil de leer (al menos más fácil que el de las alternativas). ¿Qué opinas al respecto?

    
pregunta BlackICE 09.12.2010 - 16:14

10 respuestas

73

Ya no puedo encontrar la publicación correcta, pero Eric Lippert (y posiblemente varios otros softies) ha opinado en varias ocasiones sobre cómo Linq es declarativo , que, para varias clases de problemas, es mucho más intuitivo que la sintaxis imperativa .

Linq le permite escribir código que expresa el intento , no el mecanismo .

Me dices que es más fácil de leer. Esto:

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);
    }
}

¿O esto?

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

¿O incluso esto?

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

El primer ejemplo es solo un montón de repetitivo sin sentido para obtener los resultados más simples. Cualquiera que piense que es más legible que las versiones de Linq necesita que le examinen la cabeza. No solo eso, sino que el primero desperdicia memoria. Ni siquiera puedes escribirlo usando yield return debido a la clasificación.

Tu compañero de trabajo puede decir lo que quiera; personalmente, creo que Linq ha mejorado enormemente la legibilidad del código de .

Tampoco hay nada "relacional" en Linq. Puede tener algunas similitudes superficiales con SQL, pero no intenta en ninguna forma o forma implementar el cálculo relacional. Es solo un montón de extensiones que facilitan la consulta y las secuencias de proyectos. "Consulta" no significa "relacional" y, de hecho, hay varias bases de datos no relacionales que utilizan una sintaxis similar a la de SQL. Linq es puramente orientado a objetos, simplemente funciona con bases de datos relacionales a través de marcos como Linq a SQL debido a algún vudú de árbol de expresión y diseño inteligente del equipo de C #, haciendo que las funciones anónimas se conviertan implícitamente en expresión árboles.

    
respondido por el Aaronaught 10.12.2010 - 00:52
69
  

Compañero de trabajo: Seamos honestos aquí. La sintaxis de Linq apesta. Es confuso y no intuitivo.

No puedes discutir con esa crítica. Para tu compañero de trabajo, apesta . No pudimos diseñar una sintaxis que, para ellos, fuera clara e intuitiva. Esa es nuestra falla, y puede pasar mis disculpas a su compañero de trabajo. Estoy feliz de recibir sugerencias sobre cómo mejorarlo; ¿Qué es lo que su compañero de trabajo encuentra específicamente confuso o no intuitivo?

Sin embargo, no puedes complacer a todos. Mi opinión personal, y la opinión de la mayoría de las personas con las que he hablado sobre el tema, es que la sintaxis de comprensión de consulta es mucho más clara que la sintaxis imperativa equivalente. Claramente, no todos están de acuerdo, pero afortunadamente no requerimos el consenso de todos los millones de nuestros clientes cuando hacemos diseño de idiomas.

Sin embargo, sobre el tema de lo que es "intuitivo", me acuerdo de la historia del lingüista inglés que estudió muchos idiomas diferentes y finalmente concluyó que el inglés era el mejor de todos los idiomas porque en inglés, las palabras vienen en el mismo orden en que los piensas . A diferencia de los franceses, en los que constantemente dicen cosas como "el perro blanco se come la carne roja". Qué difícil debe ser para los franceses pensar las palabras en el orden correcto y luego decir en francés orden! ¡El francés es tan poco intuitivo! Es sorprendente que los franceses logren hablarlo. ¿Y alemán? ¿Donde piensan que "el perro come la carne" pero luego tiene que decir "el perro que come la carne"? Tan poco intuitivo.

A menudo, lo que es "intuitivo" es simplemente una cuestión de familiaridad. Me tomó meses trabajar con LINQ antes de dejar de comenzar mis consultas con la cláusula "seleccionar". Ahora es una segunda naturaleza, y el orden de SQL parece extraño.

Que es! Las reglas de alcance están todas desordenadas en SQL. Algo que podría querer señalar a su compañero de trabajo es que LINQ se diseñó cuidadosamente para que (1) la introducción de variables y ámbitos ocurra de izquierda a derecha (*), y (2) el orden en que aparece la consulta en la página es El orden en que se ejecuta. Es decir, cuando dices

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

la c aparece en el alcance a la izquierda y permanece en el alcance a la derecha. Y el orden en que suceden las cosas es: primero se evalúa a los "clientes". Luego se evalúa el "donde" para filtrar la secuencia. Luego la secuencia filtrada es proyectada por el "seleccionar".

SQL no tiene esta propiedad. Si dices

SELECT Name FROM Customers WHERE City = 'London'

luego "Nombre" se pone en el alcance por algo a su derecha, no a su izquierda, y la consulta se ejecuta en un orden completamente desordenado; La cláusula central se evalúa primero, luego la última y luego la primera. Eso ahora me parece una locura y es poco intuitivo, ya que he trabajado solo con LINQ durante tanto tiempo.

(*) Las reglas de alcance son un poco extrañas en LINQ con cláusulas de unión. Pero aparte de eso, los ámbitos anidan muy bien.

    
respondido por el Eric Lippert 13.12.2010 - 08:19
22

Al igual que con cualquier otra cosa en el mundo de la programación, debes acostumbrarte a la sintaxis, y entonces es (potencialmente) más fácil de leer.

Al igual que con cualquier otra cosa en el mundo de la programación, existe el potencial para el código espagueti u otros abusos.

Como cualquier otra cosa en el mundo de la programación, puedes hacerlo de esta manera o de otra manera.

Como cualquier otra cosa en el mundo de la programación, su millaje puede variar.

    
respondido por el Wonko the Sane 09.12.2010 - 16:42
5

Vi un comentario / comentario donde decía algo, en relación con LINQ / lambda, en la siguiente línea: "Escriba un código legible para los humanos, en lugar de legible para su computadora".

Creo que esta declaración tiene muchos méritos, sin embargo, considere al desarrollador (como yo) que ha estado en toda la gama de lenguajes de desarrollo desde Assembly, pasando por procedimientos, pasando por OO, pasando por gestionado, aprovechando el alto rendimiento. soluciones paralelas de tareas.

Me enorgullezco de hacer que mi código sea tan legible y reutilizable como sea posible y de adoptar muchos de los principios de diseño de GOF para ofrecer sistemas y servicios de calidad de producción en una gran cantidad de sectores empresariales dispares.

La primera vez que encontré la expresión lambda pensé: "¡¿Qué demonios es eso ?!" Inmediatamente fue contraintuitivo para mi sintaxis declarativa explícita familiar (y, por lo tanto, cómoda). El más joven < 5 años en el trabajo ¡los muchachos, sin embargo, lo tomaron como si fuera el maná del cielo!

Esto se debe a que, durante años, pensar como una computadora (en el sentido sintáctico) se tradujo muy fácilmente en sintaxis de codificación directa (independientemente del idioma). Cuando ha tenido esa mentalidad computacional por más de 20 años (30+ en mi caso), debe apreciar que el shock inicial sintáctico de la expresión lambda puede traducirse fácilmente en miedo y desconfianza.

¿Quizás el compañero de trabajo en el OP tenía antecedentes similares a los míos (es decir, he estado alrededor del bloque unas cuantas veces) y era contraintuitivo para ellos en ese momento? Mi pregunta es: ¿qué hiciste al respecto? ¿Intentó volver a educar a sus compañeros para que comprendieran los beneficios de la sintaxis en línea o los impidió o no para "estar en el programa"? El primero probablemente hubiera visto a tu compañero de trabajo llegar a tu línea de pensamiento, el último probablemente haría que desconfiaran aún más de la sintaxis de LINQ / lambda y, por lo tanto, exacerbando la opinión negativa.

Para mí, tuve que volver a educar mi propia forma de pensar (como dice Eric, no es un cambio de mentalidad insignificante, y tuve que programar en Miranda en los años 80, así que tuve mi parte de funcional experiencia de programación) pero una vez que pasé por ese dolor, los beneficios fueron obvios pero, lo que es más importante, donde se usó en exceso (es decir, se usó para usarlo), sobre complejo y repetitivo (considerando el principio DRY en esa instancia).

Como alguien que no solo escribe muchos códigos, sino que también tiene que revisarlos técnicamente, era imperativo que entendiera estos principios para poder revisar los elementos de manera imparcial, informar dónde podría ser el uso de una expresión lambda más eficiente / legible, y también para que los desarrolladores consideren la legibilidad de expresiones lambda en línea altamente complejas (donde una llamada de método haría que el código sea más legible, mantenible y extensible).

Entonces, cuando alguien dice que "no se hacen lambda?" o la sintaxis de LINQ, en lugar de calificarlos de luddite para ayudarlos a comprender los principios subyacentes. Después de todo, pueden tener antecedentes de "vieja escuela" como yo.

    
respondido por el CWC 28.03.2013 - 20:04
4

Lambda Expressions lleva a un código menos legible si las consultas son demasiado largas. Sin embargo, es mucho mejor que demasiados bucles anidados .

Es mejor con una mezcla de los dos .

Escríbalo en Lambda si es más rápido (necesita que sea rápido) o más fácil de leer.

    
respondido por el Amir Rezaei 09.12.2010 - 16:56
1

Creo que depende en la mayoría de los casos (excepto cuando se hace algo muy extraño) si te refieres a "legible" como alguien que tiene la idea de lo que está sucediendo o si puede encontrar fácilmente todos los pequeños detalles.

Creo que el vínculo ayuda con el primero, pero a menudo (especialmente cuando se depura) daña al segundo.

En mi humilde opinión, cuando estoy viendo un código que no conozco el primero es mucho más importante que el último, por lo que me parece mucho más legible.

    
respondido por el Bill 09.12.2010 - 17:08
1

La sintaxis de LINQ me parece intuitiva y fácil de leer, especialmente porque ponen el FROM desde el principio donde pertenece en lugar de en el medio, como en SQL. Pero las lambdas de IMO son confusas y hacen que el código sea más difícil de leer.

    
respondido por el Mason Wheeler 09.12.2010 - 17:38
1

Estoy de acuerdo con usted en que la sintaxis de Linq no es significativamente diferente de T-SQL. Creo que su compañero de trabajo realmente podría estar objetando que las cosas relacionales se mezclen en su código OO agradable y brillante. Por otro lado, la programación funcional requiere un poco de tiempo para acostumbrarse, y una buena disposición para acostumbrarse a ella.

    
respondido por el Larry Coleman 09.12.2010 - 22:56
0

Depende. Obviamente, T-SQL únicamente proporciona algunas soluciones relacionales de base de datos. Obviamente, LINQ únicamente proporciona algunas soluciones OO.

Sin embargo; "Más confuso que T-SQL?" - Se discute / pregunta en la pregunta inicial. Esto claramente implica algunas características que ninguna de las respuestas existentes aborda, en lugar de acusar al crítico (obviamente conocido por SQL) de estar atascado en el pasado.

Entonces, aunque aprecio a LINQ por ciertas cualidades y no estoy en desacuerdo con las respuestas existentes aquí, siento que el contrapunto merece representación:

Años después de familiarizarse con LINQ, realizar ciertos tipos de operaciones grupales, uniones externas y no equipolares, trabajar con claves compuestas y otras operaciones en LINQ todavía me hacen temblar. (Especialmente cuando se dirige a un back-end relacional con preguntas sensibles al rendimiento).

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

Si crees que es intuitivo, más poder para ti. ;)

    
respondido por el shannon 25.02.2015 - 08:50
-4

Probablemente hay una razón por la cual Linq apesta, solo intenta hacer ejemplos del mundo real, en lugar de estos ejemplos de libros de texto.

intenta mostrar esta función en linqlamdathings y verás que toda la belleza se ha ido, mientras que la forma clásica sigue siendo legible. Sin mencionar los problemas de ejecución diferida y la configuración de puntos de interrupción.

La verdad es que los LinqLambdaThings son muy útiles en algunos casos y no se cree que reemplacen toda la ingeniosa orientación a objetos que ustedes nunca entendieron

    public IList<Customer> GetVipCustomers(IList<Customer> source, int maxCount)
    {
        var results = new SortedList<string,Customer>();

        foreach (Customer c in source)
        {
            if (maxCount == results.Count)
                break;

            if (c.IsVip && c.FirstName== "Aaron" || c.SecondName== "Aaron")
                results.Add(c.LastName, c);
        }

        return results.Values;
    }
    
respondido por el marc 14.03.2013 - 14:47

Lea otras preguntas en las etiquetas