O algoritmo é mais importante que a linguagem de programação?

35

Durante o atual concurso do Google Code Jam (2013) , houve um problema que levou mais de 200 linhas de código em C ++ e Java em comparação com as pessoas em Python que resolveram o mesmo problema usando apenas 40 linhas de código.

Python não é diretamente comparável com C ++ e Java, mas a diferença de verbosidade que pensei talvez pudesse ter uma influência na eficiência do algoritmo.

Quão importante é conhecer o algoritmo certo em comparação com a escolha do idioma? Um programa Python excelentemente implementado poderia ser implementado em C ++ ou Java de uma maneira melhor (usando o mesmo algoritmo) e isso tem alguma relação com a verbosidade natural de certas linguagens de programação?

superspacemarines
fonte
16
Já foi dito (e acredito) que a linguagem de programação em que você trabalha influencia a maneira como você pensa sobre um problema. Isso implicaria que linguagens de programação muito diferentes podem ser adequadas para diferentes classes de problemas.
Joris Timmermans
11
Muito disso depende inteiramente da escala em que você está trabalhando além do LOC. Alguns idiomas simplesmente não suportam a velocidade ou as necessidades de simultaneidade. Os algoritmos são importantes, mas às vezes se o idioma x é y vezes mais lento que o idioma z, você simplesmente não pode usar x, independentemente da verbosidade.
Rig
Como observação, a única coisa que aprendi na escola é que todo mundo tem um bug por linhas de código que permanece constante independentemente do código usado. Portanto, se uma linguagem que permite fazê-lo em menos linhas de código resultar em menos bugs, você poderá comercializá-la mais rapidamente e menos chances de um bug aparecer quando o usuário estiver usando. Então, na minha opinião, eu escolheria o melhor idioma para o trabalho que todos os outros na empresa sabem que é necessário para trabalhar nesse projeto.
Travis Pessetto
5
@ Travis: "o defeito por taxa SLOC permanece constante, independentemente do idioma", mas não é verdade. Veja a resposta de John.
precisa
Agora você está pensando em entrar no próximo concurso usando o F # como idioma!
code4life

Respostas:

73

Obviamente, se você considerar essa pergunta no contexto de algo como o Google Code Jam, o pensamento algorítmico é claramente mais importante ao resolver problemas algorítmicos.

Na vida cotidiana, no entanto, cerca de um milhão de outros fatores também devem ser considerados, o que torna a questão muito menos preta versus branca.

Apenas um contra-exemplo: se você precisa de mais 200 linhas em Java, mas todos na sua empresa conhecem Java, isso não é grande coisa. Se você pudesse escrevê-lo em 5 linhas de Python ou em qualquer outro idioma, mas seria o único na empresa a conhecer esse idioma - é um grande negócio. Um negócio tão grande, de fato, que você nem poderá fazê-lo e, em vez disso, precisará escrevê-lo em Java.

Da perspectiva de um artesão, nós sempre tentar se aproximar com a ferramenta certa para o trabalho, mas a palavra certa lá é tão complicado que se pode facilmente obtê-lo errado.

Pelo contrário, achei o pensamento algorítmico nas empresas quase ausente. Apenas poucas pessoas selecionadas o possuem, enquanto o joe médio geralmente já tem problemas para estimar as complexidades do tempo de execução de loops, pesquisas etc.

Em termos de competições algorítmicas, no entanto, minha experiência pessoal de competir nelas por vários anos me diz claramente que você deve se ater a um idioma. A velocidade é um fator importante e você simplesmente não pode perder tempo com suas ferramentas, quando deve dedicá-lo à solução dos problemas dentro do prazo. Considere também que escrever 200 linhas de código Java sem pensar ainda é muito mais rápido do que criar 50 linhas de código python complicado, exigindo muito pensamento, mas resolvendo mais ou menos o mesmo problema.

Ah, e finalmente, certifique-se de entender as principais diferenças entre o código algorítmico da concorrência e o código de produção da empresa. Vi codificadores algorítmicos fantásticos, que escreviam códigos horríveis que eu nunca aceitaria em um produto.

