Existe correlação entre a escala do projeto e o rigor da linguagem?

69

Explicando a diferença entre o rigor das linguagens e paradigmas para um colega meu, acabei afirmando que:

  • Linguagens tolerantes, como linguagens dinâmicas e interpretadas, são usadas melhor para protótipos e pequenos projetos ou aplicativos da Web de médio porte. Ao escolher linguagens dinâmicas elegantes como Python ou JavaScript com o Node.js, os benefícios são:

    1. Desenvolvimento rápido,

    2. Código clichê reduzido,

    3. Capacidade de atrair jovens programadores criativos que fogem de "idiomas corporativos" como Java.

  • Linguagens estaticamente tipadas / compiladas são melhores para aplicativos que exigem maior rigor, como aplicativos ou aplicativos essenciais aos negócios para aplicativos de médio a grande porte.

    1. Paradigmas e padrões conhecidos desenvolvidos por décadas,

    2. Facilidade de verificação estática,

    3. Capacidade de encontrar muitos desenvolvedores profissionais com décadas de experiência.

  • Linguagens rígidas como Haskell, Ada ou técnicas como contratos de código em C # são melhores para sistemas que favorecem a segurança em detrimento da flexibilidade (mesmo que o Haskell possa ser extremamente flexível), como sistemas e sistemas essenciais que devem ser extremamente estável. Os benefícios são:

    1. Capacidade de capturar tantos erros quanto possível em tempo de compilação,

    2. Facilidade de verificação estática,

    3. Facilidade de provas formais.

No entanto, olhando para as linguagens e tecnologias usadas para grandes projetos por grandes corporações, parece que minha afirmação está errada . Por exemplo, o Python é usado com sucesso em sistemas grandes, como o YouTube ou outros aplicativos do Google, que exigem uma quantidade importante de rigor.

Existe ainda uma correlação entre a escala do projeto e o rigor da linguagem / paradigma que deve ser usado?

Existe um terceiro fator que esqueci de levar em conta?

Onde estou errado?

    
por Arseni Mourzenko 24.08.2013 / 19:18
fonte

5 respostas

38

Um interessante estudo de caso sobre os projetos de escala que usam linguagem dinâmica e interpretada pode ser encontrado em Scala inicial por David Pollak.

I started searching for a way to express the code in my brain in a simpler, more direct way. I found Ruby and Rails. I felt liberated. Ruby allowed me to express concepts in far fewer lines of code. Rails was so much easier to use than Spring MVC, Hibernate, and the other “streamlined” Java web frameworks. With Ruby and Rails, I got to express a lot more of what was in my head in a shorter period of time. It was similar to the liberation I felt when I moved from C++ to Java...

As my Ruby and Rails projects grew beyond a few thousand lines of code and as I added team members to my projects, the challenges of dynamic languages became apparent.

We were spending more than half our coding time writing tests, and much of the productivity gains we saw were lost in test writing. Most of the tests would have been unnecessary in Java because most of them were geared toward making sure that we’d updated the callers when we refactored code by changing method names or parameter counts. Also, I found that working on teams where there were mind melds between two to four team members, things went well in Ruby, but as we tried to bring new members onto the team, the mental connections were hard to transmit to new team members.

I went looking for a new language and development environment. I was looking for a language that was as expressive as Ruby but as safe and high-performance as Java...

Como você pode ver, grandes desafios no dimensionamento de projetos para o autor acabaram se tornando no desenvolvimento de testes e na transferência de conhecimento.

Em particular, o autor detalha mais detalhes explicando as diferenças na escrita de teste entre linguagens tipificadas dinamicamente e estaticamente no capítulo 7. Na seção "Brincadeiras comoventes de Bunnies: Escadas de Dwemthy", discute a porta Scala de um exemplo particular de Ruby:

Why the Lucky Stiff... introduces some of Ruby’s metaprogramming concepts in Dwemthy’s Array in which a rabbit battles an array of creatures. N8han14 updated the example to work in Scala...

Compared to the Ruby code, the library parts of the Scala code were more complex. We had to do a lot of work to make sure our types were correct. We had to manually rewrite Creature’s properties in the DupMonster and the CreatureCons classes. This is more work than method_missing. We also had to do a fair amount of work to support immutability in our Creatures and Weapons.

On the other hand, the result was much more powerful than the Ruby version. If we had to write tests for our Ruby code to test what the Scala compiler assures us of, we’d need a lot more lines of code. For example, we can be sure that our Rabbit could not wield an Axe. To get this assurance in Ruby, we’d have to write a test that makes sure that invoking |^ on a Rabbit fails. Our Scala version ensures that only the Weapons defined for a given Creature can be used by that Creature, something that would require a lot of runtime reflection in Ruby...

A leitura acima pode fazer alguém pensar que, à medida que os projetos crescem ainda mais, a escrita de testes pode se tornar proibitivamente incômoda. Esse raciocínio estaria errado, como evidenciado por exemplos de projetos bem-sucedidos muito grandes mencionados nesta mesma pergunta ("O Python é usado com sucesso para o YouTube").

A coisa é que o dimensionamento dos projetos não é realmente simples. Projetos muito grandes e de longa duração podem "pagar" diferentes processos de desenvolvimento de testes, com suítes de teste de qualidade de produção, equipes de desenvolvimento de testes profissionais e outras coisas pesadas.

As suítes de teste do YouTube ou o Kit de Compatibilidade com Java certamente têm um diferente life do que testes em um pequeno projeto tutorial como Array de Dwemthy .

    
por 24.08.2013 / 23:10
fonte
24

Sua afirmação não está errada. Você só precisa cavar um pouco mais fundo.

