O uso do LINQ e Lambda Expressions leva a código menos legível? [fechadas]

41

Estou tendo uma discussão com um colega de trabalho no Linq, vou copiar aqui:

Co-Worker: Lets be honest here. Linq syntax sucks. It's confusing and non-intuitive.

Me: oh come on, more confusing than T-SQL?

Co-Worker: uh, yes.

Me: it has the same basic parts, select, where, and from

Co-Worker: Linq, to me, is a bastardization of relational + OO. Co-Worker: Don't get me wrong - it's incredibly powerful, but they repurposed SQL to use agains object collections.

Eu sou da opinião que usar o Linq + Lamda's é muito poderoso (ele concorda), e também torna o código mais fácil de ler (ele discorda nesse ponto):

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 (código VB aqui)

   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 mim, isso é limpo e fácil (pelo menos mais fácil do que as alternativas) de ler, quais são suas opiniões sobre isso?

    
por BlackICE 09.12.2010 / 16:14
fonte

10 respostas

73

Não consigo mais encontrar o post correto, mas Eric Lippert (e possivelmente vários outros softies) opinaram em várias ocasiões sobre como o Linq é declarativo , que, para várias classes de problemas, é muito mais intuitiva do que a imperativa sintaxe.

Linq permite escrever código que expressa a intenção , não o mecanismo .

Você me diz qual é mais fácil de ler. Isso:

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 isso?

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

Ou mesmo isso?

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

O primeiro exemplo é apenas um monte de boilerplate sem sentido, a fim de obter o mais simples dos resultados. Qualquer um que pense que é mais legível do que as versões do Linq precisa ter sua cabeça examinada. Não só isso, mas o primeiro desperdiça memória. Você não pode nem mesmo escrever usando yield return por causa da classificação.

Seu colega de trabalho pode dizer o que ele quer; Pessoalmente, acho que o Linq melhorou imensamente a legibilidade do código meu .

Também não há nada "relacional" sobre o Linq. Pode ter algumas semelhanças superficiais com o SQL, mas não tenta de nenhuma forma ou forma implementar o cálculo relacional. É apenas um monte de extensões que facilitam a consulta e projetar sequências. "Consulta" não significa "relacional" e, na verdade, existem vários bancos de dados não relacionais que usam a sintaxe semelhante a SQL. Linq é puramente orientado a objeto, apenas trabalha com bancos de dados relacionais através de frameworks como Linq to SQL por causa de alguma árvore de expressões voodoo e design inteligente da equipe C #, tornando funções anônimas implicitamente conversíveis em expressões árvores.

    
por 10.12.2010 / 00:52
fonte
69

Co-Worker: Lets be honest here. Linq syntax sucks. It's confusing and non-intuitive.

Você não pode argumentar com essa crítica. Para o seu colega de trabalho, é uma droga . Não criamos uma sintaxe que, para eles, fosse clara e intuitiva. Essa é nossa falha, e você pode passar minhas desculpas ao seu colega de trabalho. Fico feliz em dar sugestões sobre como melhorá-lo; o que especificamente seu colega de trabalho acha confuso ou não intuitivo?

No entanto, você não pode agradar a todos. Minha opinião pessoal, e a opinião da maioria das pessoas com quem conversei sobre o assunto, é que a sintaxe de compreensão de consulta é muito mais clara do que a sintaxe imperativa equivalente. Claramente, nem todos concordam, mas, felizmente, não exigimos o consenso de todos os milhões de nossos clientes quando fazemos o design da linguagem.

No entanto, sobre o assunto do que é "intuitivo", lembro-me da história do lingüista inglês que estudou muitas línguas diferentes e finalmente concluiu que o inglês era o melhor de todos os idiomas porque em inglês, as palavras vêm na mesma ordem que você pensa . Ao contrário do francês, onde eles estão constantemente dizendo coisas como "o cachorro branco come a carne vermelha". Quão difícil deve ser para os franceses pensarem as palavras na ordem correta e depois ter que dizer eles no francês ordem! O francês é tão pouco intuitivo! É incrível que os franceses consigam falar. E alemão? onde eles pensam "o cachorro come a carne" mas então tem que dizer "o cachorro que a carne come"!?! Tão pouco intuitivo.