Frank
fonte
11
+ 1 para "milhões de outros fatores a serem considerados"
ozz 25/04
11
Acrescentarei a isso que, se você está tentando resolver um problema funcional, então, pelo amor de Deus, use uma linguagem funcional! Então, eu diria que você realmente deve manter uma linguagem por grande paradigma de programação.
precisa saber é o seguinte
6
+1 para a última frase.
Shivan Dragão
4
+1 As linhas de código são uma métrica terrível por si só. Precisamos medir a capacidade de manutenção , não as linhas de código. 200 linhas de código de tipo seguro podem ser muito mais fáceis de manter do que 50 linhas de Python.
26413 Phil
2
@ Phil: E 200 linhas de Python podem ser muito mais fáceis de manter do que 50 linhas de código de tipo seguro. Eu nunca vi tanta vantagem de clareza em linguagens de tipo seguro, assumindo um código bem escrito.
precisa
17

Eu argumentaria que, mesmo fora das competições, o pensamento algorítmico é mais importante do que conhecer todos os truques para um idioma específico.

É claro que você deseja conhecer o idioma com o qual trabalha da melhor maneira possível, mas os idiomas vêm e vão, enquanto a capacidade de pensar abstratamente em termos de algoritmos é uma habilidade altamente transferível.

Caso em questão: se bem me lembro, havia um post aqui nos programadores há um tempo atrás em que alguém se queixou de ter falhado no FizzBuzz em uma entrevista e culpou seu desconhecimento sobre o operador de módulo do Java por isso. Esta conclusão está errada - a falta de conhecimento sobre como o módulo funciona o tornou incapaz de pensar algoritmicamente sobre o problema e resolvê-lo, mesmo na ausência de um operador de módulo dedicado. Indo além: Java possui uma classe Tree - e se, no futuro, você precisar trabalhar com uma linguagem que não implementa essa classe? Novamente, a capacidade de pensar sobre o problema supera os detalhes específicos do idioma.

Admito que os exemplos são simplistas, mas ajudam a esclarecer o assunto.

ACEG
fonte
14

A linguagem é importante.

A DARPA e a Marinha dos EUA fizeram um experimento de tiroteio há quase 20 anos. O vencedor da corrida de cavalos negros foi Haskell. Ada e C ++ estavam ambos representados; Java não era.

Na mesma época, a Pratt & Whitney fez um estudo de mineração de dados em projetos de controladores de motores a jato, analisando dados de cartões de ponto e rastreadores de erros. Eles descobriram que Ada dava o dobro da produtividade do programador e 1/4 da densidade de defeitos de qualquer outro idioma que estavam usando.

A Atari costumava usar o FORTH para desenvolver videogames, e o fato de eles estarem usando o FORTH era considerado extremamente proprietário.

Os comentários de Paul Graham sobre o uso do LISP são bem conhecidos. Os comentários de Erann Gat sobre o LISP no JPL são igualmente convincentes, embora não sejam tão conhecidos.

O software aviônico Boeing 777 é praticamente todo Ada. A experiência deles foi muito boa, apesar de um grande subcontratado ter que começar de novo no meio do fluxo.

A linguagem é importante.

John R. Strohm
fonte
Obviamente, o java foi lançado após o experimento ao qual você está vinculando.
Toasted_flakes
o artigo foi lançado em 1994. O primeiro lançamento público do Java foi em 1995.
Alessandro Teruzzi
O ponto não é que seu idioma favorito em particular tenha sido ou não representado em um experimento específico. O ponto é que a linguagem é importante. Houve muitos estudos anedóticos, que mostram isso de maneira bastante conclusiva. Também é importante notar que, apesar de ter sido rejeitado principalmente pelos programadores americanos, o Ada ainda é muito usado na Europa, especialmente para sistemas de alta confiabilidade, e ainda é usado em certos sistemas de campo nos EUA.
John R. Strohm
7

