<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/java/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/java/index.xml" rel="self" type="application/rss+xml"/><item><title>[Akitando] #74 - Emacs vs Java | Oracle vs Google</title><link>https://akitaonrails.github.io/2020/03/18/akitando-74-emacs-vs-java-oracle-vs-google/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/03/18/akitando-74-emacs-vs-java-oracle-vs-google/</guid><pubDate>Wed, 18 Mar 2020 10:30:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/2q4WN-sIN6s"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIPTION&lt;span class="hx:absolute hx:-mt-20" id="description"&gt;&lt;/span&gt;
&lt;a href="#description" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Esta é uma história de coincidências e erros que moldaram o mundo de programação como você conhece hoje e que possivelmente mudem completamente esse mesmo mundo.&lt;/p&gt;
&lt;p&gt;Richard Stallman e James Gosling são dois gigantes da computação e as ações que eles tomaram colocaram em movimento uma série de eventos que culmina com o processo da Oracle contra o Google. Quem está certo?&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/2q4WN-sIN6s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIPTION<span class="hx:absolute hx:-mt-20" id="description"></span>
    <a href="#description" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esta é uma história de coincidências e erros que moldaram o mundo de programação como você conhece hoje e que possivelmente mudem completamente esse mesmo mundo.</p>
<p>Richard Stallman e James Gosling são dois gigantes da computação e as ações que eles tomaram colocaram em movimento uma série de eventos que culmina com o processo da Oracle contra o Google. Quem está certo?</p>
<p>Links:</p>
<ul>
<li>Richard Stallman - ILC 2002 (<a href="https://www.youtube.com/watch?v=4Jjhmc3Txv0"target="_blank" rel="noopener">https://www.youtube.com/watch?v=4Jjhmc3Txv0</a>)</li>
<li>My Lisp Experiences and the Development of GNU Emacs (<a href="https://www.gnu.org/gnu/rms-lisp.en.html"target="_blank" rel="noopener">https://www.gnu.org/gnu/rms-lisp.en.html</a>)</li>
<li>Free Software: Freedom and Cooperation (<a href="https://www.gnu.org/philosophy/rms-nyu-2001-transcript.txt"target="_blank" rel="noopener">https://www.gnu.org/philosophy/rms-nyu-2001-transcript.txt</a>)</li>
<li>James Gosling on Richard Stallman (<a href="https://news.ycombinator.com/item?id=21251109"target="_blank" rel="noopener">https://news.ycombinator.com/item?id=21251109</a>)</li>
<li>James Gosling on how Richard Stallman stole his Emacs source code and edited the copyright notices (<a href="https://www.reddit.com/r/programming/comments/dhrcxw/james_gosling_on_how_richard_stallman_stole_his/"target="_blank" rel="noopener">https://www.reddit.com/r/programming/comments/dhrcxw/james_gosling_on_how_richard_stallman_stole_his/</a>)</li>
<li>Open Source History: Why Didn’t BSD Beat Out GNU and Linux? (<a href="https://www.channelfutures.com/open-source/open-source-history-why-didnt-bsd-beat-out-gnu-and-linux"target="_blank" rel="noopener">https://www.channelfutures.com/open-source/open-source-history-why-didnt-bsd-beat-out-gnu-and-linux</a>)</li>
<li>Sun is using the GPL as a weapon&hellip;but against whom and for what purpose? (<a href="https://dzone.com/articles/sun-using-gpl-a-weaponbut-agai"target="_blank" rel="noopener">https://dzone.com/articles/sun-using-gpl-a-weaponbut-agai</a>)</li>
<li>Emacs violates GPL since 2009 (<a href="https://news.ycombinator.com/item?id=2820986"target="_blank" rel="noopener">https://news.ycombinator.com/item?id=2820986</a>)</li>
<li>CAN JAVA STILL BE FREE AFTER JANUARY 2019? (<a href="https://www.snowsoftware.com/int/blog/2019/03/07/can-java-still-be-free-after-january-2019"target="_blank" rel="noopener">https://www.snowsoftware.com/int/blog/2019/03/07/can-java-still-be-free-after-january-2019</a>)</li>
<li>Free but Shackled - The Java Trap (<a href="https://www.gnu.org/philosophy/java-trap.en.html"target="_blank" rel="noopener">https://www.gnu.org/philosophy/java-trap.en.html</a>)</li>
<li>The Oracle-Google Case Will Decide the Future of Software (<a href="https://www.wired.com/2016/05/oracle-google-case-will-decide-future-software/"target="_blank" rel="noopener">https://www.wired.com/2016/05/oracle-google-case-will-decide-future-software/</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>No último video eu tentei quebrar algumas ingenuidades que as pessoas costumam ter sobre software livre. Tem uma história em particular que eu queria contar mas que não cabia no vídeo então resolvi fazer um separado. E tem a ver com dois assuntos que nem todo mundo associa. Sobre a origem do GPL e sobre um dos motivos de porque Java demorou tanto pra ser aberto como GPL e algumas ramificações disso.</p>
<p>A idéia deste episódio é também ensinar sobre outro ponto importante: não existem empresas perfeitas e não existem pessoas perfeitas. Por alguma razão as pessoas gostam de escolher celebridades que são excelentes em uma coisa e daí os fãs esperam que tudo que essa pessoa faça seja perfeito também. E ficam chateadas quando descobrem que na realidade essa pessoas não eram perfeita, era só pessoas. Você sabe que ainda é um adolescente se quando isso acontece sua reação é falar &ldquo;Nossa, eu esperava mais dessa pessoa&rdquo;.</p>
<p>Eu não me frustro com essas coisas porque eu não coloco nada nem ninguém num pedestal. Eu admiro o resultado de seus trabalhos e só. Meu mundo seria chato demais se eu ficasse perdendo tempo julgando coisas irrelevantes. Exemplo disso, a despeito do que muita gente pode imaginar, eu gosto de Java, ou melhor, eu respeito as milhões de horas homem colocada no Java. E por consequência eu respeito o trabalho de seus criadores como James Gosling ou Bill Joy. Eu gosto de Linux, sempre vou respeitar o trabalho hercúleo que o Linus Torvalds precisou executar pra conseguir isso. E eu também gosto de usar todo o ferramental GNU e tiro o chapéu pro Richard Stallman. Eu não pretendo cagar regra na cabeça de nenhum deles, porque eu não consigo me ver realizando nem metade do que esses nomes e vários outros conseguiram entregar. Por outro lado, é só até esse o limite que eles me interessam: o software.</p>
<p>Se o Stallman ou o Torvalds são socialistas ou capitalistas, se são democratas ou republicanos, o que eles dizem ou deixaram de dizer, nada disso muda a qualidade do software. Se realmente me interessasse cagar regra nisso, cadê eu desenvolvendo um projeto melhor que o deles? Seria muito hipócrita da minha parte achar que sou melhor que eles e ao mesmo tempo continuar usando o que eles criaram. Eu sou pragmático, não sou evangelista de software livre e nem de Microsoft e por isso vou seguir rodando Windows com Linux em cima dele. E pra demonstrar porque é perda de tempo achar que o mundo é maniqueísta e separado entre o Bem e o Mal, deixa eu contar uma história &hellip;</p>
<p>(&hellip;)</p>
<p>Se você não conhece Richard Stallman nem sua reputação controversa, basta dizer que ele é o criador do conceito de software livre, da licença GPL e diversos softwares importantes que estão em toda distro Linux como o compilador GCC ou o editor de textos Emacs. E eu diria que é só isso que você precisa saber. Mas se você tem interesse em assuntos de software livre deveria pelo menos ler todos os textos no site gnu.org. Foi o que eu fiz quando era estudante na faculdade.</p>
<p>Em 2002 o Stallman fez uma palestra na International Lisp Conference. Você que é fã de programação funcional, deveria saber que dezenas de programadores já programavam em linguagens funcionais como Lisp décadas antes de você descobrir o termo que, obviamente, não nasceu agora. Nessa palestra ele começa contando seu primeiro contato com Lisp nos anos 70, quando ele tinha acabado de entrar em Harvard e escreveu seu primeiro interpretador Lisp pra um PDP-11, uma máquina pequena que tinha uns 8 kilobytes de memória. E ele escreveu esse interpretador só com umas mil instruções. Lisp é um software fascinante que se você ainda não conhece, deveria.</p>
<p>Anos depois ele se aventurou a escrever um Lisp de verdade quando começou a trabalhar no MIT, no laboratório de Inteligência Artificial. Parece termos que você associa como modernos né? Lisp, programação funcional, inteligência artificial. Estamos falando do meio dos anos 70. De novo, você não está descobrindo nada de novo, é tudo derivado de mais de 4 décadas atrás.</p>
<p>De qualquer forma ele resolveu escrever um editor de textos chamado Emacs. Mas esse não é o Emacs que conhecemos hoje, era um editor escrito em linguagem de máquina, assembler de PDP-10. Pra quem não sabe, o Emacs é um editor de textos famoso porque ele contém uma linguagem de programação embutida, o Emacs Lisp ou elisp que é um dialeto de Lisp usado pra escrever código que manipula o editor. Toda vez que você instala uma extensão num Sublime Text, Atom ou VS Code, a idéia original vem do Emacs e muitos vão argumentar que Emacs ainda é superior nisso.</p>
<p>Porém, essa primeira versão ainda não tinha um interpretador Lisp. A idéia na verdade veio de outro editor que eles usavam, o TECO que significa Text Editor and Corrector, que tinha uma linguagem super feia porque ele não foi originalmente pensado pra ser programável. Era um editor que acabou ganhando funcionalidades de ser extensível via script.</p>
<p>De qualquer maneira, várias versões diferentes começaram a ser feitas. O próprio Stallman começou a desenvolver uma versão de Emacs em cima desse Teco. Outros desenvolvedores como Dan Weinreb e Bernie Greenberg tiveram a idéia de escrever Emacs usando o MacLisp do Multics. A idéia era tentar desenvolver um editor que fosse super flexível, com suas estruturas de dados internas como o buffer de edição, acessível a um Lisp e dessa forma fazer um meta-editor, ou seja, você podia editar o próprio editor.</p>
<p>Na sequência, o primeiro Emacs escrito em C que rodava em Unix veio de ninguém menos que James Gosling, que muitos hoje ainda devem reconhecer como um dos criadores do Java. Foi quando o Gosling também estava na faculdade. E essa versão foi conhecida como GosMacs. A palestra do Stallman é focada mais na história de como a pequena comunidade Lisp dos anos 70 foi desmantelada por uma briga comercial entre duas empresas que se derivaram do laboratório de inteligência artificial do MIT, a Lisp Machines Inc e a Symbolics.</p>
<p>O final dessa briga feia motivou Stallman a criar um sistema operacional livre que ele acreditava que seria necessário pra recriar uma comunidade livre de Lisp. Porém, diferente das máquinas especializadas de Lisp, que tinham instruções em nível de máquina que tornavam Lisp robusto e rápido, máquinas mais gerais não iam conseguir rodar Lisp de forma eficiente. Então, embora a intenção original fosse fazer um sistema operacional em Lisp, ele optou em fazer o sistema GNU em C e sobre esse sistema ele poderia rodar Lisp como um programa.</p>
<p>E assim, nos anos 80, começa o desenvolvimento do sistema GNU que você usa até hoje. Se você não sabia, - e isso todo mundo de software livre vai repetir na sua orelha até você cansar -, o que você roda é um sistema GNU com a kernel do Linux e por isso eles insistem que o sistema todo deveria no mínimo ser chamado de GNU/Linux.  Eu sou a favor de nomenclaturas corretas mas esse acabou virando um daqueles casos que o nome popular significa mais do que o original. Quando falamos que estamos rodando “Linux” normalmente a gente quer dizer uma distribuição inteira, que inclui a kernel do Linux, o sistema GNU e vários outros software que compõe um pacote completo &ldquo;Linux&rdquo;. Usar Linux basicamente quer dizer um sistema que não é Windows nem Mac.</p>
<p>De qualquer forma, pra escrever o sistema nasce o GNU Emacs. E como o sistema GNU seria em C, ele precisava também de um editor Emacs escrito em C. Ele poderia escrever um do zero mas naquela época já existia o Gosling Emacs. Segundo os relatos do próprio Stallman, um amigo dele disse que tinha contribuído pro GosMacs e ele tinha uma permissão por e-mail do Gosling dizendo que ele podia distribuir a versão dele. Entendam, naquela época não havia ainda os conceitos modernos de software livre e licenças. Os hackers dos anos 70 simplesmente distribuiam o código por fita ou outros meios pra quem pedisse.</p>
<p>O Gosling, sendo um hacker daquela época, estava no mesmo espírito de colaboração e distribuia o código do GosMacs pra quem tivesse interesse em contribuir. Então quando o amigo do Stallman disse que era ok usar o GosMacs o Stallman embarcou. Só como tangente técnica, o GosMacs não era um Emacs como o feito em MacLisp por Greenberg pro Multics. Ele implementou uma linguagem de script muito mais simples chamada de mocklisp que parecia Lisp mas não tinha o conceito mais poderoso de tudo ser dados no interpretador e ser fácil manipular qualquer estrutura de dados do editor.</p>
<p>Pra quem não entende isso, se você for de Javascript por exemplo, seria o equivalente a você abrir o console do navegador e injetar novos códigos Javascript e conseguir inspecionar os dados em memória da página e tudo sem precisar recompilar ou recarregar a página. É o que o Emacs fazia nos anos 70 graças ao MacLisp. E hoje em dia é o que um editor como Atom ou VS Code faz também, é o mesmo conceito. De qualquer forma o mocklisp era muito mais simplório e o Stallman decidiu que não dava pra usar aquilo e ele resolveu substituir o mocklisp por um Lisp de verdade. Segundo Stallman o mocklisp não tinha um tipo de dados de estrutura, não tinha listas, não tinha arrays, não tinha symbols que são objetos com nomes.</p>
<p>Ao mesmo tempo que ele substituiu o mocklisp por um Lisp de verdade, ele precisou ir substituindo várias partes das estruturas internas do editor para que se tornassem objetos de Lisp e assim pudessem ser manipulados por script. Ele queria que a interface entre o Lisp e o editor fossem limpas, o que significava que objetos como buffer de edição, sub-processos, janelas, posição no buffer, tudo precisava ser objetos de Lisp, de forma que as primitivas do editor fossem chamáveis através de funções em Lisp. Esse trampo todo significou que seis meses depois ele praticamente reescreveu o GosMacs no que viria a ser o GNU Emacs.</p>
<p>Agora, a reviravolta aconteceu que depois disso. Aparentemente o Gosling vendeu o GosMacs pra uma empresa chamada UniPress. Pra piorar o tal amigo do Stallman que disse que tinha autorização de distribuição do Gosling perdeu o backup da mensagem. Então o Gosling Emacs se tornou Unipress Emacs que eles passaram a vender. No começo, vendo o GNU Emacs eles se interessaram em distribuir e até contratar o Stallman. Mas depois mudaram de idéia e em vez disso passaram a dizer na rede que ele não estava autorizado a distribuir o Emacs. Eles não disseram que iam processar ninguém nem nada, só que podiam pensar nisso um dia. E segundo o Stallman, isso foi suficiente pra fazer as pessoas pararem de usar o GNU Emacs com medo de serem processadas.</p>
<p>Como o Stallman já tinha reescrito uma boa parte do Gosling Emacs pra colocar Lisp e transformar em GNU Emacs, ele resolveu continuar o trabalho e substituir o que faltava, e assim não ter mais nenhum bit do código fonte do antigo GosMacs e não ser mais um problema contra a Unipress. Segundo ele, foi o trabalho de pouco mais de uma semana pra terminar. Mas por causa desse episódio, diz a lenda que assim nasceu a primeira licença copyleft na forma do Emacs General Public License. A primeira vez que o nome GNU General Public License apareceu foi em junho de 1988. E dali ele veio evoluindo pra ser um pouco menos restrita pra bibliotecas com o advento do LGPL junto com o GPL v2 lá por 1999. Durante esse período nasceu a kernel do Linux que se uniu ao sistema GNU e possibilitou as distros Linux que você usa até hoje.</p>
<p>E o GPL v3 foi o assunto do meu video de Apple e GPL que eu recomendo que vocês assistam. E assim termina a página da história do GPL do site free soft.org que eu falei. mas não seria um video no meu canal se fosse só isso. A história tem uma outra reviravolta.</p>
<p>(video gosling)</p>
<p>Em 15 de março de 2019 o canal Computer History Museum gravou uma entrevista com James Gosling. Eu vou voltar nessa entrevista em outro episódio, mas o trecho que nos interessa hoje foi quando ele foi questionado sobre o episódio do Emacs e num 180 graus de evento ele resolveu acusar o Stallman de ter roubado o GosMacs.</p>
<p>Segundo sua versão da história, o GosMacs como eu disse estava sendo desenvolvido no espírito de software aberto e distribuído quando ele estava na faculdade, em Carnegie Mellon, mas num belo dia ele parou pra pensar &ldquo;bom, eu posso continuar sendo o Mr. GosMacs ou eu posso me focar e me formar de uma vez da faculdade&rdquo;. Ele procurou pessoas que quisessem continuar mantendo o GosMacs mas ninguém tinha muito tempo pra assumir o projeto. Diz ele que chegou a oferecer até pro próprio Stallman e nem ele tava muito a fim porque na época ele era total anti coisas Unix. No final ele achou dois caras que estavam a fim de manter o projeto, mas eles iam precisar ganhar algum dinheiro com isso.</p>
<p>Como background, o Gosling explica uma coisa que parece que era comum em muitas universidades americanas, de que se o aluno cria alguma coisa dentro da universidade, essa criação parcialmente pertence à universidade. Então você não pode comercializar e nem mesmo dar de graça o que foi produzido enquanto era aluno. Carnegie Mellon no começo era mais frouxo com isso e o aluno era dono do que criava. Na época Carnegia era uma universidade pequena mas que tinha dois departamentos que se destacavam mundialmente, uma era a de artes e a outra a de computação. Daí aconteceu que um dos alunos de artes pro seu projeto de mestrado criou uma opera rock que acabou se tornando um puta sucesso financeiro e aí parece que a universidade tentou mudar retroativamente as regras de propriedade intelectual, supostamente pra tentar pegar um pedaço desse bolo.</p>
<p>Pra piorar no departamento de computação aconteceu algo similar onde um desenvolvedor chamado Brian Reed criou um software que se tornou muito popular chamado Scribe, um formatador de textos. E de novo, a universidade supostamente tentou algo similar com ele. E por conta desses episódios os alunos e professores tomavam muito cuidado com assuntos de propriedade intelectual. O Gosling conta isso na entrevista pra dizer que sob os conselhos do professor Mike Shamus ele adicionou cabeçalhos de textos de copyright em todos os arquivos do código fonte do GosMacs e ele tomava o cuidado de pedir uma carta de toda pessoa que quisesse uma cópia do GosMacs, basicamente dizendo que aceitavam a licença. Apesar que algumas pessoas daquela época reportam que pediram a tal cópia mas nunca tiveram que mandar nenhuma carta. Seria o equivalente hoje de você apertar o checkbox aceitando Termos e Condições quando instala um software.</p>
<p>Então, quando ele resolveu não ser mais o Mr. GosMacs e os tais dois caras apareceram, o acordo era que o GosMacs precisava ser grátis pra universidade e ao mesmo tempo não ser ridiculamente caro pra todo o resto. Os dois, segundo Gosling, eram tipo empreendedores de garagem e o novo Unipress Emacs parece que ganhou alguma tração e eles conseguiram algum dinheiro pra pagar ir pagando as contas.</p>
<p>Agora, segundo a versão do Gosling, quando o Unipress Emacs estava de boa no seu canto, pagando as contas, o Stallman ficou doidão. Assim mesmo que ele fala na entrevista “freak out” e saiu editando todos os cabeçalhos de copyright do código fonte do antigo GosMacs e liberou como GNU Emacs. Na cabeça do Gosling foi só isso que o Stallman fez com o código. E aí a IBM e a Digital Equipment, a DEC, pegaram essa versão e começaram a distribuir de graça, o que basicamente matou o mercado da Unipress. Daí eles resolveram processar a IBM e a DEC e isso virou um puta caso cabeludo. No final parece que eles ganharam e a IBM e DEC pagaram danos pra Unipress. Só que o GNU Emacs não desapareceu e depois disso a Unipress teve que mudar de modelo de negócio e fazer outra coisa.</p>
<p>(.. final da entrevista)</p>
<p>Como eu não estava lá presente no começo dos anos 80, minha opinião de hoje é que Stallman, Gosling, a Unipress, a IBM e DEC todos foram vítimas do não entendimento das leis de copyright. Sem precisar acusar ninguém de má índole, a resposta mais simples parece ser que foi ingenuidade mesmo. Eram todos basicamente recém formados de faculdade. O próprio Gosling não estava muito aí, ele ouviu falar dessa idéia interessante de Emacs, que já existia na forma de um monte de macros do editor TECO que começou com Guy Steele, o Emacs de Greenberg feito em MacLisp e a própria primeira versão mais simples do Stallman em Assembly de PDP-10 feito uns 7 anos antes do GosMacs. O que o Gosling fez foi a primeira versão em C.</p>
<p>Quando o Stallman começou a desenvolver o sistema GNU no começo dos anos 80 ele de fato pegou o GosMacs e fez todas as modificações que eu falei, como trocar o mocklisp por elisp e assim por diante. Mas durante o período que a Unipress distribuiu a versão do Gosling, o GNU Emacs de fato continua ainda contendo algum código do GosMacs. Contrário do que o Gosling acredita, não foi só uma versão sem os textos de copyright. Portanto sim, faz sentido a IBM e DEC perderem porque a versão do GNU Emacs que eles distribuíram ainda continua código original do GosMacs conforme testemunhas técnicas puderam atestar comparando arquivos dos dois. E faz sentido que o GNU Emacs em si ainda existiu depois porque faltava pouco pra substituir o resto, que foi o que o Stallman fez, e a partir desse ponto já não infringia mais a licença da Unipress. E esse é o GNU Emacs que você muita gente usa até hoje.</p>
<p>Mas o Gosling não estava muito interessado nisso porque no fim dos anos 80 quando esse episódio se desenrolou ele foi recrutado pela Sun Microsystems. Um dos fundadores é ninguém menos que Bill Joy que veio de Berkeley e trabalhou no que hoje você conhece como o Berkeley Software Distribution ou BSD UNIX, na forma de distros como FreeBSD, OpenBSD ou NetBSD que muita gente usa até hoje, sendo o atual MacOS da Apple meio que um derivado do FreeBSD. O SunOS 4 era baseado em BSD e depois o Solaris viria a ser derivado de outro Unix, o System V. E ironicamente Bill Joy também tendo sido o inventor de outro editor de textos, o lendário VI que depois foi reescrito como Vi Improved ou VIM do Brian Moolenar.</p>
<p>De qualquer forma, na Sun eles perseguiram outro projeto o Star7, um tipo de set top box, pense os Roku ou Apple TV ou Chromecast que você tem hoje, mas no fim dos anos 80. Já é uma lenda que desse projeto foi que nasceu a linguagem derivada de Simula, Pascal, Mesa e outros, codenome Oak que se tornaria o Java que todo mundo usa hoje. Mas a parte importante é que no fim dos anos 80 e começo dos anos 90, ninguém sabia muito bem o que fazer com código fonte aberto. O Linux ainda não era o sucesso que é hoje, e era muito experimental e razoavelmente apavorante adotar uma licença nova como a GPL.</p>
<p>E você pode imaginar que não ajudou nem um pouco o Gosling ter raiva do Stallman por causa do incidente da Unipress. E você pode ver que ele ainda guarda rancor porque ele mesmo disse isso agora em 2019. Pro Stallman ele é a vítima por ter trabalhado em cima do código do Gosmacs e pra ele o Gosling traiu todo mundo que colaborou no código do GosMacs quando ele resolveu unilateralmente vender pra Unipress. Ele se sentiu atacado e temendo novos episódios semelhantes no futuro daí que lendariamente ele teve a idéia de criar o conceito de copyleft e inventar a General Public License ou licença GPL.</p>
<p>Por outro lado o Gosling se sente a vítima porque na visão dele o Stallman roubou o código dele e prejudicou o negócio dos seus amigos da Unipress. Tanto ele se sente assim que ele foi contra adotar o GPL pro Java logo no começo. Precisou de mais de 10 anos e muita pressão da comunidade e do mercado pra ele apoiar a iniciativa do OpenJDK. Em vez disso a Sun tinha uma licença semi-proprietária. O código fonte era aberto mas você não podia usar esse código. Porém, a propaganda da Sun sempre foi que eles eram bonzinhos e apesar de segurarem a propriedade de tudo que é derivado do Java, eles nunca iam fazer nenhuma maldade.</p>
<p>Esse problema é grave e foi uma discussão longa do fim dos anos 90 até o começo dos anos 2010. Entenda, no mundo jurídico a palavra verbal não significa muita coisa. Sempre se lembre disso: tenha tudo por escrito em papel, assinado e com testemunha, senão você é o trouxa da história. O Stallman não gostou do posicionamento da Sun. E por conta de episódios como o Bug do Milênio que levou à adoção de linguagens e tecnologias que fossem imunes a esse bug e à Bolha da Internet que também ajudou muito a adoção do Java, agora um monte de empresas estava à mercê da boa vontade da Sun. Eu lembro que acho que foi por volta de 2004 que ele escreveu o famoso artigo Libre mas Algemado, a Armadilha Java, ou Java Trap como ficou conhecido. Eu era programador Java e acompanhava essa novela na época e lembro que fiquei pensando: uma hora isso vai dar merda.</p>
<p>A comunidade de software livre não ficou parada, e desde os anos 90 já existiam engenharia reversa do Java com projetos como o GCJ que é o compilador Java em cima do GCC, o GCC Classpath que é a reimplementação das bibliotecas Java padrão de forma aberta. Mas era uma corrida de gato e rato difícil. O Java ficava cada vez maior, e mesmo você reimplementando uma versão cleam room, a versão da Sun era mais testado e tinha mais investimento então sempre era mais performático. Nenhuma versão aberta era 100% compatível porque a Sun não liberava os testes pra validar. Finalmente nasceu o projeto IcedTea só em 2006, mais de 10 anos depois do Java ter sido inventado, que se tornou o projeto OpenJDK.</p>
<p>Mesmo a introdução do OpenJDK na JavaOne de 2006 não foi exatamente um mar de rosas. Como eu já expliquei não basta abrir usando uma licença de software livre. Por exemplo, de cara eles mudaram pro OpenJDK ser GPK com uma cláusula de exclusão de classpath. Se fosse GPL puro todo projeto Java que linkasse com bibliotecas Java seria contaminado com GPL e precisaria abrir seu código. Por isso existe a cláusula de exclusão que é uma versão mais leve do LGPL que é feito justamente pra bibliotecas. Porém eles não fizeram isso pra tudo, levou um tempo ainda pra coisas como o JavaFX ganhar a cláusula de exclusão, então no dia um você ainda estava arriscando se contaminar com GPL. Não foi uma transição suave. Eventualmente as coisas estabilizaram mas levou um tempo. Eu fico imaginando se já em 2006 existia a informação interna de serem vendidos pra alguém e antes disso eles deixaram esse cavalo de tróia ativo.</p>
<p>“Ah, mas a Sun é boazinha e nunca vai dar ruim.” Essa era a postura até o mundo ficar chocado quando a Oracle comprou a Sun e passou a ser a nova dona do Java. E se alguém acreditou que a Oracle comprou a Sun pra ajudar o Java, pense de novo. Recapitulando a histórica o projeto Android começou lá por 2003. Segundo a Wikipedia, o Google tentou negociar com a Sun comprar licenças pra usar o Java mas a Sun recusou porque segundo o testemunho da Oracle, o objetivo do Google era fazer um fork proprietário e incompatível do Java, coisa que a Sun já sofreu antes como no caso do J++ da Microsoft nos anos 90.</p>
<p>Como naquela época o OpenJDK ainda não era o que é hoje o Google se voltou pra outro projeto open source, o Apache Harmony, que era outra engenharia reversa aberta, ou implementação clean room - que é o que se chama uma reimplementação do zero sem olhar o código fonte original pra garantir que você não vai cair em plágio. Esse desenvolvimento se tornou a virtual machine Dalvik que saiu nos Android. Ao que parece, o Apache Harmony incluía 37 chamadas de API e 11 mil e quinhentas linhas de código que supostamente eram centrais ao Java e esse é estopim do caso contra o Google. A Apache Foundation na época tinha tentado conseguir licença da Sun mas de novo a Sun não concordou por divergências nas licenças.</p>
<p>Quando o Google lançou o Android em novembro de 2007 o CEO da Sun resolveu publicamente congratular o Google pra comunidade achar que o Android continua fazendo parte do ecossistema do Java. Mas aí veio o soco no estômago, quando a Oracle anunciou em abril de 2009 que estava completando a aquisição da Sun por 7.4 bilhões de dólares no que o CEO da Oracle, Larry Ellison chamou a aquisição da linguagem Java &ldquo;do mais importante ativo de software que ela já adquiriu&rdquo;.</p>
<p>Menos de um ano depois, em agosto de 2010 a Oracle entra com processo contra o Google por infringir copyright e patentes. Esse caso é complicado e eu não tenho paciência de seguir cada reviravolta,  e entenda que este caso continua ativo até hoje. Em 2020 ainda não temos um veredito. E esse é o Java Trap que o Stallman avisou em seu artigo em 2004. Porém a discussão foi mais longe porque estão questionando se você implementar uma API que já existe é infringir copyright. Um exemplo tosco, System.out.println todo mundo sabe que é uma API do Java, essa e outras milhões que fazem parte da JVM e das classes standard que vem no JDK, se você reimplementar a API isso é considerado “fair use” ou isso é infringir propriedade intelectual?</p>
<p>Uma ramificação, Linux é software livre, mas ele também é a implementação de um outro padrão o POSIX que é a API do UNIX original, que não é livre. Já foi passada pra SCO, depois pra Novell e agora está na mão da Micro Focus. Se a Oracle ganhar e criar este precedente, então todo mundo que usa Linux se encontra numa posição ruim? A Micro Focus poderia processar todo mundo que usa Linux sobre o argumento que o Linux infringe copyright do UNIX ao reimplementar as mesmas APIs?</p>
<p>Pro Google a grande vantagem de ter implementado as APIs do Java e não ser o Java e sim uma implementação independente, foi porque ele achou que podia burlar as patentes e copyright da Sun e ao mesmo tempo se aproveitar de todo o ecossistema de código aberto, ferramentas e, principalmente, desenvolvedores de Java que poderiam potencialmente adotar o Dalvik do Android com mínimo esforço, se comparado à Microsoft ou Apple que precisaram convencer os desenvolvedores a adotar C# ou Objective-C. Mas se ele perder esse caso, além de ter que pagar até 80 bilhões de dólares de danos pra Oracle, pode gerar ramificações pra todo o mundo de código aberto.</p>
<p>Lembram que eu falei que definir fair use é complicado no episódio anterior? Este é um caso real e gigante, que alguns consideram o maior do século. E se você é um hater de Trump, deve odiar mais ainda a Oracle já que seu CEO Larry Ellison é um apoiador declarado. Apesar de tudo isso o julgamento não é trivial, por um lado, muitos argumentam e eu concordo que APIs não deviam ser objeto de copyright. Por outro lado, o caso da Oracle é que o Google não só implementou as APIs em cleanroom como eu falei, eles de fato usaram código do Java original. Como eu falei antes, o código fonte era aberto embora você não devesse usar porque a licença da Sun não era aberta. E se eu não entendi errado o projeto Apache Harmony que o Google usou, continha esses códigos também. Então não é um caso binário de certo ou errado. A forma como o suprema corte verbalizar a conclusão do caso pode ter efeitos em toda a indústria.</p>
<p>Na prática nenhum dos dois é totalmente certo nem totalmente errado. O Google escolheu se colocar nessa situação, ele poderia ter feito como a Microsoft, que depois que apanhou no caso do J++ da Sun, levou ao desenvolvimento do .NET e C#. Mas isso daria muito mais trabalho. Copiar a API do Java e até mesmo partes do código e criar um concorrente incompatível é muito mais simples e eles apostaram que iam sair ilesos disso. Foi uma aposta arriscada e eles sabiam disso, além do que eles não previram que a Sun seria obrigada a vender justo pra Oracle. Como eu já disse, você não pode se declarar ignorante da lei e dar de joão sem braço depois, foi uma aposta, eles blefaram e a Oracle pagou pra ver.</p>
<p>É impossível prever o futuro e vendo de trás pra frente sempre as coisas parecem mais simples. Mas veja que interessante, tudo isso está acontecendo porque o Java nunca foi realmente software livre. Durante sua história ele teve reimplementações como GCC Classpath ou Apache Harmony, mas eles nunca foram completos nem competitivos. Demorou até 2006 pra começar a iniciativa OpenJDK, e só por volta de 2008 que o OpenJDK começou de fato a ficar usável. Durante esse período todo mundo só confiou que mesmo o Java não sendo aberto, a Sun seria boazinha e ninguém viu a Oracle chegando um dia, nem o Google.</p>
<p>Se lá no meio dos anos 80, o Gosling não tivesse ficado com raiva do Stallman e tivesse comprado a idéia de software livre, talvez o Java tivesse tido a chance de ser aberto muito mais cedo, talvez desde o começo já que Bill Joy também veio do mundo dos hackers trocando código aberto. O que aconteceu em universidades como MIT, Carnegie Mellon, Berkeley e outras foi a origem dos conceitos de software livre. Mas, por outro lado, se o Stallman não tivesse se sentido prejudicado pelo Gosling e a Unipress, talvez não teríamos o GPL a tempo e software cruciais como Linux não teriam adotado essa licença no começo dos anos 90, estando a mercê de ser fechado num episódio similar ao da Unipress.</p>
<p>Aliás, o almoço grátis já acabou ano passado, em janeiro de 2019. Pra ter atualizações, negócios que vivem de Java precisam adquirir licença da Oracle diretamente ou via parceiros como a Oracle WebLogic ou SAP Netweaver. Ou usar OpenJDK e ficar por conta da comunidade. Ou pagar uma empresa que dá suporte ao OpenJDK como a Azul Systems, dentre outras alternativas. Mas não existe mais aquela idéia de &ldquo;confie na Sun e use Java&rdquo;. Essa é uma das razões de porque muitas empresas preferem não usar Java se não for realmente necessário, o que é uma infelicidade porque de fato a plataforma Java até hoje é uma das melhores que já foi criada. Resumo pra hoje em dia, se precisa usar Java, use OpenJDK.</p>
<p>Se você é novo em programação acho que vale a pena entender o quê é o quê nesse mundo que ainda está em constantes mudanças. Uma tecnologia não existe num vácuo. É importante entender a história das coisas que você usa. O mundo não é nem estático e nem preto no branco. Aliás, como última ironia, em 2011 descobriram que o Emacs, sim o software livre original, estava liberando binários sem liberar o código fonte completo por quase 2 anos, entre 2009 e 2011. Claro, parece que foi um erro da automação de releases e o Stallman se desculpou e já consertou isso, mas é pra ilustrar como é fácil cometer erros também. Todo mundo comete erros. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, não deixem de assinar o canal, clicar no sininho pra não perder os próximos episódios e compartilhem o video com seus amigos pra ajudar o canal. A gente se vê, até mais.</p>
]]></content:encoded><category>historia-da-computacao</category><category>java</category><category>leis-e-regulacao</category><category>akitando</category></item><item><title>Geração de Linguagem Natural em Ruby (com JRuby + SimpleNLG)</title><link>https://akitaonrails.github.io/2016/10/28/geracao-de-linguagem-natural-em-ruby-com-jruby-simplenlg/</link><guid isPermaLink="true">https://akitaonrails.github.io/2016/10/28/geracao-de-linguagem-natural-em-ruby-com-jruby-simplenlg/</guid><pubDate>Fri, 28 Oct 2016 17:53:00 -0200</pubDate><description>&lt;p&gt;Estou tocando um projeto que precisa gerar frases em inglês decentes. A primeira versão que fiz usava o jeito mais ingênuo possível: criar um template de string e ir fazendo substituições e concatenações simples.&lt;/p&gt;
&lt;p&gt;Mas dá pra imaginar que isso vira uma bagunça rapidamente quando você precisa lidar com pluralização, flexão verbal, e o código começa a ficar parecido com isso:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;There &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;is&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;are&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; user&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ou usar o suporte de I18n do Rails desse jeito:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Estou tocando um projeto que precisa gerar frases em inglês decentes. A primeira versão que fiz usava o jeito mais ingênuo possível: criar um template de string e ir fazendo substituições e concatenações simples.</p>
<p>Mas dá pra imaginar que isso vira uma bagunça rapidamente quando você precisa lidar com pluralização, flexão verbal, e o código começa a ficar parecido com isso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="s2">&#34;There </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="s1">&#39;is&#39;</span> <span class="p">:</span> <span class="s1">&#39;are&#39;</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="vi">@users</span><span class="o">.</span><span class="n">size</span><span class="si">}</span><span class="s2"> user</span><span class="si">#{</span><span class="s1">&#39;s&#39;</span> <span class="k">unless</span> <span class="vi">@users</span><span class="o">.</span><span class="n">size</span> <span class="o">==</span> <span class="mi">1</span><span class="si">}</span><span class="s2">.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou usar o suporte de I18n do Rails desse jeito:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">backend</span><span class="o">.</span><span class="n">store_translations</span> <span class="ss">:en</span><span class="p">,</span> <span class="ss">:user_msg</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:one</span> <span class="o">=&gt;</span> <span class="s1">&#39;There is 1 user&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="ss">:other</span> <span class="o">=&gt;</span> <span class="s1">&#39;There are %{count} users&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="no">I18n</span><span class="o">.</span><span class="n">translate</span> <span class="ss">:user_msg</span><span class="p">,</span> <span class="ss">:count</span> <span class="o">=&gt;</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#39;There are 2 users&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Para frases transacionais simples (tipo flash messages), isso resolve de sobra.</p>
<p>Mas se você quer gerar um artigo inteiro em inglês a partir de estruturas de dados, a lógica fica convoluta muito rápido.</p>
<p>Dei uma olhada em alguns projetos Ruby que poderiam ajudar, por exemplo:</p>
<ul>
<li><a href="https://github.com/chorn/nameable"target="_blank" rel="noopener">&ldquo;nameable&rdquo;</a> que faz coisas úteis assim:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Chris&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">gender</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; :male</span>
</span></span><span class="line"><span class="cl"><span class="no">Nameable</span><span class="o">::</span><span class="no">Latin</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;Janine&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">female?</span>
</span></span><span class="line"><span class="cl"><span class="c1">#=&gt; true</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<ul>
<li><a href="https://github.com/maetl/calyx"target="_blank" rel="noopener">&ldquo;calyx&rdquo;</a> que dá pra usar para gerar frases simples desse jeito:</li>
</ul>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GreenBottle</span> <span class="o">&lt;</span> <span class="no">Calyx</span><span class="o">::</span><span class="no">Grammar</span>
</span></span><span class="line"><span class="cl">  <span class="n">mapping</span> <span class="ss">:pluralize</span><span class="p">,</span> <span class="sr">/(.+)/</span> <span class="o">=&gt;</span> <span class="s1">&#39;\\1s&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">start</span> <span class="s1">&#39;One green {bottle}.&#39;</span><span class="p">,</span> <span class="s1">&#39;Two green {bottle.pluralize}.&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">bottle</span> <span class="s1">&#39;bottle&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;One green bottle.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;Two green bottles.&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Bonitinho, mas ainda inútil para as necessidades mais complexas que tenho em mente.</p>
<p>Então resolvi cavar mais fundo, no mundo obscuro do NLG, ou <strong>Natural Language Generation</strong> (Geração de Linguagem Natural). Cuidado para não confundir com NLP, que é Natural Language Processing, justamente o oposto do que eu quero. NLP recebe um texto em inglês e devolve uma estrutura de dados parseada.</p>
<p>Para <strong>NLP</strong> (parsing, tokenização, etc), recomendo demais o <a href="http://stanfordnlp.github.io/CoreNLP/"target="_blank" rel="noopener">&ldquo;Stanford CoreNLP&rdquo;</a>. Parece ser um dos mais robustos e completos por aí (vai, é de Stanford). Também é um projeto Java, e um download enorme (mais de 300MB!). Esses projetos de linguística são pesados pra caramba porque precisam baixar dicionários inteiros e bases de léxico.</p>
<p>Mas focando no meu problema atual, <strong>NLG</strong>, existem <a href="https://aclweb.org/aclwiki/index.php?title=Downloadable_NLG_systems"target="_blank" rel="noopener">várias opções</a> disponíveis. Sendo bem honesto, não fiz uma pesquisa muito extensa, então se você conhece qual é o mais robusto, bem mantido e com uma interface fácil de usar, deixa nos comentários aí embaixo.</p>
<p>Minha escolha foi o <a href="https://github.com/simplenlg/simplenlg"target="_blank" rel="noopener">SimpleNLG</a>. Pela página dele no GitHub dá pra ver que continua sendo bem mantido até hoje, é uma biblioteca Java simples e é uma das alternativas mais &ldquo;simples&rdquo;. Já o <a href="http://www.fb10.uni-bremen.de/anglistik/langpro/kpml/README.html"target="_blank" rel="noopener">KPML</a> está no extremo oposto: parece ser um dos mais antigos (desde os anos 80!) e robustos. Mas falando sério, você precisa praticamente de um Ph.D. só pra começar.</p>
<p>Ler o código-fonte Java do SimpleNLG foi chato, mas tranquilo o suficiente. Reserva um dia inteiro de estudo para se acostumar com o código e você está pronto.</p>
<p>O problema principal é que ele é escrito em Java, e eu não pretendo escrever nada em Java (ou derivados) por enquanto. Por um instante cheguei a considerar a empreitada de reescrever o troço todo em algo mais portátil, tipo Rust, que eu poderia carregar de qualquer lugar via FFI.</p>
<p>Mas mesmo o SimpleNLG tendo &ldquo;Simple&rdquo; no nome, ele tem algumas dependências cabeludas para carregar a base de léxico. E a base em si é um dump de HSQLDB, que é um banco escrito em Java. E ainda haveria a questão de manter um fork.</p>
<p>Desisti rápido dessa ideia e contornei o problema embrulhando a biblioteca dentro de um endpoint <a href="https://github.com/rails-api/rails-api"target="_blank" rel="noopener">Rails-API</a> simples. Tive uns problemas porque eu tinha o Git LFS rastreando os arquivos jar no meu sistema e o Heroku não suporta isso, e acabei com um deploy corrompido (cuidado com essas pegadinhas, aliás!).</p>
<p>No fim consegui colocar no ar um projeto JRuby + Rails-API funcionando com SimpleNLG embutido no Heroku. Você pode subir sua própria cópia clonando meu <a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a>. Funciona bem com o JRuby 9.1.5.0 mais recente. Você precisa pagar pelo menos um plano Hobby no Heroku. Java leva um tempo ridículo para subir e mais tempo ainda para esquentar. O free tier do Heroku desliga seu dyno se ele ficar parado, e a próxima requisição web vai dar timeout ou levar uma eternidade para responder.</p>
<p>Uma vez no ar, ele sobe o Rails e carrega <a href="https://github.com/Codeminer42/nlg_service/blob/master/config/initializers/simple_nlg.rb"target="_blank" rel="noopener">este initializer</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;java&#39;</span>
</span></span><span class="line"><span class="cl"><span class="no">Java</span><span class="o">::</span><span class="no">JavaLang</span><span class="o">::</span><span class="no">System</span><span class="o">.</span><span class="n">set_property</span> <span class="s2">&#34;file.encoding&#34;</span><span class="p">,</span><span class="s2">&#34;UTF-8&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_DEFAULT_LEXICON_PATH</span> <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG/resources/default-lexicon.xml&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl"><span class="no">SIMPLE_NLG_PATH</span>                 <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;lib/SimpleNLG&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Dir</span><span class="o">[</span><span class="s2">&#34;</span><span class="si">#{</span><span class="no">SIMPLE_NLG_PATH</span><span class="si">}</span><span class="s2">/*.jar&#34;</span><span class="o">].</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">jar</span><span class="o">|</span> <span class="nb">require</span> <span class="n">jar</span> <span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E depois mapeio as classes <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/models/simple_nlg.rb"target="_blank" rel="noopener">assim</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">SimpleNLG</span>
</span></span><span class="line"><span class="cl">  <span class="sx">%w(
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.aggregation
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.features
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.format.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.framework
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.lexicon
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.morphology.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.orthography.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.phrasespec
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.realiser.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.syntax.english
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser
</span></span></span><span class="line"><span class="cl"><span class="sx">    simplenlg.xmlrealiser.wrapper
</span></span></span><span class="line"><span class="cl"><span class="sx">  )</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">package</span><span class="o">|</span> <span class="n">include_package</span> <span class="n">package</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por fim, tenho um endpoint simples mapeado para uma action de <a href="https://github.com/Codeminer42/nlg_service/blob/master/app/controllers/api/realisers_controller.rb"target="_blank" rel="noopener">controller</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Api</span><span class="o">::</span><span class="no">RealisersController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">create</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">java</span><span class="o">::</span><span class="n">io</span><span class="o">::</span><span class="no">StringReader</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:xml</span><span class="o">]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">begin</span>
</span></span><span class="line"><span class="cl">      <span class="n">records</span> <span class="o">=</span> <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">getRecording</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">output</span> <span class="o">=</span> <span class="n">records</span><span class="o">.</span><span class="n">getRecord</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">record</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">        <span class="no">SimpleNLG</span><span class="o">::</span><span class="no">XMLRealiser</span><span class="o">.</span><span class="n">realise</span><span class="p">(</span><span class="n">record</span><span class="o">&amp;.</span><span class="n">getDocument</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="vi">@realisation</span> <span class="o">=</span> <span class="n">output</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span>
</span></span><span class="line"><span class="cl">      <span class="n">render</span> <span class="ss">plain</span><span class="p">:</span> <span class="vi">@realisation</span>
</span></span><span class="line"><span class="cl">    <span class="k">ensure</span>
</span></span><span class="line"><span class="cl">      <span class="n">reader</span><span class="o">.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O processo de gerar o texto final em inglês se chama <strong>&ldquo;realisation&rdquo;</strong> (realização). O SimpleNLG tem uma API Java bem completa, mas também expõe tudo num formato XML mais simples. O <a href="https://github.com/simplenlg/simplenlg/blob/master/src/main/resources/xml/RealizerSchema.xsd"target="_blank" rel="noopener">XML Realiser Schema</a> completo está disponível como XSD.</p>
<p>Se eu quiser escrever esta frase:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>Este é o XML que preciso montar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;NLGSpec</span> <span class="na">xmlns=</span><span class="s">&#34;http://simplenlg.googlecode.com/svn/trunk/res/xml&#34;</span> <span class="na">xmlns:xsd=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema&#34;</span> <span class="na">xmlns:xsi=</span><span class="s">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;Recording&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Record&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;Document</span> <span class="na">cat=</span><span class="s">&#34;PARAGRAPH&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;child</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;subj</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;ADVERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>there<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/subj&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">PERSON=</span><span class="s">&#34;THIRD&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;base&gt;</span>be<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;NPPhraseSpec&#34;</span> <span class="na">NUMBER=</span><span class="s">&#34;PLURAL&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;NOUN&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>story<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;spec</span> <span class="na">xsi:type=</span><span class="s">&#34;WordElement&#34;</span> <span class="na">cat=</span><span class="s">&#34;DETERMINER&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;base&gt;</span>a<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/spec&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;preMod</span> <span class="na">xsi:type=</span><span class="s">&#34;CoordinatedPhraseElement&#34;</span> <span class="na">conj=</span><span class="s">&#34;and&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>finish<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;coord</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>deliver<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/coord&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/preMod&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;compl</span> <span class="na">xsi:type=</span><span class="s">&#34;SPhraseSpec&#34;</span> <span class="na">MODAL=</span><span class="s">&#34;may&#34;</span> <span class="na">PASSIVE=</span><span class="s">&#34;true&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;vp</span> <span class="na">xsi:type=</span><span class="s">&#34;VPPhraseSpec&#34;</span> <span class="na">TENSE=</span><span class="s">&#34;PAST&#34;</span> <span class="na">NEGATED=</span><span class="s">&#34;true&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;head</span> <span class="na">cat=</span><span class="s">&#34;VERB&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&lt;base&gt;</span>test<span class="nt">&lt;/base&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="nt">&lt;/head&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/compl&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&lt;/vp&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/child&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;/Document&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Record&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/Recording&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/NLGSpec&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ok, eu sei, isso é absurdo.</p>
<p>Por isso resolvi seguir adiante e usar uma das forças mais reconhecidas do Ruby: criar <strong>DSLs</strong>, ou Domain Specific Languages.</p>
<p>O resultado da minha tentativa inicial de simplificar esse processo é a gem <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a>. Basta adicionar isso ao seu <code>Gemfile</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>gem &#39;nlg_xml_realiser_builder&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E o XML monstruoso ali em cima vira algo bem mais gerenciável, assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl"><span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="s1">&#39;PLURAL&#39;</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span><span class="o">.</span><span class="n">to_xml</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Entender as nuances de um <code>NPPhraseSpec</code> versus um <code>VPPhraseSpec</code>, ou a diferença entre um <code>WordElement</code> e um <code>StringElement</code>, está fora do escopo deste post. Mas a maior parte do XSD original foi mapeada <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/lib/nlg_xml_realiser_builder/consts.rb"target="_blank" rel="noopener">neste arquivo de constantes</a>.</p>
<p>Tenho <a href="https://github.com/Codeminer42/nlg_xml_realiser_builder/blob/master/spec/nlg_xml_realiser_builder_spec.rb"target="_blank" rel="noopener">algumas specs de aceitação</a> que geram XMLs como o de cima, postam no meu NLG Web Service que está no ar e pegam de volta as frases em inglês resultantes. Vou mudar esse processo no futuro, mas você já pode testar por conta própria.</p>
<p>As vantagens começam aqui. Vamos olhar o exemplo anterior mais de perto. De novo, ele renderiza esta frase:</p>
<blockquote>
  <p>&ldquo;There are some finished and delivered stories that may not have been tested.&rdquo;</p>

</blockquote>
<p>Repare que está no plural porque estou falando de &lsquo;stories&rsquo;, mas e se eu quiser uma versão no singular?</p>
<p>Abaixo está a nova versão, onde eu envolvo o código num método e faço o atributo &lsquo;NUMBER&rsquo; aceitar tanto &lsquo;PLURAL&rsquo; quanto &lsquo;SINGULAR&rsquo;:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">example</span><span class="p">(</span><span class="n">plural</span> <span class="o">=</span> <span class="s1">&#39;PLURAL&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span> <span class="o">=</span> <span class="no">NlgXmlRealiserBuilder</span><span class="o">::</span><span class="no">DSL</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">  <span class="n">dsl</span><span class="o">.</span><span class="n">builder</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">sp</span> <span class="ss">:child</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">subj</span> <span class="ss">:np</span><span class="p">,</span> <span class="s1">&#39;there&#39;</span><span class="p">,</span> <span class="ss">cat</span><span class="p">:</span> <span class="s1">&#39;ADVERB&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="n">verb</span> <span class="s1">&#39;be&#39;</span><span class="p">,</span> <span class="ss">PERSON</span><span class="p">:</span> <span class="s1">&#39;THIRD&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="n">compl</span> <span class="ss">:np</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;story&#39;</span><span class="o">]</span><span class="p">,</span> <span class="ss">NUMBER</span><span class="p">:</span> <span class="n">plural</span>  <span class="k">do</span>
</span></span><span class="line"><span class="cl">          <span class="n">preMod</span> <span class="ss">:cp</span><span class="p">,</span> <span class="ss">conj</span><span class="p">:</span> <span class="s1">&#39;and&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="n">coord</span> <span class="ss">:vp</span><span class="p">,</span> <span class="s1">&#39;deliver&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">          <span class="n">compl</span> <span class="ss">:sp</span><span class="p">,</span> <span class="ss">MODAL</span><span class="p">:</span> <span class="s1">&#39;may&#39;</span><span class="p">,</span> <span class="ss">PASSIVE</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="n">verb</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="ss">TENSE</span><span class="p">:</span> <span class="s1">&#39;PAST&#39;</span><span class="p">,</span> <span class="ss">NEGATED</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">          <span class="k">end</span>
</span></span><span class="line"><span class="cl">        <span class="k">end</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span><span class="o">.</span><span class="n">to_xml</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E posso rodar a versão singular assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>puts example(&#39;SINGULAR&#39;)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esta é a frase resultante:</p>
<blockquote>
  <p>&ldquo;There is a finished and delivered story that may not have been tested.&rdquo;</p>

</blockquote>
<p>Olha como ele mudou o verbo de &ldquo;are&rdquo; para &ldquo;is&rdquo; e o determinante do substantivo de &ldquo;some&rdquo; para &ldquo;a&rdquo; sozinho! E claro, este é um exemplo bobo. Agora imagine um artigo inteiro customizável, cheio de parágrafos e frases que eu posso variar dependendo de várias variáveis que tenho.</p>
<p>Enquanto eu estudava e escrevia essa DSL, peguei uma compreensão razoável da estrutura do SimpleNLG, mas se você tem mais exemplos para estruturas de frase mais complexas, deixa nos comentários aí embaixo.</p>
<p>A maior parte das specs foi copiada dos testes do XML Realiser do projeto Java original para garantir que estou cobrindo a maioria dos casos.</p>
<p>Vai ser interessante ver se essa DSL facilita a vida de mais gente que queira experimentar com NLG. Como sempre, mandem seus Pull Requests, ideias e sugestões nos meus repositórios públicos do GitHub:</p>
<ul>
<li><a href="https://github.com/Codeminer42/nlg_service"target="_blank" rel="noopener">nlg_service</a></li>
<li><a href="https://github.com/Codeminer42/nlg_xml_realiser_builder"target="_blank" rel="noopener">nlg_xml_realiser_builder</a></li>
</ul>
<p>E se você se interessa pelo assunto de NLP e NLG, encontrei <a href="https://github.com/diasks2/ruby-nlp"target="_blank" rel="noopener">esta lista</a> de projetos open source relacionados em Ruby também.</p>
]]></content:encoded><category>ruby</category><category>java</category><category>rails</category></item><item><title>IIS 8 finalmente ganha um módulo de Proxy-Reverso! E como executar Rails sobre JRuby no Windows!</title><link>https://akitaonrails.github.io/2015/02/16/iis-8-finalmente-ganha-um-modulo-de-proxy-reverso-e-como-executar-rails-sobre-jruby-no-windows/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/02/16/iis-8-finalmente-ganha-um-modulo-de-proxy-reverso-e-como-executar-rails-sobre-jruby-no-windows/</guid><pubDate>Mon, 16 Feb 2015 12:29:00 -0200</pubDate><description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: se está familiarizado com os problemas de executar Rails no Windows e já sabe o que é o HttpPlatformHandler, porque devemos usar JRuby no Windows, pule direto pra seção &lt;a href="#configuracao"&gt;Configurando Rails da forma Correta para Windows&lt;/a&gt; mais pra abaixo.&lt;/p&gt;
&lt;p&gt;No dia 4/2 a Microsoft &lt;a href="http://azure.microsoft.com/blog/2015/02/04/announcing-the-release-of-the-httpplatformhandler-module-for-iis-8/"target="_blank" rel="noopener"&gt;anunciou o módulo HttpPlatformHandler&lt;/a&gt;. Então, em 9/2, o conhecido blogueiro &lt;a href="http://www.hanselman.com/blog/AnnouncingRunningRubyOnRailsOnIIS8OrAnythingElseReallyWithTheNewHttpPlatformHandler.aspx"target="_blank" rel="noopener"&gt;Scott Hanselman fez um blog post&lt;/a&gt; explicando como poderíamos usar esse módulo para servir uma aplicação Rails atrás do IIS 8. Depois de um comentário que fiz ele atualizou para demonstrar como servir uma aplicação Rails em cima do JRuby.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>TL;DR</strong>: se está familiarizado com os problemas de executar Rails no Windows e já sabe o que é o HttpPlatformHandler, porque devemos usar JRuby no Windows, pule direto pra seção <a href="#configuracao">Configurando Rails da forma Correta para Windows</a> mais pra abaixo.</p>
<p>No dia 4/2 a Microsoft <a href="http://azure.microsoft.com/blog/2015/02/04/announcing-the-release-of-the-httpplatformhandler-module-for-iis-8/"target="_blank" rel="noopener">anunciou o módulo HttpPlatformHandler</a>. Então, em 9/2, o conhecido blogueiro <a href="http://www.hanselman.com/blog/AnnouncingRunningRubyOnRailsOnIIS8OrAnythingElseReallyWithTheNewHttpPlatformHandler.aspx"target="_blank" rel="noopener">Scott Hanselman fez um blog post</a> explicando como poderíamos usar esse módulo para servir uma aplicação Rails atrás do IIS 8. Depois de um comentário que fiz ele atualizou para demonstrar como servir uma aplicação Rails em cima do JRuby.</p>
<p>O HttpPlatformHandler é um módulo que há anos estava faltando no IIS, e não entendo a razão  de porque tanta demora. Todo servidor HTTP tinha um módulo desses por padrão (Apache, NGINX, etc), menos o IIS. E esse módulo é importante para poder repassar uma requisição HTTP do IIS para uma aplicação web que responde HTTP atrás dele (basicamente qualquer coisa que não é PHP, de Python/WSGI a Java). Antes disso era necessário usar um módulo desenvolvido por terceiros ou uma combinação de <a href="http://www.gitshah.com/2013/06/how-to-use-iis7-as-front-end-to-java.html"target="_blank" rel="noopener">ARR (Application Request Routing, que é um balanceador de carga) e URL Rewrite</a>, que é tudo menos algo &ldquo;plug-and-play&rdquo;.</p>
<p>Minha &ldquo;teoria da conspiração&rdquo; é que a Microsoft obviamente gostaria que o IIS fosse o único servidor de aplicação e qualquer coisa dinâmica deveria rodar dentro do controle de seus Application Pools, o que era verdade para ASP antigo e .NET. O resto ficaria relegado ao antigo (obsoleto) esquema de sub-processo por requisição de CGI/FastCGI (que é extremamente ineficiente).</p>
<p>Na verdade não precisamos do IIS se quisermos rodar uma aplicação Rails, Java ou qualquer outro no Windows: basta desabilitar o IIS (para não ocupar a porta 80) e fazer o JRuby on Rails/Puma ou Java/JBoss/Tomcat/etc subir na porta 80 e pronto. Por outro lado poderíamos querer executar uma aplicação ASP.NET MVC e outra em Java/JSF na mesma máquina, e aí começa a ficar mais complicado.</p>
<p>Um módulo de proxy-reverso é a solução nesses cenários: agora é possível executar aplicações em quaisquer linguagens na mesma máquina, todas coordenadas com o IIS 8, repassando a requisição quando ele mesmo não tiver como responder. Com a proposta do Azure de querer ser uma plataforma para muitas linguagens e projetos open source, esse componente era muito necessário para colocá-lo em pé de igualdade com NGINX e outros servidores web.</p>
<h2>Por que Rails (ou qualquer coisa diferente de .NET) no Windows?<span class="hx:absolute hx:-mt-20" id="por-que-rails-ou-qualquer-coisa-diferente-de-net-no-windows"></span>
    <a href="#por-que-rails-ou-qualquer-coisa-diferente-de-net-no-windows" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Na realidade é a mesma resposta de &ldquo;por que Java/Python/PHP/etc&rdquo; no Windows. Na prática, eu diria que se você precisar muito se manter na plataforma Windows - e existem dezenas de razões legítimas pra isso - mantenha-se na stack do .NET, use ASP.NET MVC (ou o vNext que é o próximo). Faça web services com WCF, faça aplicações desktop com WPF. Muitas soluções corporativas precisam integrar diversos componentes como BizTalk, Exchange, Sharepoint, conectar exclusivamente com endpoints SOAP ou COM+ e nesses casos o melhor é ficar no nativo.</p>
<p>Usar algo diferente de .NET significa não somente mudar de linguagem, mas mudar de sistema operacional e toda uma forma de trabalhar e desenvolver que são completamente diferentes. Linguagens de script como PHP, Ruby, Python, Perl dependem bastante do sistema operacional por baixo. Algumas se esforçaram para oferecer mais suporte no Windows, mas eles nunca vão se comportar 100% da mesma forma em dois sistemas operacionais diferentes.</p>
<p>O <a href="https://technet.microsoft.com/en-us/library/bb496993.aspx"target="_blank" rel="noopener">próprio Technet da Microsoft</a> tem vários artigos detalhando as diferenças (tanto técnicas quanto filosóficas) e se procurar no Google vai achar centenas de artigos (muitos meramente pedantes e trolls, evite-os) detalhando mais sobre essas diferenças, principalmente nos aspectos de <a href="http://www.kernelthread.com/publications/security/uw.html"target="_blank" rel="noopener">segurança</a>.</p>
<p>Extensões nativas precisam ser escritas levando em consideração APIs, chamadas de baixo nível de sistema muito diferentes. Windows e Linux/Unix são animais diferentes, gerenciam memória de formas diferentes, lidam com I/O (sistema de arquivos, rede) de formas diferentes. Daí é necessário programar uma &ldquo;camada intermediária&rdquo; que tenta abstrair as duas coisas. PHP é de longe o que tem mais &ldquo;wrappers&rdquo; prontos para ambos os sistemas, Python vem na sequência. Ruby não tem histórico de uso no Windows por isso tem menos wrappers.</p>
<p>Existem várias ferramentas do mundo Linux que um desenvolvedor no Windows não está acostumado a usar. Coisas que vão desde coisas simples como um simples wget ou curl até coisas mais complexas como GDB ou DTrace. Por isso mesmo não é simples para um programador Windows migrar para qualquer outra plataforma diferente de .NET.</p>
<p>Mesmo assim, pode ser muito útil saber o básico de algumas linguagens pois daí é possível tirar vantagens de instalar um Wordpress (PHP), ou um Plone (Python) e até mesmo no caso de Rails usar aplicações excelentes como Redmine, Discourse, Spree, FatFreeCRM, e várias outras aplicações de código aberto, sem precisa duplicar esforços e refazê-los em .NET. Ou então usar as excelentes ferramentas que temos para criar CRUDs rápidos usando Rails + Devise + ActiveAdmin por exemplo. Existem várias razões para tirar proveito das excelentes ferramentas do ecossistema Rails que não existem no mundo ASP.NET MVC.</p>
<p>Por essas razões, o Ruby no Windows nunca será tão bom quanto o Ruby no Linux/OS X, nem mesmo PHP ou Perl será tão bom no Windows quanto é no Linux, no mesmo hardware. Um exemplo prático mais notável: <a href="http://stackoverflow.com/questions/21732566/linux-fork-function-compared-to-windows-createprocess-what-gets-copied"target="_blank" rel="noopener">Windows não tem o conceito e nem a implementação de fork()</a>, algo essencial para nossos servidores de aplicação Ruby como Unicorn, Puma, Thin, etc. Por isso mesmo, rodar Rails usando o servidor padrão, Webrick, não é aceitável em produção. Ele vai ter um único processo e responder a apenas uma requisição de cada vez, sem possibilidade de responder conexões simultâneas.</p>
<p>Isso dito, no caso específico de Ruby, existe uma ótima solução e é <a href="http://jruby.org"target="_blank" rel="noopener">JRuby</a>, que permite executar código Ruby dentro da máquina virtual Java. Em resumo, uma aplicação inteira feita em Ruby on Rails, com pequenas modificações (por exemplo, instalando o driver JDBC pra acessar banco de dados), pode ser executado no ambiente Java, com todas as vantagens que ele oferece como melhor performance e capacidade para multithreading real.</p>
<p>O motivo disso é que Java roda sobre a Java Virtual Machine (JVM) que, como o próprio nome diz, é literalmente uma máquina virtual (de um jeito tosco, pense nele como um VirtualBox, com outro sistema operacional rodando virtualmente). A JVM abstrai completamente o sistema operacional por baixo e é como se fosse um micro-sistema operacional próprio. De fato, já houve a tentativa de se fazer um <a href="http://en.wikipedia.org/wiki/JavaOS"target="_blank" rel="noopener">Java OS</a> inteiro que não necessitaria de um outro sistema como Linux ou Windows pra executar.</p>
<p>Feito isso, podemos colocar uma aplicação Rails, com boa performance, com boa concorrência, integrado com banco de dados como SQL Server ou Oracle, atrás do IIS, rodando lado a lado com aplicações feitas em .NET.</p>
<p><a name="configuracao"></a></p>
<h2>Configurando Rails da forma Correta para Windows<span class="hx:absolute hx:-mt-20" id="configurando-rails-da-forma-correta-para-windows"></span>
    <a href="#configurando-rails-da-forma-correta-para-windows" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A partir daqui vou assumir que você é um desenvolvedor familiarizado com o ambiente Windows e sabe como usar <a href="http://www.microsoft.com/web/downloads/platform.aspx"target="_blank" rel="noopener">Web Platform Installer</a>, onde procurar instaladores, não estranha em usar o Command Prompt e sabe como instalar os seguinte componentes básicos:</p>
<ul>
<li>IIS 8</li>
<li>SQL Server 2008 R2</li>
<li>Java 1.8</li>
</ul>
<p>E antes de realmente começar precisamos configurar algumas coisas.</p>
<p>No caso de Java, também precisamos antes instalar o <a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html"target="_blank" rel="noopener">Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy</a> que é um tosco arquivo zip cujos arquivos precisam ser manualmente copiados no diretório de policies do JRE:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/481/Screen_Shot_2015-02-13_at_14.13.41.png" alt="JCE"  loading="lazy" /></p>
<p>Depois disso precisamos fazer o SQL Server se ligar à porta TCP 1433. Para isso instale e abra o SQL Server Configuration Manager, habilite o TCP/IP e na tela de propriedades apague o que estiver em &ldquo;TCP Dynamic Ports&rdquo; e coloque &ldquo;1433&rdquo; em TCP Port. Precisa fazer isso em todos os campos.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/482/Screen_Shot_2015-02-13_at_14.18.37.png" alt="SQL Server Configuration Manager"  loading="lazy" /></p>
<p>Agora, baixe <a href="https://github.com/akitaonrails/jruby_windows_demo"target="_blank" rel="noopener">meu código do Github</a> em alguma pasta. Se não for diretamente dentro do C:\inetpub\wwwroot precisa adicionar o usuário IIS_IUSRS para ter acesso a todos os subdiretórios:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/483/Screen_Shot_2015-02-13_at_14.16.34.png" alt="Permissões"  loading="lazy" /></p>
<p>A partir de um Command Prompt, entre no diretório do projeto e execute:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>jruby -S bundle install</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso deve instalar todas as dependências que estão listadas no arquivo <tt>Gemfile</tt> cujas partes mais importantes são:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># Bundle edge Rails instead: gem &#39;rails&#39;, github: &#39;rails/rails&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rails&#39;</span><span class="p">,</span> <span class="s1">&#39;4.1.9&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Use jdbcsqlite3 as the database for Active Record</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;jdbc-mssql-azure&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;activerecord-jdbc-adapter&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;activerecord-jdbcmssql-adapter&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;puma&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;jruby-openssl&#39;</span><span class="p">,</span> <span class="nb">require</span><span class="p">:</span> <span class="kp">false</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;tzinfo-data&#39;</span><span class="p">,</span> <span class="ss">platforms</span><span class="p">:</span> <span class="o">[</span><span class="ss">:mingw</span><span class="p">,</span> <span class="ss">:mswin</span><span class="p">,</span> <span class="ss">:x64_mingw</span><span class="p">,</span> <span class="ss">:jruby</span><span class="o">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>As partes importantes:</p>
<ul>
<li>Use Rails 4.1 e não 4.2 pois muitas gems ainda não estão totalmente compatíveis até o momento deste post.</li>
<li>Use <a href="https://github.com/MikeEmery/jdbc-mssql-azure"target="_blank" rel="noopener">drivers JDBC</a> pois estaremos rodando dentro da JVM, e para isso funcionar é necessário um <a href="https://github.com/jruby/activerecord-jdbc-adapter/tree/master/activerecord-jdbcmssql-adapter"target="_blank" rel="noopener">adapter de activerecord</a>.</li>
<li>Vamos usar <a href="https://github.com/puma/puma"target="_blank" rel="noopener">Puma</a> como servidor Web em vez do padrão Webrick, que é muito melhor por suportar multi-thread na JVM.</li>
<li>Precisamos adicionar o pacote <a href="https://github.com/jruby/jruby-openssl"target="_blank" rel="noopener">jruby-openssl</a> pois o Windows não tem suporte nativo a OpenSSL e também o <a href="https://github.com/tzinfo/tzinfo-data"target="_blank" rel="noopener">tzinfo-data</a> pois o Windows também não tem dados de time zones facilmente acessíveis (lembram quando falei das várias coisas diferentes entre sistemas operacionais, estes são exemplos de pacotes pra cobrir buracos desse tipo).</li>
</ul>
<p>Finalmente, configure uma nova aplicação no IIS dentro do Default Web Site, numa sub-pasta chamada &ldquo;rails&rdquo;:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/484/Screen_Shot_2015-02-13_at_14.16.13.png" alt="IIS"  loading="lazy" /></p>
<p>Uma aplicação Rails, por padrão, não é feito para funcionar numa sub-pasta, mas este trecho no arquivo <tt>config.ru</tt> garante que isso vai funcionar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">relative_url_root</span> <span class="o">=</span> <span class="s1">&#39;/rails&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">map</span> <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">relative_url_root</span> <span class="o">||</span> <span class="s2">&#34;/&#34;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">run</span> <span class="no">Rails</span><span class="o">.</span><span class="n">application</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Você vai precisar criar um banco de dados chamado &ldquo;jruby_demo&rdquo; ou outro nome que você pode configurar no arquivo <tt>config/database.yml</tt>. Note que você precisa modificar também o usuário e senha nesse arquivo para conseguir se conectar ao seu banco. Nesse caso significa que precisa usar <a href="https://msdn.microsoft.com/en-us/library/ms144284.aspx"target="_blank" rel="noopener">SQL Server Authentication</a> e não o padrão Windows Authentication.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="cp">&amp;default</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">adapter</span><span class="p">:</span><span class="w"> </span><span class="l">jdbcmssql</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">driver</span><span class="p">:</span><span class="w"> </span><span class="l">com.microsoft.sqlserver.jdbc.SQLServerDriver</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;jdbc:sqlserver://localhost;databaseName=jruby_demo&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l">sa</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="l">abcd1234</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se estiver configurado corretamente, agora podemos usar o processo de migrations do ActiveRecord para criar tabelas e subir dados de exemplo, executando o seguinte na linha de comando:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>jruby -S rake db:migrate db:seed</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Para o IIS 8 conseguir carregar corretamente o JRuby, você precisa configurar o arquivo <tt>Web.config</tt>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-XML" data-lang="XML"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;configuration&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;system.webServer&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;handlers&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">&#34;httpplatformhandler&#34;</span> <span class="na">path=</span><span class="s">&#34;*&#34;</span> <span class="na">verb=</span><span class="s">&#34;*&#34;</span> <span class="na">modules=</span><span class="s">&#34;httpPlatformHandler&#34;</span> <span class="na">resourceType=</span><span class="s">&#34;Unspecified&#34;</span> <span class="na">requireAccess=</span><span class="s">&#34;Script&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/handlers&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;httpPlatform</span> <span class="na">stdoutLogEnabled=</span><span class="s">&#34;true&#34;</span> <span class="na">stdoutLogFile=</span><span class="s">&#34;rails.log&#34;</span> <span class="na">startupTimeLimit=</span><span class="s">&#34;60&#34;</span> <span class="na">startupRetryCount=</span><span class="s">&#34;5&#34;</span> <span class="na">processPath=</span><span class="s">&#34;c:\jruby-1.7.19\bin\jruby.exe&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="na">arguments=</span><span class="s">&#34;-S puma --env production --dir C:\Users\Fabio\Projects\jruby_demo2 -p %HTTP_PLATFORM_PORT%&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;environmentVariables&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;environmentVariable</span> <span class="na">name=</span><span class="s">&#34;JAVA_HOME&#34;</span> <span class="na">value=</span><span class="s">&#34;C:\Program Files\Java\jre1.8.0_31&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&lt;environmentVariable</span> <span class="na">name=</span><span class="s">&#34;SECRET_KEY_BASE&#34;</span> <span class="na">value=</span><span class="s">&#34;4a8f4bb5de3637e9fab1f3c8fb6e3a787f60a811d6b36ff8d77a3371a31d19f7a93cfb48597d8263f46748c729b291a0277e6e819a869c4f8edf9445595e5548&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&lt;/environmentVariables&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;/httpPlatform&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/system.webServer&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/configuration&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Preste atenção aos diretórios no arquivo para refletirem onde estão essas coisas na sua máquina, sem isso estar correto, nada vai carregar.</p>
<p>Feito isso, você já deve conseguir carregar a URL &ldquo;http://localhost/rails&rdquo; num navegador. Como é JRuby a primeira requisição vai demorar alguns segundos pra carregar (até a JVM terminar de carregar). Mas depois disso vai ficar tudo rápido.</p>
<p>Uma coisa diferente entre o HttpPlatformHandler e um módulo normal de proxy-reverso é que além de fazer o papel de proxy reverso ele também controla o ciclo de vida da aplicação por trás, no caso o JRuby + Puma. E também controla em que porta a aplicação vai ficar escutando (pela variável de ambiente &ldquo;HTTP_PLATFORM_PORT&rdquo;).</p>
<p>Sobre aplicações Rails, não se esqueça que todos tem um &ldquo;SECRET_KEY_BASE&rdquo; diferente. Sempre gere um novo através da linha de comando <tt>jruby -S rake secret</tt>.</p>
<p>Se tudo foi feito corretamente, você deveria conseguir ver o seguinte no navegador:</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/485/Screen_Shot_2015-02-13_at_14.12.18.png" alt="JRuby Demo"  loading="lazy" /></p>
<p>A partir daqui você pode evoluir a aplicação, criar mais models, mais controller, adicionar frameworks CSS como Bourbon (pois o Asset Pipeline vai funcionar corretamente usando o <a href="https://github.com/mozilla/rhino"target="_blank" rel="noopener">Rhino</a> como runtime Javascript no lugar do V8).</p>
]]></content:encoded><category>rails</category><category>java</category><category>microsoft</category></item><item><title>Twitter muda de Ruby para Java. Ruby é 3x mais lento que Java.</title><link>https://akitaonrails.github.io/2011/04/16/twitter-muda-de-ruby-para-java-ruby-e-3x-mais-lento-que-java/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/16/twitter-muda-de-ruby-para-java-ruby-e-3x-mais-lento-que-java/</guid><pubDate>Sat, 16 Apr 2011 01:57:00 -0300</pubDate><description>&lt;p&gt;Estava esperando ter um tempinho para falar sobre isso. Se você presta atenção já deve ter visto posts de blog, tweets e tudo mais falando sobre um &lt;a href="http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html"target="_blank" rel="noopener"&gt;post recente&lt;/a&gt; do próprio Twitter explicando sobre a migração dos seus front-ends feitos em Ruby on Rails para uma solução que eles mesmo fizeram, chamada Blender, que é construída com Java. Com isso eles reduziram o tempo de requisição de 800ms para 250ms e conseguiram fazer suas máquinas terem 10 vezes mais capacidade.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Estava esperando ter um tempinho para falar sobre isso. Se você presta atenção já deve ter visto posts de blog, tweets e tudo mais falando sobre um <a href="http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html"target="_blank" rel="noopener">post recente</a> do próprio Twitter explicando sobre a migração dos seus front-ends feitos em Ruby on Rails para uma solução que eles mesmo fizeram, chamada Blender, que é construída com Java. Com isso eles reduziram o tempo de requisição de 800ms para 250ms e conseguiram fazer suas máquinas terem 10 vezes mais capacidade.</p>
<p>Este é o resumo que você vai ler em todas os canais de comunicação que noticiaram o ocorrido. E, claro, os mais atrevidos e sem noção não se inibiram de novamente dizer “Ruby é muito lento, por isso compensa usar Java mesmo”. Como faz algum tempo que não falo sobre o assunto, acho que vale a pena repetir. Sim, todos nós rubistas sabemos que Ruby é uma das linguagens mais lentas que existem em uso hoje. E nenhum de nós faz nenhum esforço para esconder esse fato. Isso não é novidade, nunca foi. E aí eu pergunto: <em>“e daí?”</em> E a resposta continua: <em>“oras, por isso mesmo não compensa usar Ruby e devemos todos continuar com Java, que é muitas vezes mais rápido, afinal se o Twitter disse é porque deve ser verdade.”</em></p>
<p>Como vocês me conhecem, sabem que eu vou desviar do assunto principal para ensinar alguns conceitos que todos já deveriam saber:</p>
<h2>Argumentações Falaciosas<span class="hx:absolute hx:-mt-20" id="argumentações-falaciosas"></span>
    <a href="#argumenta%c3%a7%c3%b5es-falaciosas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim, novamente textos escritos com conclusões falaciosas (não vou linkar nenhum dos artigos falaciosos que o pessoal tem twitado porque não quero lhes dar tráfego de graça, mas usem o Google e facilmente encontrarão dezenas). Primeiro o bom e velho <a href="http://www.nizkor.org/features/fallacies/hasty-generalization.html"target="_blank" rel="noopener">Hasty Generalization</a> ou “Generalização Apressada”. Ela acontece assim:</p>
<ul>
<li>Uma amostra S, que é muito pequena (às vezes apenas 1 caso), é tirada de uma população bem maior P;</li>
<li>Uma conclusão C é generalizada à população P baseada em S</li>
</ul>
<p>No nosso caso:</p>
<ul>
<li>O Twitter trocou de Ruby on Rails para Java;</li>
<li>Conclusão: Ruby é ruim e todos deveriam trocar para Java.</li>
</ul>
<p>Além disso todos os artigos que falam sobre este assunto cometem quase todos as falácias de <a href="http://en.wikipedia.org/wiki/List_of_cognitive_biases"target="_blank" rel="noopener">Cognitive Bias</a> do livro:</p>
<ul>
<li>Anchoring: a tendência humana comum de depender demais numa “âncora” ou pedaço de informação quando toma decisões. <em>“Esta linguagem é lenta, portanto ela é inútil”</em></li>
<li>Bandwagon effect: a tendência de fazer (ou acreditar) em coisas porque muitas outras pessoas fazem (ou acreditam) na mesma coisa. <em>“O Twitter trocou Ruby por Java, portanto todo mundo deveria.” ou “Todo mundo diz que Ruby é ruim, portanto deve ser.”</em></li>
<li>Confirmation Bias: a tendência de procurar por ou interpretar informação de maneira a confirmar seu preconceito. <em>“Eu acho que Ruby deve ser ruim. O Twitter trocou Ruby. Aha, portanto estou certo, Ruby é ruim.”</em></li>
<li>Negative Bias: a tendência de prestar mais atenção ou dar maior peso a experiências negativas do que positivas. <em>“O Twitter trocou Ruby, portanto Ruby é ruim. O Groupon e centenas de outras startups usam Ruby, mas isso não quer dizer quase nada.”</em></li>
<li>Status quo Bias: a tendência de gostar que as coisas se mantenham relativamente as mesmas. <em>“Todo mundo sempre usou Java, pra que tentar outra coisa?”</em></li>
</ul>
<p>Tem mais, mas vou parar por aqui porque já deu para demonstrar meu ponto.</p>
<h2>Cum hoc ergo propter hoc e Nirvana<span class="hx:absolute hx:-mt-20" id="cum-hoc-ergo-propter-hoc-e-nirvana"></span>
    <a href="#cum-hoc-ergo-propter-hoc-e-nirvana" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Meus dois favoritos tipos de falácias são: <a href="http://en.wikipedia.org/wiki/Correlation_does_not_imply_causation"target="_blank" rel="noopener">Correlação não implica causa</a> (Cum hoc ergo propter) e <a href="http://en.wikipedia.org/wiki/Perfect_solution_fallacy"target="_blank" rel="noopener">Falácia da Solução Perfeita ou Nirvana</a>.</p>
<p>O princípio é que existe algum tipo de Cognitive Bias – como mostrei antes – que gera um preconceito <em>“Ruby tem que ser ruim.”</em></p>
<p>Quem procura sempre acha, já dizia o ditado. E de fato, todos sempre encontrarão correlações, neste caso <em>“O Twitter trocou de Ruby para Java. O Ruby é lento. Portanto é melhor sempre usar Java e nunca usar Ruby. Portanto Ruby é ruim”</em> – ou algo similar.</p>
<p>O aspecto “performance” é sempre usado de maneira acima do peso que merecia (Negative Bias) para justificar que o Ruby inteiro deve ser ruim. O aspecto Twitter ou qualquer outro que teve problemas com Ruby serve de justificativa para demonstrar que Ruby é ruim (Hasty Generalization Fallacy).</p>
<p>E finalmente, a crença de que <em>“existe solução perfeita para hoje e que vai aguentar até o futuro sem problemas.”</em> (Perfect Solution Fallacy).</p>
<p>Pois bem, não existe.</p>
<h2>A Realidade<span class="hx:absolute hx:-mt-20" id="a-realidade"></span>
    <a href="#a-realidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de mais nada, vale dizer que o <a href="http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html"target="_blank" rel="noopener">artigo original no blog do Twitter</a> – não as republicações – é muito boa, concordo com ela e recomendo que todos leiam.</p>
<p>O título diz: “Pesquisas no Twitter agora são 3x mais rápidas”. E isso é um fato. Ela não diz: <em>“Twitter determina que Ruby é ruim, troca para Java e fica 3x mais lento.”</em> Essa conclusão nos artigos que republicaram o original são apenas provocações sensacionalistas.</p>
<p>Agora, trechos do artigo traduzido em português:</p>
<blockquote>
  <p>Para conseguir entender os ganhos de performance, você deve primeiro entender as ineficiências dos nossos servidores de front-end anteriores, que eram em Ruby on Rails (…) Nós sabemos há muito tempo que o <strong>modelo síncrono</strong> de responder requisições de forma usam nossos CPUs de forma ineficiente. Com o tempo, nós também acabamos acumulando um <strong>débito técnico</strong> significativo no nosso código Ruby, tornando muito difícil adicionar novas funcionalidades e melhorar a confiabilidade do nosso engine de pesquisa. Blender [a nova solução feita com tecnologias Java] endereçam esses problemas: criando um serviço de agregação totalmente <strong>assíncrono</strong> (…)</p>

</blockquote>
<p>O que o artigo explica é como a <strong>mudança de arquitetura</strong> foi de grande benefício e como o <strong>débito técnico que eles acumularam</strong> facilitou a decisão de jogar o legado em Ruby fora e começar do zero. O resto do artigo explica como o Blender funciona, como eles usaram estruturas de DAGs (<a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"target="_blank" rel="noopener">directed acyclic graphs</a>) para facilitar e otimizar o fluxo de trabalho entre os diferentes serviços dependentes. Como eles também criaram um novo proxy multiplexador de requisições de entrada (ainda não vi ninguém concluindo “O Twitter trocou seus proxies X por código deles mesmo. Portanto X é ruim.”). Finalmente eles descrevem as mudanças no roteamento de requisições no back-end entre os serviços dependentes.</p>
<p>Eu criticaria o fato deles estarem reescrevendo do zero tantos componentes de infraestrutura em vez de usar tecnologias que já existem, em particular o sistema de workflow e de fila, os proxies, etc. Porém, eu não concluiria que isso é errado. O caso do Twitter é uma exceção, não a regra. E a única forma de determinar o que o caso do Twitter necessita é estando no dia-a-dia de operações e desenvolvimento dentro do Twitter. Eu nunca estive por lá, portanto não posso concluir nada.</p>
<p>Mas repita comigo: <em>“eu não sou o Twitter, eu não sou o Twitter, eu não sou o Twitter.”</em> E sinceramente, você dificilmente um dia chegará a uma fração do que é o Twitter. Não é impossível, afinal existe 1 caso de Twitter.</p>
<p>Para ilustrar, veja este gráfico de CPU semanal do Munin de um aplicativo que minha equipe desenvolveu:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/16/weekly-CPU_original.png?1302928669" alt=""  loading="lazy" /></p>
<p>Note uma coisa: a maior parte do gráfico é “idle”. Ou seja, a maior parte do tempo este hardware está apenas esperando, sem fazer nenhum processamento. Se esta aplicação fosse, sei lá, 20 vezes mais lento, ainda assim estaria sobrando algum processamento. Pense bem: minha máquina não está sequer saturada. Será que ficar 3x mais rápido vai trazer algum benefício? Acho muito difícil. Porém, se minha equipe fosse 3 vezes menos produtiva, o prazo para entrega desta aplicação simplesmente não teria sido possível para nosso cliente.</p>
<p>Agora, no caso do Twitter, se o gráfico das centenas de máquinas que eles tem fossem parecidas com este, seria um enorme problema. Pense 100 máquinas onde 90% do tempo ele não está fazendo nada. Significa que daria para trocar as 100 máquinas por apenas 1 ou 2 onde menos de 10% do tempo ele não estaria fazendo nada. Ou seja, estaria saturado a maior parte do tempo.</p>
<p>Só que aqui vem outra das cognitive bias: de que performance é a única variável de impacto na solução e de que todos deveriam estar preparados para um dia ter a escala do Twitter. Agora prestem atenção:</p>
<blockquote>
  <p><strong>Performance</strong> NÃO é a única variável de um problema!</p>

</blockquote>
<p>Ruby on Rails sempre se vendeu nos seguintes fatores:</p>
<ul>
<li>Usar Ruby que é uma das linguagens mais elegantes e prazerosas de trabalhar (embora gosto é algo que não se discute, e tem gente que acha ler assembler algo bonito)</li>
<li>Ruby on Rails ajuda a aumentar a produtividade (considerando que com boas ferramentas e técnicas adequadas, certos casos de uso, a produtividade poderia aumentar em 5 vezes ou mais) – a premissa aqui é que para a maioria dos projetos (onde a exceção são casos como Twitter, Google) o custo da improdutividade normalmente seria muito mais caro do que meramente alugar mais máquinas. Não é verdade que Ruby on Rails sempre compensará, mas é real que em muitos casos isso é verdade.</li>
<li>Ruby on Rails faz diversos “trade-offs” que fazem sentido para muitos projetos: de que perder performance para ganhar me produtividade + mantenabilidade + prazer da equipe é uma troca mais do que justa.</li>
<li>(e para hoje em dia) o Ecossistema cresceu exponencialmente e hoje existem ferramentas incríveis para diversos aspectos do ciclo de desenvolvimento. Especialmente na área de testes com coisas como Capybara, RSpec, Riot, Cucumber, Steak, Akephalos, Factory Girl e muito, muito mais.</li>
</ul>
<p>Encare a realidade: a grande maioria dos desenvolvedores sequer sabe a diferença entre requisições síncronas e assíncronas, sequer sabem o que é um sistema de filas, sequer sabem o que é um Munin! (que gera informações como o histórico de uso do CPU pelo tempo como na figura anterior).</p>
<p>Inclusive, aprenda a aprender: Ruby on Rails não é a única tecnologia existente no ecossistema Ruby. Está precisando de mais throughput, precisa mudar do modelo síncrono para assíncrono? Existem várias opções, uma delas é o <a href="http://www.igvita.com/2011/03/08/goliath-non-blocking-ruby-19-web-server/"target="_blank" rel="noopener">Goliath</a> do Ilya Grigorik e utilizado há tempos em produção pelo <a href="http://www.postrank.com/"target="_blank" rel="noopener">PostRank.com</a>.</p>
<h2>Performance é sempre mais importante<span class="hx:absolute hx:-mt-20" id="performance-é-sempre-mais-importante"></span>
    <a href="#performance-%c3%a9-sempre-mais-importante" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se nenhum dos argumentos anteriores fez sentido para você, aqui vai uma última. Se para você, performance bruta é o único fator de decisão de uma linguagem + plataforma + ecossistema, Não use Ruby, não use Python, sequer use .NET ou Java.</p>
<blockquote>
  <p>Vá direto para C!!</p>

</blockquote>
<p>Este é um exemplo usando o framework web para C chamado <a href="https://github.com/DanielWaterworth/raphters"target="_blank" rel="noopener">Raphters</a>. E este é um exemplo dele para um micro código à la “hello world”</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;raphters.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">START_HANDLER</span> <span class="p">(</span><span class="n">simple</span><span class="p">,</span> <span class="n">GET</span><span class="p">,</span> <span class="s">&#34;simple&#34;</span><span class="p">,</span> <span class="n">res</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">matches</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">response_add_header</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="s">&#34;content-type&#34;</span><span class="p">,</span> <span class="s">&#34;text/html&#34;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">response_write</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="s">&#34;hello world&#34;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">END_HANDLER</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">START_HANDLER</span> <span class="p">(</span><span class="n">default_handler</span><span class="p">,</span> <span class="n">GET</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="n">res</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">matches</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">response_add_header</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="s">&#34;content-type&#34;</span><span class="p">,</span> <span class="s">&#34;text/html&#34;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">response_write</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="s">&#34;default page&#34;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">END_HANDLER</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">add_handler</span><span class="p">(</span><span class="n">simple</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">add_handler</span><span class="p">(</span><span class="n">default_handler</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="nf">serve_forever</span><span class="p">();</span>  
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Consigo enxergar esse framework sendo usado em algum serviço web muito específico e muito pequeno que é muito crítico, o suficiente para ir para C.</p>
<p>Agora, quero ver quem é o “performance-macho” suficiente (ou se fosse Tropa de Elite 2, quem é o “pica-das-galáxias”) para escrever algo da complexidade dos front-ends do Twitter totalmente usando C ou C++ com perda mínima de produtividade e aumento de custo de desenvolvimento e manutenção por um longo período de tempo (pelo menos 3 anos). Se não for capaz, pra que diabos você está perturbando com conclusões falaciosas?</p>
<p>E sabe por que você usa Java e não C ou C++? Não é por performance, foi por produtividade! Porque escrever sistemas é coisa para C. Mas escrever aplicações funcionais é mais produtivo com Java. E nós estamos dizendo que para um certo nicho de aplicações web, é bem mais produtivo fazer em PHP, Ruby, Python. Esses são os argumentos corretos.</p>
<p>PS: e sim, esta última parte foi uma <a href="http://pt.wikipedia.org/wiki/Troll_%28internet%29"target="_blank" rel="noopener">#trollagem</a></p>
]]></content:encoded><category>arquitetura-de-software</category><category>rails</category><category>java</category></item></channel></rss>