Muitas vezes, o que é "intuitivo" é meramente uma questão de familiaridade. Levou-me meses de trabalhar com o LINQ antes de deixar de começar minhas consultas com a cláusula "select". Agora é uma segunda natureza, e a ordem SQL parece bizarra.

Qual é! As regras de escopo estão todas confusas no SQL. Algo que você pode querer salientar ao seu colega de trabalho é que o LINQ foi cuidadosamente projetado para que (1) a introdução de variáveis e escopos ocorra da esquerda para a direita (*) e (2) a ordem em que a consulta aparece na página seja a ordem em que é executado. Isto é, quando você diz

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

o c aparece no escopo à esquerda e permanece no escopo pela direita. E a ordem em que as coisas acontecem são: primeiro, os "clientes" são avaliados. Em seguida, o "onde" é avaliado para filtrar a sequência. Então a sequência filtrada é projetada pelo "select".

O SQL não tem essa propriedade. Se você disser

SELECT Name FROM Customers WHERE City = 'London'

em seguida, o "Nome" é colocado em escopo por algo à sua direita, não à esquerda, e a consulta é executada em uma ordem completamente confusa; a cláusula do meio é avaliada primeiro, depois a última e depois a primeira. Isso agora parece louco e não intuitivo para mim, tendo trabalhado apenas com o LINQ por tanto tempo agora.

(*) As regras de escopo são um pouco estranhas no LINQ com cláusulas de associação. Mas, além disso, os telescópios se encaixam bem.

    
por 13.12.2010 / 08:19
fonte
22

Como qualquer outra coisa no mundo da programação, você precisa se acostumar com a sintaxe, e então (potencialmente) é mais fácil de ler.

Como qualquer outra coisa no mundo da programação, existe o potencial para o código de espaguete ou outros abusos.

Como qualquer outra coisa no mundo da programação, você pode fazer isso de uma maneira ou de outra.

Como qualquer outra coisa no mundo da programação, sua milhagem pode variar.

    
por 09.12.2010 / 16:42
fonte
5

Eu vi um comentário / observação onde ele afirmou algo - em relação ao LINQ / lambda - ao longo das linhas de: "Escrever código legível para humanos, ao invés de legível para o seu computador".

Acho que essa afirmação tem muito mérito, no entanto, considere o desenvolvedor (como eu) que passou pela gama completa de linguagens de desenvolvimento da Assembly, passando por procedimentos, OO, gerenciados, alavancando alta taxa de transferência soluções paralelas de tarefas.

Eu me orgulhei de tornar meu código legível e reutilizável quanto possível e adotei muitos dos princípios do padrão de projeto GOF para fornecer sistemas e serviços de qualidade de produção em um grande número de setores de negócios distintos.

A primeira vez que encontrei a expressão lambda, pensei: "Que diabos é isso!?!" Foi imediatamente contra-intuitivo para a minha sintaxe declarativa explícita (familiar e confortável). O mais novo < 5 anos no trabalho pessoal, no entanto, lambeu como se fosse maná do céu!

Isso porque, durante anos, pensar como um computador (no sentido sintático) traduziu-se muito facilmente em sintaxe de codificação direta (independentemente da linguagem). Quando você teve essa mentalidade computacional por volta de 20+ anos (30+ no meu caso), você deve entender que o choque sintético inicial da expressão lambda pode facilmente se traduzir em medo e desconfiança.

Talvez o colega de trabalho no OP tenha vindo de um contexto semelhante ao meu (ou seja, esteve no quarteirão algumas vezes) e foi contra-intuitivo para eles naquela época? Minha pergunta é: o que você fez sobre isso? Você tentou reeducar o seu colega para entender os benefícios da sintaxe inline, ou você o espancou / ostracizou para não "estar com o programa"? O primeiro provavelmente teria visto o seu colega de trabalho chegar à sua linha de pensamento, o último provavelmente faria com que eles desconfiassem ainda mais da sintaxe do LINQ / lambda e, assim, exacerbassem a opinião negativa.