Alguns pontos:

  • As primeiras posições tendem a ser C ++ / C / Java, independentemente de quantas linhas de código a diferença entre essa e outra linguagem. Talvez isso aconteça porque os principais codificadores tendem a escolher esses idiomas em detrimento de outros, provavelmente por causa de sua velocidade bruta.
    Infelizmente, você não consegue ver facilmente a linguagem de programação no Google Code Jam, mas baixei algumas das principais e, tanto quanto me lembro, elas são principalmente em C / C ++. O TopCoder (um popular site de hospedagem de concursos de programação on-line) geralmente apresenta resultados semelhantes.

  • Porque eles são bastante baixo nível, eu tenho certeza que você não vai facilmente bater C / C ++ em termos de tempo de execução crua (e Java de não arrastar muito longe atrás). De acordo com minha experiência, os idiomas tipificados dinamicamente tendem a ser significativamente mais lentos que os idiomas estaticamente. A solução ideal pode até não ser rápida o suficiente em alguns idiomas, mas isso não deve ser uma regra geral.

  • O algoritmo certo é vital. Se você soube resolver todos os problemas (em detalhes) desde o início e é um codificador bom e rápido, provavelmente vencerá, independentemente do idioma em que codificar (assumindo a solução ideal nesse idioma) é rápido o suficiente).

  • O número direto de linhas não é grande coisa. Depois de obter experiência de programação suficiente, você saberá que pode gastar 10 minutos programando 10 linhas ou 200 linhas, tudo depende da complexidade das linhas. Além disso, se você codificou código semelhante centenas de vezes, poderá fazê-lo rapidamente. Sem mencionar também todas as macro que os principais codificadores C / C ++ costumam usar para otimizar seu tempo de codificação.

  • Frank faz um bom argumento - (fora das competições de programação), você não pode codificar em Python para sua empresa se toda a sua base de códigos estiver em C ou o que for, você precisa estar em conformidade com a linguagem deles.

  • É razoavelmente fácil alternar entre idiomas, não é fácil criar anos de conhecimento de pensamento algorítmico. Estou disposto a apostar que quase qualquer programador excelente pode mudar para outra linguagem (vagamente semelhante) em, digamos, uma semana. Talvez ele / ela não seja bom o suficiente para vencer competições de programação nesse idioma (aguarde mais 2 semanas), mas tenha o básico.

Dukeling
fonte
Falsidade: o download de várias soluções de alguns sites de concursos de código é um estudo científico definitivo suficiente para concluir que você definitivamente sabe de fato como são as principais posições.
Lie Ryan
@LieRyan True, mas participar de algumas dezenas de competições de programação (como eu) no (provavelmente) site mais popular (TopCoder) e sempre vendo a maioria das posições de topo como C / C ++ / Java é bastante significativo. Além disso, eu disse que "tendem a" não "são sempre".
precisa saber é o seguinte
discordo de que "o número direto de linhas não é um problema tão grande". código é o inimigo
jk.
6
@jk. Eu deveria ter destacado "tal"? É importante, mas não é o alfa e o ômega. Você prefere poucas linhas a legibilidade? Eu com certeza não. Levarei algumas declarações if simples para uma expressão multicondicional muito confusa, ilegível, com deslocamento de bits, multiplicação, divisão, adição, subtração, XORing, ANDing, expressão multicondicional a qualquer dia. Possivelmente não é do que você estava falando, mas é para isso que às vezes se reduz a contagem de linhas. E eu estava falando mais sobre implementar algo complexo em poucas linhas, ou algo simples em muitas linhas; o último geralmente leva menos tempo.
Dukeling
5

A mesma lógica pode ser implementada melhor em C ++? Claro que pode, se por melhor você quer dizer mais rápido e mais eficiente em termos de memória. O problema é que a quantidade de esforço necessária para isso é significativamente maior. Além disso, teoricamente, você ainda pode diminuir o nível e implementá-lo em C puro ou mesmo ASM, o que levaria ainda mais tempo, mas você poderia ter um código ainda mais otimizado.