Simplificando, sistemas grandes usam vários idiomas, não apenas um idioma. Pode haver partes que são construídas usando idiomas "estritos", e pode haver partes que são construídas usando linguagens dinâmicas.

Quanto ao seu exemplo do Google e do YouTube, ouvi dizer que eles usam principalmente o Python como "cola" entre vários sistemas. Apenas o Google sabe com que esses sistemas são construídos, mas aposto que muitos dos sistemas críticos do Google são criados usando linguagens restritas e "corporativas" como C ++ ou Java, ou talvez algo que eles mesmos criaram como o Go.

Não é que você não pode usar linguagens tolerantes para sistemas de larga escala. Muitas pessoas dizem que o Facebook usa PHP, mas elas esquecem de mencionar que o Facebook precisou criar diretrizes de programação extremamente rígidas para usá-lo de maneira eficiente nessa escala.

Então, sim, algum nível de rigor é necessário para projetos de grande escala. Isso pode resultar do rigor da linguagem ou estrutura, ou das diretrizes de programação e convenções de código. Você não pode simplesmente pegar alguns recém-formados, dar a eles Python / Ruby / JavaScript e esperar que eles escrevam softwares que se estendam por milhões de usuários.

    
por 24.08.2013 / 21:10
fonte
3

Existem dois tipos de erros a verificar: erros de tipo (concatenar um inteiro + lista de flutuantes) e erros de lógica de negócios (transferir dinheiro para uma conta bancária, verificar se a conta de origem tem dinheiro).

A parte "dinâmica" de uma linguagem de programação dinâmica é apenas o local onde a verificação de tipos ocorre. Em uma linguagem de programação "dinamicamente tipada", a verificação de tipos é feita durante a execução de cada instrução, enquanto em uma verificação de tipo "linguagem estaticamente tipada" é feita no tempo de compilação. E você pode escrever um interpretador para uma linguagem de programação estática (como emscriptem ), e você também pode escrever um compilador estático para uma dinâmica linguagem de programação (como gcc-python ou shed-skin faz).

Em uma linguagem de programação dinâmica, como Python e Javascript, é necessário escrever testes de unidade não apenas para a lógica de negócios do programa, mas também para verificar se o programa não possui erros de sintaxe ou de tipo. Por exemplo, se você adicionar "+" um inteiro a uma lista de flutuantes (o que não faz sentido e emitirá um erro), em uma linguagem dinâmica, o erro será gerado em tempo de execução ao tentar executar a instrução. Em uma linguagem de programação estática como C ++, Haskell e Java, esse tipo de erro de tipo será capturado pelo compilador.

Uma pequena base de código em uma linguagem de programação verificada dinamicamente é mais fácil de procurar por erros de tipo, porque é mais fácil ter uma cobertura um> do código-fonte. É isso aí, você executa o código manualmente algumas vezes com valores diferentes e pronto. Ter uma cobertura de 100% do código-fonte dá a você uma boa indicação de que seu programa pode não ter erros de erros .

Com uma base de código grande em uma linguagem de programação verificada dinamicamente, é mais difícil testar cada instrução com todas as combinações de tipos possíveis, especialmente se você for descuidado e escrever uma função que retorne uma string, lista ou objeto personalizado dependendo de seus argumentos.

Em uma linguagem de programação verificada estaticamente, o compilador detectará a maioria dos erros de tipo em tempo de compilação. Eu digo mais porque uma divisão por erro zero, ou um erro de matriz fora dos limites também são erros de tipo.

Na maioria das vezes, a discussão real não é sobre linguagens de programação, mas sobre as pessoas que usam essas linguagens. E isso é verdade porque, por exemplo, a linguagem assembly é tão poderosa quanto qualquer outra linguagem de programação, mas estamos escrevendo código em JavaScript. Por quê? Porque somos humanos. Primeiro, todos nós cometemos erros e é mais fácil e menos propenso a erros usar uma ferramenta dedicada especializada para uma tarefa específica. Em segundo lugar, há uma restrição de recursos. Nosso tempo é limitado e escrever páginas da Web na montagem demoraria séculos para terminar.

    
por 30.06.2014 / 09:56
fonte
3

Minha experiência com sistemas grandes é que eles permanecem ou não por escolha de idioma, mas por questões de design / arquitetura ou cobertura de teste . Eu prefiro ter uma equipe Python talentosa no meu projeto de grande empresa, do que uma de Java medíocre.

Dito isto, qualquer linguagem que lhe permita escrever significativamente menos código , vale a pena olhar (por exemplo, Python vs Java). Talvez o futuro esteja em linguagens inteligentes e tipificadas com inferência de tipos avançada (por exemplo, no molde Scala). Ou híbrido, como o C # está tentando com seu qualificador dynamic ...?

E não vamos esquecer o "outro" benefício de tipagem estática: o código IDE-completamento / intellisense, que na minha opinião é uma característica essencial, não uma boa ideia.

    
por 25.03.2015 / 14:26
fonte
0

Outra consideração é o quem está por trás de escrever aplicativos de grande escala. Eu trabalhei em muitos lugares que querem usar Ruby ou Python em alguns grandes projetos de estilo corporativo, mas são consistentemente "abatidos" por gerentes de TI e equipes de segurança corporativa precisamente por causa da natureza de código aberto dos projetos.

Foi-me dito: "Não podemos usar Ruby on Rails porque é open source e alguém pode colocar hacks lá que roubam informações críticas ou protegidas". Me desculpe, mas uma vez que alguém tenha essa mentalidade de que o código aberto é o mal, é quase impossível mudá-lo. Essa linha de pensamento é uma doença corporativa.

C # e Java são linguagens confiáveis com plataformas confiáveis . Ruby e Python não são idiomas confiáveis.

    
por 24.08.2013 / 21:41
fonte