Para mim, eu tive que reeducar minha própria maneira de pensar (como Eric infere acima, não é uma mudança de mentalidade insignificante, e eu tive que programar em Miranda nos anos 80, então eu tive minha cota de funcional experiência de programação), mas uma vez que passei por essa dor, os benefícios eram óbvios, mas - mais importante - onde seu uso era usado (usado para usá-lo), complexo e repetitivo (considerando o princípio DRY nessa instância).

Como alguém que não apenas escreve muito código, mas que também precisa revisar tecnicamente muito código, é imperativo que eu entenda esses princípios para que eu possa revisar itens de maneira imparcial, aconselhar onde o uso de uma expressão lambda pode ser mais eficiente / legível, e também para fazer com que os desenvolvedores considerem a legibilidade de expressões lambda inline altamente complexas (onde uma chamada de método faria - nesses casos - tornar o código mais legível, sustentável e extensível).

Então, quando alguém diz que eles "não recebem lambda?" ou a sintaxe do LINQ, em vez de marcá-los com um luddite , tente ajudá-los a entender os princípios subjacentes. Eles podem ter, afinal de contas, um histórico da "velha escola" como eu.

    
por 28.03.2013 / 20:04
fonte
4

Lambda Expressions leva a um código menos legível se as consultas forem muito longas. No entanto, é muito melhor do que muitos loops aninhados .

É melhor com uma mistura dos dois .

Escreva no Lambda se for mais rápido (você precisa ser rápido) ou mais fácil de ler.

    
por 09.12.2010 / 16:56
fonte
1

Eu acho que depende da maioria dos casos (exceto quando se faz algo muito bizarro) se você quer dizer "legível" como alguém tendo a ideia do que está acontecendo ou se eles podem facilmente encontrar todos os pequenos detalhes.

Acho que o link ajuda com o primeiro, mas muitas vezes (especialmente quando depuração) prejudica o último.

IMHO quando estou olhando para o código não estou familiarizado com o primeiro é muito mais importante do que o último, então eu acho muito mais legível.

    
por 09.12.2010 / 17:08
fonte
1

Eu acho a sintaxe LINQ intuitiva e fácil de ler, especialmente desde que eles colocam o FROM no início, onde ele pertence, em vez de no meio, como no SQL. Mas os lambdas da IMO são confusos e tornam o código mais difícil de ler.

    
por 09.12.2010 / 17:38
fonte
1

Eu concordo com você que a sintaxe do Linq não é significativamente diferente do T-SQL. Eu acho que o seu colega de trabalho pode estar se opondo a coisas relacionais se misturando com o seu código OO legal e brilhante. Por outro lado, a programação funcional demora um pouco para se acostumar e a vontade de se acostumar com isso.

    
por 09.12.2010 / 22:56
fonte
0

Depende. Obviamente, o T-SQL fornece apenas algumas soluções relacionais de banco de dados. Obviamente, o LINQ oferece algumas soluções OO.

No entanto; "mais confuso que o T-SQL?" - é discutido / perguntado na pergunta inicial. Isso claramente implica algumas características que nenhuma das respostas existentes aborda, em vez de acusar o crítico (obviamente familiarizado com SQL) de estar preso no passado.

Então, embora eu aprecie o LINQ por certas qualidades, e não discordo muito das respostas existentes aqui, eu sinto que o contraponto merece representação:

Anos depois de se familiarizar com o LINQ, executar certos tipos de operações de grupo, junções externas e não-equijoins, trabalhar com chaves compostas e outras operações no LINQ ainda me deixam assustado. (Especialmente ao direcionar um back-end relacional com perguntas sensíveis ao desempenho.)

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

Se você acha que isso é intuitivo, mais poder para você. ;)

    
por 25.02.2015 / 08:50
fonte
-4

Existe provavelmente uma razão pela qual o Linq é uma droga, apenas tente fazer exemplos do mundo real, ao invés de exemplos de livros didáticos.

tente mostrar esta função em linqlamdathings e você verá que toda a beleza se foi, enquanto o modo clássico permanece legível. Sem mencionar problemas de execução adiada e configuração de pontos de interrupção.

A verdade é que os LinqLambdaThings são muito úteis em alguns casos e não são pensados para substituir toda a orientação a objetos que vocês nunca entenderam

    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;
    }
    
por 14.03.2013 / 14:47
fonte