Obviamente, no caso de competições como Code Jam ou TopCoder, não é nada demais, pois são apenas 40 linhas versus 200 linhas. Por outro lado, nesse tipo de competição, o que mais importa é a complexidade de tempo / espaço do algoritmo. Enquanto na aplicação da vida real, YMMV, nesses tipos de competições, o algoritmo O (n) escrito nas linguagens mais lentas sempre supera O (n²) escrito nas linguagens mais rápidas. Especialmente que haverá vários testes que são o pior cenário.

Mas, além das competições, se estamos falando de grandes projetos da vida real, não são mais 40 linhas versus 200 linhas. Em grandes projetos, uma enorme base de código começa a ser um problema. Nesse ponto, você chega a:

C ++ vs Python?

insira a descrição da imagem aqui

O Python puro é lento. É por isso que o interpretador Python padrão (CPython) é escrito em C. Praticamente todos com funções internas escritas como C. altamente otimizadas C. Python também pode ser facilmente usado em conjunto com bibliotecas C (via ctypes ou como módulos cpython nativos ) e com bibliotecas C ++ via Boost :: Python . Dessa forma, você pode escrever sua lógica de alto nível em Python, uma linguagem flexível, que permite prototipagem e adaptação rápidas (o que significa que você pode gastar mais tempo aprimorando e aprimorando seu algoritmo). OTOH, você pode escrever suas funções de biblioteca de nível inferior no módulo C ou C ++. Um bom exemplo dessa abordagem é o SciPy, que é a biblioteca Python, mas, sob o capô, usa bibliotecas numéricas altamente otimizadas, como ATLAS, LAPACK, Intels MKL ou ACML da AMD.

vartec
fonte
O que você está escrevendo apenas raspa a superfície. Você está assumindo uma noção de 'melhor' que nem todos compartilham. Qualidade é sempre uma questão de adequação aos objetivos. A programação em C ++ nem sempre é uma boa opção para todos os objetivos.
Reinierpost
11
@reinierpost: foi por isso que escrevi sobre um esforço significativamente maior. Nos casos mencionados, o C ++ não é adequado, mas não porque não pode ser feito. Não é adequado, porque serão necessários muitos recursos para desenvolvedores.
vartec
Além do mais, simplesmente não é melhor nesse caso.
reinierpost
2
e, de fato, é o que acontece em muitos setores, os jogos, por exemplo, têm muito código Lua que une o código C ++ para desempenho e produtividade.
gbjbaanb
4

Na minha opinião, o que as pessoas consideram coloquialmente como "linguagens de programação" são na verdade três coisas distintas:

  1. Tipo e sintaxe do idioma
  2. IDE de linguagem
  3. Bibliotecas disponíveis para um idioma

Por exemplo, quando alguém menciona C # em uma discussão, você pode pensar que está falando sobre sintaxe de linguagem (1), mas é 95% certo de que a discussão envolverá a estrutura .Net (3). Se você não está projetando um novo idioma, é difícil e geralmente inútil isolar (1) e ignorar (2) e (3). Isso ocorre porque o IDE e a biblioteca padrão são "fatores de conforto", coisas que afetam diretamente a experiência do uso de uma determinada ferramenta.

Nos últimos anos, eu também participei do Google Code Jam. Na primeira vez, optei pelo C ++ porque ele possui um bom suporte para a leitura da entrada. Por exemplo, a leitura de três números inteiros de uma entrada padrão em C ++ se parece com isso:

int n, h, w;
cin >> n >> h >> w;

Enquanto em C #, o mesmo ficaria assim:

int n, h, w;
string[] tokens = Console.ReadLine().Split(' ');
n = int.Parse(tokens[0]);
h = int.Parse(tokens[1]);
w = int.Parse(tokens[2]);

