Depois de um ano trabalhando com C# , gostaria de partilhar algumas ideias comparativas entre a plataformas .NET e a Java e as linguagens C# e Java.
Já devem estar pensando que lá vem mais um cara fazer comparações e dizer que é tudo a mesma coisa. Não. Não é tudo a mesma coisa e resposta é bem definitiva. A plataforma Java está a anos luz à frente da plataforma .net. A razão é simples. A plataforma .net não se preocupa muito em acomodar as preocupações e os casos de uso de bilhões de pessoas. O seu foco é mais no aqui e agora, com possibilidade de interagir com o OS. É possível ter grandes sistemas criados em .NET ? com certeza, mas a um custo e esforço muito maior. A plataforma .net é voltada a resultados e não é muito acadêmica. A curva de aprendizado é suave e rapidamente você consegue ter algo funcionando. Especialmente se o seu stack tecnológico é completamente baseado em tecnologias Microsoft. Ai sim a plataforma brilha. Contudo certas partes são um pouco restringentes demais. Se olharmos o cubo de arquitetura e compararmos as duas plataformas em relação a teremos uma melhor ideia do que estou falando.
A plataforma física é a própria máquina seguida de drivers na plataforma baixa , o OS na plataforma alta, as tecnologias de programação na plataforma virtual e a plataforma de aplicação que a (infra) estrutura do seu sistema. A plataforma .NET permite a você mais flexibilidade na hora de comunicar com a plataforma alta e interagir com o OS, mas ao mesmo tempo também é mais restrita ao nível da aplicação. Ele sabe fazer apenas uma coisa e pronto. Ou a sua aplicação encaixa com isso, ou nada feito. Não ha nada que você possa manipular ou alterar para fazer melhor. Quando ha, são coisas a que poucos se atrevem pela complexidade e pelo custo/beneficio. Nesse caso é mais comum você partir para componentes prontos e alguns até pagos, porque não é divertido mexer com o interior da máquina. Porque a plataforma provê quase tudo, não ha necessidade de inventar muito e você consegue ter um resultado palpável rapidamente. A Microsoft sempre teve tradição no desenvolvimento RAD. O problema é que quando você quer alterar ou prover alguma coisa um pouco diferente você está nas mãos da plataforma que tende a ser mais fechada que a plataforma Java. Fechada não é bem o termo. Coloquemos assim: a caixa é mais preta. Do outro lado a plataforma java lhe dá zero controle sobre o OS e a plataforma alta, embora você possa conseguir a interface necessária via JNI (Java Native Interface) a programação dessa parte não acontece na plataforma em si. Esta ausência de controle é proposital e quando necessária é provida pela JVM que ao longo do tempo tem vindo a prover mais formas de interagir com a plataforma alta. Mas este não é o objetivo. O objetivo é prover uma plataforma virtual – ou seja, uma plataforma boa para muitos tipos de aplicações e muitos e diversificados ambientes. Desde o Java Card rodando no seu cartão de crédito, à sua set-top-box da sua companhia de TV por cabo , ao chip de celular ( ou do decodificador de dito set-top-box) , até à aplicação de declaração de impostos no seu desktop, ao servidor web e empresarial que alimenta o tweeter. E mais recentemente a placas como o Raspbery Pi que já roda Java 8 Embeded. O objetivo é prover APIs que facilitam todos estes tipos de aplicação. A plataforma Java , por design, não tenta fazer o trabalho por você. Ela apenas promove as API para que você possa desenvolver a sua própria plataforma de aplicação. É por isso que as pessoas têm a sensação que em java se programa mais e as coisas demoram mais. É porque as empresas têm a mania de criar uma plataforma de aplicação para cada aplicação que fazem. A plataforma de aplicação é a parte mais cara do custo do software e se você faz uma cada aplicação o negócio não escala. É por isso que em alguns lugares você houve falar de “frameworks” ou de “infraestrutura” que em tese é reaproveitável de umas aplicações para outras. O problema desta abordagem é que quem cria esses frameworks não sabe muito bem o que está fazendo e eles acabam ficando obsoletos rapidamente. Para que uma plataforma de aplicação sobreviva ao tempo ela tem que abstrair a plataforma virtual por baixo. E isso, acredite, não é fácil. Nada mesmo. Alguns exemplos de sucesso nessa area são o Ruby On Rails e o Grails que partem de uma plataforma virtual como o ruby ( no primeiro caso) e java+ groovy no segundo para prover um nivel de isolamento que torna a plataforma de aplicação mais independente da plataforma virtual subjacente.
Portanto, em java você precisa criar sua plataforma de aplicação do chão porque a plataforma virtual java lhe dá muitas opções. Talvez opções demais. Em .Net as opções são menos e mais dirigidas a resultados. Praticamente tudo foi decidido por você, você apenas tem que usar. A quantidade de frameworks disponíveis para java não é coincidência. É o próprio propósito da plataforma, e como tal a plataforma é um sucesso. É impossível remover java do mundo. Tanto é assim que é possível executar Java dentro do .Net e muitos frameworks conhecidos do mundo java tem sido portados para o mundo .net. Porquê ? Porque, como disse, o custo beneficio é muito pequeno quando isto é feito em pequena escala. Mas frameworks como Log4 , Hibernate e Spring são praticamente onipresentes.
Em poucas palavras a plataforma Java é melhor que plataforma .Net. Sem meios mas.
Mas enquanto a plataforma é onipresente e excelente em vários níveis, a linguagem java está mostrando seus anos. A linguagem em si sempre foi muito alinhada com a plataforma e a linkagem dinâmica sempre foi uma das suas maiores features, mas é exatamente ela que torna as coisas tão complicadas. O Java 7 deu um passo monstruoso na direção certa ao introduzir um novo bytecode. Ao contrário da microsoft que não vê problema em quebrar compatibilidade com código anterior , a Sun e agora a Oracle não têm esse luxo. São milhares de milhões de linhas de código que já estão escritas e compiladas em jars que as pessoas usam até hoje. Os mesmos jars. O Java 8 trará uma nova forma de pensar ao mundo java com a introdução de lambdas, mas o mérito não está na funcionalidade em si, mas na forma como ela foi implementada para vencer todos os entraves e limitação que a compatibilidade reversa implica. Com o java 8 vem também um novo conceito. O conceito que existem muitos e diferentes compiladores java e o javac da Oracle é apenas um entre eles. Com isso em mente a Oracle está lançando o conceito de um compilador expansível. Isto significa que poderá usar o compilador do java para criar outros compiladores ou compilar seu código em diferentes formas, inclusive criando suas próprias extensões à linguagem como novos operadores, por exemplo. Este conceito é revolucionário. Significa basicamente “se acham que é tão simples estender o java, então façam vocês mesmos”. O ponto aqui é todos sabem que a linguagem java precisa de uma revitalização ou irá ser relegada. Mas ela é tão intrínseca à API Java que seria irrealista criar uma nova linguagem para a plataforma que não pudesse usar as APIs que já existem. Várias linguagens têm aparecido e continuam aparecendo para preencher este vazio deixado pela linguagem java. Linguagens como Scala e Groovy já provaram que é possível estender a linguagem java a outro nível.
A linguagem C# sofre de alguns problemas conceituais que atrapalham um pouco a vida ( como o conceito de strut), especialmente quando você trabalha com genéricos ( que embora não sofram de erasure como em java, sofre como problemas de variância e contra-variancia. Por exemplo apenas interfaces podem ser contra-variantes, mas classes não. E struts não são classes, o que significa que os genéricos são mais ou menos genéricos porque constrangimentos genéricos nem sempre funcionam bem para classes e struts ao mesmo tempo e não ha como destingir entre os dois de uma forma transparente). Tenho trabalhando com C# no último ano e realmente é uma linguagem muito versátil e útil (se não tiver problemas em ignorar algumas falhas conceituais) . As vantagens são : conceito de operador, extensões não virtuais e LINQ. O conceito de operador não é util em larga escala, mas é muito útil ao criar objetos de valor como Money , Fraction e outros que traduzem valores e vêm equipados com operações. O sistema de operadores não é tão sofisticado como o de scala, mas atende perfeitamente. O conceito de extensões é bastante útil, sobre tudo encapsulando código repetitivo que de outra forma teria que ir num Utils da vida. Como são métodos é simples encadear chamadas a várias extensões e o compilador faz um bom trabalho escolhendo a extensão certa tendo em conta os tipos das variáveis e os tipos genéricos usados nas extensões. Linq é um conceito interessante. Ele se parte em duas vertentes. A primeira é a base para o resto que é o conceito que o compilador pode ler um lambda e processar sua informação num objeto chamado Expression que por sua vez pode ser usado para executar o lambda, mas mais importante que isso para ter acesso ao que o lambda está fazendo. É como ter objetos Method no java, mas em que o objeto lhe diz que operações vão acontecer lá dentro e entre quais argumentos. Este truque do compilador permite que você possa escrever lambdas que são mais fluentes de entender e depois obter toda a árvore de chamadas. É como um reflection avançado feito em compile time. A outra parte é pegar nesse objeto Expression ( que na realidade é forma uma arvore) e usá-lo para automatizar consultas ao banco de dados ou qualquer outra tecnologia como XML , Diretórios de Arquivos, grafos, ou de diretórios de nomes. Enfim, qualquer estrutura de dados que possa ser pesquisada. Esta é uma capacidade que o compilador dá que pode ser usada para muitas coisas diferentes que não só pesquisa. Pode ser usada para configurações complexas. Pode ser usada, na realidade para construir Builders avançados que são muito fluentes.
Claro que nem tudo são rosas e por outro lado, o uso de lamdas é um pouco mais restrito que nos lambdas do java e outras linguagens, porque SAM types (Single Abstract Method Types) não são possíveis de abstrair com lambdas. Apenas delegates. Que é um conceito diferente que não existem em java, mas na realidade não é assim tão necessário (é basicamente o padrão listenner na forma de um construto da linguagem). A linguagem C# tem avanços em relação ao Java que no dia a dia são muito úteis e permitem que o seu código fique curto e fluente, contudo o preço a pagar é que nem todas as apis ou construtos são igualmente sensacionais.
A atenção que foi dada a generics é realmente limitada e é óbvio que ninguém pensou direito das consequências das coisas de uma forma abrangente. Tanto é que, as features relacionadas a generics foram sendo incrementalmente lançadas e não todas de uma vez. Uma ue ficou para o fim, que é realmente triste é a Variância (co e contra). E coisas simples e obivas como a co-variância de métodos são simplesmente proteladas por falta de interesse de uns poucos como se pode ler em algumas respostas interessantes no stackoverflow. Chega a beirar o descaso de que tantos usuários da Microsoft lamentam. A diferença é que a Sun conseguir formar uma comunidade em torno da tecnologia. E isso lhe saia caro, mas também por isso ela foi comprada pela Oracle. O Java não é feito por uma pessoa, é feito por milhares, e nem todos pertencentes à empresa. É pera isso que existe o JCP e as universidades são chamadas a intervir e muito trabalho acadêmico está por detrás das decisões. No .NET as decisões são tomadas com base em custo/beneficio e não na opinião ou requisição de quem usa a ferramenta.
A linguagem C# é realmente mais convenientes que a linguagem java e o pessoal da Oracle , e a comunidade como um todo sabem disso. É por isso que linguagens emergem para a plataforma todos os dias: Cylon, Kotlin, Fantom, Groovy, Scala , Xtend, JRuby, JPyton … só para nomear algumas. Extentions são muito úteis e existem em scala e xtend de uma forma inteligente. Mas o poder co C# vem realmente do Linq, porque ele mune a linguagem com a capacidade de entender Monads e isso é muito poderoso (de novo, Scala também tem isso)
Resumindo, a linguagem do futuro é algo como mais como Scala e menos como Java ou C#. Isto porque tanto o java e o C# não fizeram um tão bom serviço quanto podiam ao incluir conceitos como generics, covariancia, extensões e monads. O java porque tem problemas de retrocompatibilidade originados na sua linkagem dinâmica e o C# porque teve alguns problemas no processo de tomar decisões e encontrar compromissos com a comunidade , especialmente a de utilizadores e a acadêmica. Scala é fortemente baseado em orientação a objetos como Java (Em C# é possível criar uns bichos meio estranhos que violam alguns princípios básicos de OO através de uma coisa chamada Explicit Implementation que viola explicitamente o principio de substituição de Liskov). Mas o que é bonito em scala é que a linguagem consegue manter-se fiel aos conceitos de OO e fugir dos problemas conceituais do C# e de compatibilidade do java. Um exemplo é a implementação de generics. Em scala os genéricos são retificados como em C# (o que significa que vc consegue qual é o tipo real que estão em T) e manter os princípios de variância e co-variância como em java.
Claramente o futuro é Scala , mas embora scala seja uma bem desenhada linguagem ela não tem uma API própria muito grande. Ou seja, é uma linguagem, mas não é uma plataforma virtual. Scala já funciona na plataforma java e até na plataforma .Net (através de um truque com uma máquina virtual java que corre em .NET). No fim de contas você pode ter o melhor de todas as opções. A melhor plataforma existente – java – com a linguagem que deixa no chinelo todas as outras – Scala. A migração de .Net/C# para Java/Scala me parece natural neste momento da historia , embora eu entenda que nem todo o mundo pode fazer essa migração, já existem exemplos de que é possível. E mais do que isso, que é a solução óbvia.
Tentei mostrar como chegar nesta conclusão de um ponto de vista macro ( e rápido, embora longo de escrever), mas internamente eu tive que chegar nesta conclusão iterativamente. Após iniciar o projeto MiddleHeaven e ver como a plataforma java evoluía (especialmente a plataforma JEE) comecei a ver que ao mesmo tempo que ficava mais complexo criar e manter o MiddleHeaven eu ia descobrindo as limitações da linguagem java. No fim descobri que precisava não apenas de uma API mas de uma linguagem que tornasse o uso da api fácil. Por um tempo brinquei com a ideia de criar a minha própria linguagem. Eu queria uma linguagem OO pura como java com uma sintaxe similar, mas com as capacidades avançadas que o C# e outras linguagens modernas têm. E cada vez que chegava em uma funcionalidade interessante para a linguagem via que Scala já tem essas capacidades. Além disso o compilador do Scala pode ser programado o que permite ainda mais opções (sim, a ideia do compilador java ser extensível não é original). Ai fica dificil de argumentar que é necessária outra linguagem… fora o tempo e os recursos que implicam criar uma linguagem…
Ai fica a ideia…
Excelente artigo. Mas tenho uma dúvida, Scala já uma linguagem madura o suficiente para sua adoção? A plataforma Java conta com uma série de frameworks para auxiliar no desenvolvimento, como fica essa questão com scala?
Madura com certeza sim. Tem várias empresas usando. Quando à API você pode usar toda a API Java e todos os frameworks java. Portanto vc pode fazer o mesmo que poderia fazer em java. Existem alguns frameworks especificos de scala que são melhores em algumas coisas ( como atores) e tem até um servidor web voltado mais para o paradigma scala (lift) , mas nada impede de usar scala junto com as tecnologias tradicionais do java.
A verdade é que Scala teve seu momento de Boom mas percebeu-se que é uma linguagem complexa demais, cheia de estruturas difíceis de usar e entender. Agora estão fazendo um trabalho para esconder essa complexidade, mas o estrago já foi feito.
Fábio, gostaria que envia-se algum link para corroborar sua opinião. Scala é uma linguagem muito rica que se utiliza de artificios muito espertos da OO e de programação orientada a funções mais alguns truques de compilador. Contudo, scala é ainda mais purista que java no que toca a Orientação a Objectos. Seus objetos tender a ser imutáveis o que os torna mais simples, não mais complexos. Talvez muita gente se sinta intimidada pelo poder dos tipos genéricos em scala, mas isso é porque scala implementou tipos genéricos como deve ser e não como um pensamento à posteriori como java e c#. Isso torna scala mais poderoso, mas não mais complexo.
É fácil dizer que scala parece mais complicado. Mas o mesmo pode ser dito do java se a pessoa so programa com C ou PHP. Sim, ha uma evolução natural que a pessoa tem que fazer para entender, mas qualquer pessoa com experiência em programação pode entender e apreciar o poder do scala. Scala não é mais complexa, é mais rica.