Isso representa muito mais sobrecarga mental para uma funcionalidade simples. As coisas ficam ainda mais complicadas em C # com entrada de várias linhas. Talvez eu simplesmente não tenha descoberto uma maneira melhor naquela época. De qualquer forma, não consegui passar na primeira rodada porque tinha um bug que não consegui corrigir antes do final da rodada. Ironicamente, o método de leitura de entrada ofuscou o bug. O problema era simples, a entrada continha um número muito grande para um número inteiro de 32 bits. Em C # int.Parse(string)lançaria uma exceção, mas em C ++ o fluxo de entrada de arquivo definiria um certo sinalizador de erro e falharia silenciosamente, tornando o desenvolvedor desavisado inconsciente de um problema.

Ambos os exemplos demonstram como a biblioteca foi usada e não a sintaxe da linguagem. Primeiro demonstra a verbosidade e o outro demonstra a confiabilidade. Muitas bibliotecas são portadas para vários idiomas e alguns idiomas podem usar bibliotecas que não foram criadas especificamente para eles (consulte a resposta da @ vartec sobre o Python com bibliotecas C).

Para finalizar, saber o algoritmo certo ajuda. Nas competições de codificação, é crucial, especialmente quando recursos como tempo de execução e memória são propositadamente limitados. No desenvolvimento de aplicativos, é bem-vindo, mas geralmente não é crucial. A manutenção é mais importante lá. Isso pode ser alcançado aplicando padrões de design corretos, com boa arquitetura, código legível e documentação relevante, e todos esses métodos dependem muito das bibliotecas internas e de terceiros. Portanto, acho mais importante saber que tipo de rodas já foram inventadas e como elas se encaixam, e como fazer as minhas.

Imperador Orionii
fonte
11
A preparação é importante quando possível. Com o Google Code Jam, eu tenho uma pequena biblioteca que lê as entradas e exibe as saídas como elas desejam, e incluo esse código no meu envio.
Mark Hurd
Na segunda vez, fiz algo semelhante, mas como modelo de projeto. Ele cria um arquivo de origem com uma classe de entrada abaixo Maine poucas coisas dentro do Mainmétodo (instância da minha classe de entrada e o fluxo de saída e loop de caso).
Imperador Orionii
Não me lembro da última vez que li de stdin. Dê-me um arquivo que eu possa colar em um analisador JSON.
gnasher729
2

Se você deseja competir em competições de programação programada, deve aprender a linguagem mais expressiva permitida na competição. Perl provavelmente seria o melhor, seguido por Ruby ou Python. Você ainda precisará de boas instalações com algoritmos, mas pelo menos não ficará atolado escrevendo algo como

Integer prev = b.get(k)
if (prev == null) prev = 0
Integer v = a.get(k);
if (v == null) v = 0;
b.put(prev + v);

ao invés de

b[k] += a[k]

Não se preocupe em aprender várias bibliotecas. Eles são todos muito parecidos e a documentação está online. Tornar-se fluente em idiomas mais expressivos fará de você um programador melhor (mas possivelmente frustrado) em idiomas menos expressivos. O oposto não é verdadeiro.

NB

A diferença entre 200 linhas de código e 40 linhas de código é enorme e é ainda maior quando é a diferença entre um programa de 200.000 linhas e um programa de 40.000 linhas. Então é a diferença entre uma equipe de cinco pessoas e um gerente e uma equipe de um ou dois.

Kevin Cline
fonte
3
(a) Sei que C / C ++ / Java tendem a ser as primeiras posições em competições de programação. (b) C / C ++ é considerado a "linguagem mais poderosa" por muitos (definitivamente acima do Perl / Ruby / Python). (c) Devido à sobrecarga do operador, o código C ++ pode parecer quase idêntico ao seu segundo exemplo. (d) Uma verificação tão extensa (em Java, é?) é necessária apenas se: (1) Você não tem ideia do que está fazendo. (2) A natureza dos dados é tal que isso é necessário (não acontece em competições de codificação). (3) Você está escrevendo um código para ser usado por outras pessoas (não aplicável).
Dukeling
11
@Dukeling: de acordo com este estudo ( página.mi.fu-berlin.de / prechelt / Biblio / jccpprtTR.pdf ), as linguagens de script permitem um desenvolvimento mais rápido e um código-fonte menor. De acordo com outro estudo ( flownet.com/gat/papers/lisp-java.pdf ), o Lisp oferece ainda mais produtividade do que as linguagens de script. De acordo com o segundo estudo citado acima, o código Lisp é quase tão rápido quanto o código C ++, enquanto leva menos tempo para escrever.
Giorgio
"entre um programa de 200.000 linhas e um programa de 40.000 linhas": acho que você precisa distinguir. As diferenças devido à verbosidade da linguagem de programação (sintaxe) não adicionam complexidade ao código e, portanto, podem ter pouco impacto no esforço de manutenção necessário. Por outro lado, você pode ter uma contagem de linhas diferente devido a diferentes recursos de idioma. Por exemplo, em Python, você não precisa gerenciar a memória, enquanto em C, você deve implementar todo o gerenciamento de memória. Então, eu concordo com você que no código C você tem mais funcionalidade e definitivamente precisa de tempo de manutenção extra.
Giorgio
@ Giorgio Não estou discutindo sobre o tempo de desenvolvimento ou o tamanho do código fonte, apenas o que realmente acontece nas competições de programação, com base em uma experiência significativa.
Dukeling
11
Eu estava citando dois artigos científicos (que vale a pena dar uma olhada na IMO), não estava falando sobre o que as pessoas nas páginas da web pensam sobre isso. O fato de uma opinião ser difundida não implica automaticamente que ela é válida. :-) Pelo menos, é preciso verificar de alguma maneira rigorosa.
Giorgio
2

Qualquer algoritmo pode ser implementado em qualquer linguagem de programação. Afinal, não é a sintaxe que importa. Mas usar uma linguagem de alto nível como Python tem suas próprias vantagens. Menos trabalho e menos quantidade de codificação. Portanto, para implementar um algoritmo em Python, você precisará de menos linhas do que o necessário em uma linguagem de baixo nível como C.

O Python possui a maioria das estruturas de dados incorporadas à sua biblioteca. Mas em C, precisamos começar do zero e usar uma estrutura para construir tudo. Certamente, existem diferenças entre a linguagem de alto e baixo nível, mas a linguagem não deve impedi-lo de implementar qualquer algoritmo.

Robin Thomas
fonte
2

Embora extrapolar o exemplo "40 LoC vs 200 LoC", dizendo "bem, apenas um quinto do LoC total é obviamente mais rápido de escrever, portanto deve ser melhor" pode parecer tentador, eu realmente acho que há pouca verdade a ser encontrada lá.

Otimizar para menos LoC quase nunca é uma boa ideia na minha opinião. Sim, todo LoC escrito é um potencial para erros, e você nunca precisa depurar o que nunca escreveu etcetc. A questão é otimizar para facilitar a leitura e a dissociação. Não importa se você resolver um problema usando um grande regex de 20 linhas, em vez de escrever um módulo de 1k LoC. O regex será uma parede opaca, extremamente propensa a bugs, difícil de entender, pesadelo para alterar sem alterar seu comportamento de maneiras inaceitáveis, etc.

Livrar-se da clichê e da verbosidade que não agregam valor é muito bom, mas, por outro lado, usar algo como Java ou C #, ter conhecimento sobre padrões de design e ferramentas como o re-afiador, permite tanta flexibilidade na refatoração do código , limpá-lo com o tempo, quebrar coisas etc., isso seria MUITO mais difícil se você o tivesse escrito como um script python ou aplicativo ruby ​​muito menor.

Uma comparação muito reveladora: eu preferiria ter 100k LoC de código C # dissociado coberto por teste, preenchido com coisas de "exagero", como padrão de estratégia, fábricas etc., em vez de um aplicativo python de 20k que apenas "faz as coisas". 5 vezes mais código ou não, a arquitetura vence todos os dias.

Concordo plenamente que alguns tipos de trabalho são mais fáceis e convenientes em alguns idiomas, mas acredito mais na escolha do seu idioma com base em quais ferramentas você precisa e quais são os requisitos (e podem ser no futuro próximo).

sara
fonte