A ThoughtWorks, minha contratante, é primariamente uma empresa de entrega de software. Nós construímos softwares para pessoas, incluindo produtos construídos para nós mesmos. Uma parte importante de nossa filosofia é abertura para usar diferentes plataformas de desenvolvimento, de forma que podemos escolher a plataforma apropriada para nossos diferentes clientes. Quando me juntei à ThoughtWorks em 2000, Java era nossa plataforma mais usada. Logo depois começamos a trabalhar com .NET e essas duas plataformas dominaram nosso trabalho pelo meio da década.
Algumas pessoas, entretanto, começaram com linguagens de script LAMP, em particular Ruby. A aparição do framework web Ruby on Rails deu um grande empurrão ao Ruby, o suficiente para que em 2006, começássemos a fazer alguns projetos sérios com a essa plataforma. Enquanto escrevo isto em 2009, a plataforma Ruby tem uma grande parcela de nosso trabalho, não tanto quanto Java e C#, mas uma porção significante.
Durante esses três anos aprendemos muito sobre Ruby na prática. Quando 2009 começou, eu fui convidado para falar sobre nossas experiências com Ruby para a conferência QCon. Me preparando para isso eu conduzi uma extensiva pesquisa de nossos projetos Ruby e questionei nosso líderes Ruby por seus pensamentos e experiências. Levou mais tempo do que gostaria para produzir este artigo também, mas aqui está ele.
Dividi este artigo em 3 partes. Para começar olharei para o perfil de experiência de nossos projetos Ruby, para dar uma sensação de quais tipos de projetos estivemos tocando nesses últimos anos. Em seguida vou para várias questões comuns sobre Ruby e como nossas experiências respondem a elas. Finalmente vou para algumas lições que aprendemos por usar Ruby.
A Forma de Nossos Projetos
De 2006 a 2008, a ThoughtWorks se envolveu em cerca de 41 projetos de Ruby. Eu defino um projeto de Ruby como um projeto onde Ruby foi a principal linguagem de desenvolvimento. Ruby apareceu em outros projetos também, existem muitos desenvolvimentos recentes usando ruby para automações ou testes funcionais para projetos de Java. Quase todos esses projetos envolveram Rails, e a maioria são projetos de web sites onde Rails é pelo menos tão importante quanto Ruby.
Figura 1: Gráfico de Dispersão de picos de contagem de pessoas vs. tamanho envolvido por projetos Ruby da ThoughtWorks de 2006 a 2008.
A Figura 1 dá uma sensação do tamanho dos projetos que estivemos envolvidos. A contagem de pessoas é o pico de todos os envolvidos (ThoughtWorks, clientes e outros; desenvolvedores, gerentes de projetos, analistas, etc.) O tamanho é a duração que estivemos envolvidos no projeto.
Projetos Ruby são geralmente vistos como mais curtos e menores do que outros projetos. Infelizmente não tenho dados comparativos com outros de nossos projetos em outras plataformas para ter uma sensação melhor se isso é verdade ou não. Certamente podemos ver que a maioria desses projetos envolve menos de 20 pessoas por menos de um ano.
Existem alguns projetos fora da curva. De longe nosso maior projeto é o que vou me referir como projeto Atlanta, com uma contagem de pessoas acima de 40. Outro grande e ainda corrente é o Jersey. Esses dois estão relacionados no sentido que houve muita rotação de pessoas entre eles, algumas de nossas mais experientes pessoas de Ruby estiveram em ambos.
O terceiro projeto é o Mingle, que é um caso particularmente interessante já que é um produto da ThoughtWorks Studios – e como tal podemos ser mais públicos sobre ele do que outros que fizemos para clientes. É um projeto longo e corrente e também internacional: começando na Austrália, movendo para Beijing e agora multi-site entre Beijing e São Francisco.
Figura 2: Gráfico de Tiras mostrando esforço por projeto a cada ano.
A Figura 2 olha para a forma do gráfico de maneira diferente, olhando para o esforço em vários projetos que estivemos envolvidos a cada ano. Cada ponto no gráfico representa o esforço total (todas as pessoas) em um projeto durante esse ano. Esse gráfico fornece uma boa sensação de quanto crescimento vemos em projetos Ruby durante os últimos três anos.
Figura 3: Gráfico de Tiras mostrando esforço de projetos por país.
A Figura 3 mostra projetos por país onde foram feitos. Não é muito exato já que não tentei lidar com alguns projetos multi-site que se moveram (Mingle, por exemplo, eu classifiquei como China embora sua história tenha variado.)
A divisão por país mostra que os Estados Unidos viram o maior interesse por trabalhos em Ruby. A Índia também viu uma boa quantidade – de fato nosso primeiro projeto de Ruby foi em Bangalore. A Inglaterra foi onde teve a menor quantidade. Isso provavelmente reflete o fato que nossos evangelistas de Ruby era na maioria baseados nos Estados Unidos e existiu ceticismo considerável sobre Ruby na Inglaterra. O nível de envolvimento da Índia é encorajador, tradicionalmente a Índia é vista como sendo atrasada no uso de novas tecnologias mas estamos conseguindo fazer um trabalho razoável de tornar nossos escritórios na Índia bem diferentes.
Nossa experiência vendendo trabalho de Ruby é que usar linguagens dinâmicas como Ruby se encaixa bem com nossa imagem geral. Nossa força é que contratamos pessoas talentosas que são difíceis de serem atraídos por organizações típicas de TI. Ruby tem filosofia de um ambiente que dá a um desenvolvedor talentoso mais vantagem, do que tentar proteger os desenvolvedores menos talentosos dos seus erros. Um ambiente como Ruby, portanto, dá aos nossos desenvolvedores mais habilidade para produzir seu verdadeiro valor.
Ruby também se encaixa com nossa preferência por processos ágeis de desenvolvimento de software. A filosofia ágil é sobre feedback rápido construindo software e revisando regularmente com o cliente. Quanto mais produtivo for um ambiente de desenvolvimento, mais freqüentemente podemos revisar o progresso e melhor o processo ágil de “inspecionar e adaptar” funciona.
Questões Sobre Ruby
Ruby foi a escolha correta?
Olhando para trás em nossos 41 projetos, talvez a questão mais importante para perguntar é se a plataforma Ruby foi a escolha correta. Uma forma de responder é perguntar aos líderes técnicos do projeto se, em retrospectiva, eles acham que foi a escolha correta.
Figura 4: Ruby foi a escolha correta de plataforma para esse projeto?
Como a Figura 4 indica, o voto foi muito positivo com 36 contra 5 suportando a escolha. Como um grupo, nossos líderes técnicos normalmente não são tímidos em indicar se estão insatisfeitos com a escolha tecnológica. Então eu vejo isso como uma afirmação firme da viabilidade da plataforma Ruby como uma escolha razoável.
Eu me aprofundei mais nos cincos projetos arrependidos. A primeira coisa que se sobressaiu foi que em quatro dos cinco casos, os líderes sentiram que usar Ruby não foi uma escolha mais ruim do que as alternativas. Por Ruby não ser uma coisa comum significa que sentimos que usar Ruby tem que vir com mais benefícios que as alternativas. Quatro dos cinco também relataram problemas por causa de integração com tecnologias .NET, por exemplo. Outro tema que dois dos projetos relataram foram problemas sociais – as pessoas na organização dos clientes se opuseram a Ruby ou outras linguagens dinâmicas. O projeto na pior situação mostrou esse problema social – uma organização de TI que resistiu com unhas e dentes ao Ruby (o patrocinador de negócios nesse caso foi um fã de Ruby.)
De fato quanto mais eu perguntava sobre as bandeiras vermelhas por usar Ruby em um projeto de software, a única resposta clara foi a respeito de problemas sociais. Ruby era de forma geral aceita ou encorajada por nosso trabalho de desenvolvimento de software, mas o maior sinal para evitá-la seria uma resistência social da parte do cliente.
Ruby é mais produtivo?
Quando as pessoas perguntam porque Ruby deveria ser usado em um projeto, a resposta mais comum é que ele aumenta a produtividade. Um indicador inicial foi a afirmação de um projeto que sugeria que Ruby deu uma melhoria de uma ordem de magnitude na produtividade.
Como um resultado parecia óbvio perguntar aos líderes técnicos dos projetos sobre a produtividade – o ruby aumentou a produtividade e se sim, por quanto. Eu pedi que comparassem com projetos feitos em Java ou .NET da maneira mais produtiva que eles sabiam como.
Figura 5: Quanto Ruby melhorou a produtividade para este projeto? (Comparado com a melhor ferramenta mainstream que você conhece.)
Não leve esses resultados ao pé da letra. Afinal não existe maneira objetiva de medir produtividade de software. Esses são resultados subjetivos e qualitativos dos líderes técnicos de cada projeto (eu não consegui respostas para todos os projetos.) Entretanto eles ainda sugerem que existiu uma real melhoria de produtividade acontecendo.
A sugestão é mais reforçada considerando os envolvidos. Scott Conley, que gerencia nosso escritório de Atlanta, relata que uma vez que um projeto Ruby começa a andar, ele espera precisar de 50% mais pessoas focadas em preparação de requerimentos do que o esperado em outras tecnologias.
Uma coisa que vimos é que você não deve esperar melhorias de produtividade aparecer imediatamente. Eu ouvi diversas vezes que as pessoas ficavam alarmadas nas semanas iniciais sobre o progresso devagar de novas equipes de projetos Ruby – uma conseqüência do que chamamos de Ravina de Melhoria. Realmente leva tempo para uma equipe Ruby se inteirar sobre como a plataforma funciona e durante esse tempo eles serão mais devagar do que o esperado.
A ravina de melhoria é um fenômeno comum e um paliativo comum é garantir que existem algumas pessoas experientes na equipe. Nossa história, entretanto, é que a experiência mais importante aqui é com linguagens dinâmicas que suportam os tipos de meta-programação que o Ruby suporta, mais do que especificamente experiência com Ruby. Como o Scott Conley coloca: a diferença é entre risco de eficiência e risco de entrega. Uma equipe com experiência em linguagens dinâmicas mas pouca experiência com Ruby será mais devagar inicialmente (risco de eficiência) mas uma equipe sem qualquer experiência com linguagens dinâmicas podem produzir código ruim que poderia arriscar a entrega no geral.
Ruby é lento?
Em uma palavra, “sim”. Procure por aí por benchmarks na internet e verá numerosas pesquisas que mostram que, mesmo pelos padrões de linguagens de script, Ruby é uma tartaruga.
No geral, entretanto, isso tem sido irrelevante para nós. A maioria do nosso uso de Ruby é construindo websites ligados a bancos de dados. Eu visitei muitos projetos durante muitos anos, usando ruby e outras tecnologias, quase todo projeto gasta tempo trabalhando em problemas de performance e em quase todos os casos esses problemas eram no acesso a banco de dados. As pessoas gastam tempo tunando SQL e não tunando o código de processamento. Então, já que quase toda aplicação é limitada por I/O, o uso de linguagens mais lentas para processamento não trás um impacto tão importante à performance geral do sistema.
Vocês vão notar que eu usei o comum palavreado absoluto no parágrafo anterior. Embora quase todo projeto seja limitado por I/O, você ainda cai em exceções ocasionais – e um interessante é o Mingle. O Mingle é incomum em muitas maneiras. Sua forma de mostrar telas de forma dinâmica significa que ele não pode usar nenhum tipo de caching de página para melhorar performance, o que imediatamente a torna diferente da maioria das aplicações web. Como resultado ele não é limitado por I/O e para melhor performance precisa de mais hardware do que a maioria das pessoas espera (um box de quatro cores com 2Gb de memória para suportar equipes de 20-40 pessoas.)
Mas a equipe do Mingle ainda sente que fizeram a escolha correta com Ruby. Eles construíram muitas funcionalidades rapidamente e sentem que o ganho de produtividade que tiveram com o Ruby vale o custo de mais demanda de hardware no produto final. Como com muitas coisas, esta é uma troca de hardware vs. produtividade – uma das mais velhas trocas na computação. Cada equipe precisa pensar sobre qual importa mais. A boa notícia aqui é que o Mingle tem ótima escalabilidade horizontal (jogue mais processadores nele e terá proporcionalmente melhor performance). Escalabilidade de hardware é normalmente a coisa mais valiosa que você pode ter nessas situações enquanto o custo de hardware decresce.
Eu devo re-enfatizar. Para a maioria dos projetos a velocidade do Ruby tem sido irrelevante já que quase todos eles são limitados por I/O. Mingle é uma exceção, não o caso comum.
Um código de Ruby é difícil de entender?
Uma preocupação que freqüentemente ouvimos sobre Ruby é que sua tipagem dinâmica, suporte a meta-programação e a falta de ferramentas coloquem um risco de deixar um código difícil de seguir. Em geral isso não tem se tornado um problema na prática para nós. A história que eu ouço é que o fato de poder escrever muito menos código para a mesma funcionalidade significa que é mais fácil manter o código limpo do que é para a maioria das linguagens mais populares.
Isso dito, é importante lembrar do nosso contexto. Os desenvolvedores da ThoughtWorks tendem a ser muito acima da média em termos de habilidade e também altamente disciplinados em técnicas como Extreme Programming. Colocamos alto valor em testes (algo que é verdade na comunidade Ruby em geral) e esses testes ajudam muito a manter o código limpo. Então não posso dizer se nossa experiência é comparável a outros desenvolvedores menos disciplinados. (Mesmo as ferramentas e relativo controle de outras linguagens não nos impedem de ver código bem horrível, então é uma questão em aberto se um código ruim de Ruby seria tão mais ruim.)
Temos visto uma seqüência comum de atitudes sobre meta-programação.
Figura 6: Progressão de sentimentos sobre meta-programação.
- Assustador e Ruim: as pessoas são prudentes quanto a meta-programação e não a usam muito.
- Assustador e Bom: as pessoas começam a ver valor na meta-programação mas ainda não se sentem confortáveis usando.
- Fácil e Bom: as pessoas ficam confortáveis e começam a usar demais, o que pode complicar o código.
- Fácil e Ruim: as pessoas são prudentes com meta-programação e entendem que é muito útil em pequenas doses.
No fim, a analogia que gosto mais para esse tipo de técnica é que eles são como receitas de remédios. Muito valiosos em pequenas quantidades mas você precisa se certificar de não cair numa overdose.
Assim como muitas outras coisas, experiência é a maior ajuda aqui, podendo levá-lo por essa curva mais rápido. Em particular é importante esperar essa curva de adoção, particularmente a utilização excessiva. Quando se aprende alguma coisa nova é normal usar demais em algum estágio porque sem cruzar essa linha é difícil saber onde fica a linha. Também pode ser útil tentar construir um sandbox – uma área relativamente contida de código para as pessoas testarem meta-programação. Com um sandbox é mais fácil desfazer o uso excessivo depois.
Ruby é uma plataforma viável?
Todas essas questões se somam na pergunta chave para nós: Ruby (e Rails) é uma plataforma viável para nós e nossos clientes? A resposta até agora é um grande “sim”. Ele oferece ganhos palpáveis em produtividade, nos permitindo ser mais responsivos e produzir melhor software, mais rapidamente para nossos clientes. Isso não significa que é a escolha certa para todas as situações. Escolher uma plataforma de desenvolvimento nunca é uma escolha simples, particularmente porque normalmente é mais uma coisa social do que técnica. Mas a conclusão é que Ruby é uma escolha que vale a pena considerar, o suficiente para nós querermos manter essa ferramenta em nossa caixa de ferramentas.
Uma outra questão interessante aqui é o papel de outras linguagens menos comuns. Deveríamos usar Groovy, F#, Python, Smalltalk e outros? Eu não ficaria surpreso se muitas das mesmas trocas que vimos com Ruby forem também verdade para qualquer dessas linguagens. Espero ver algumas dessas em nossa caixa de ferramentas no futuro.
Também devo estressar que não é um caso de “e/ou” quando falamos em usar essas linguagens e outras mais populares como Java ou C#. Eu sempre defendi que equipes de desenvolvimento usando uma linguagem como Java/C# deveriam também usar linguagens de script para outras tarefas de suporte. Ruby é uma excelente escolha para isso, e estamos vendo essa combinação crescer em nossos projetos. Com o crescimento do suporte dessas linguagens na JVM e CLR, vemos mais oportunidades de misturar diferentes linguagens com diferentes pontos fortes – uma coisa que Neal Ford refere como Programação Poliglota.
Algumas Dicas de Desenvolvimento
Nessa última seção, vou passar por algumas lições que aprendemos usando Ruby.
Testando com Active Record
Logo no começo de nosso uso de Ruby, houve um debate de qual era a melhor organização de testes na presença da camada Active Record de banco de dados em Rails. O problema básico é que na maioria do tempo, a performance de aplicações enterprise é dominada por acesso a banco de dados. Descobrimos que usando Dublê de Testes podemos aumentar muito a velocidade dos testes. Ter testes rápidos é crucial para nosso processo de desenvolvimento que é intensivo em testes. Kent Beck recomenda uma construção básica de commit de menos de dez minutos. A maioria de nossos projetos conseguem isso hoje em dia, e usar um dublê de banco de dados é parte vital para conseguir isso.
O problema com Active Record é que ao combinar o acesso a código de banco de dados com lógica de negócios, é meio difícil criar um dublê de banco de dados. A reação da equipe do Mingle a isso foi aceitar que o Rails se liga ao banco de dados de forma apertada e portanto rodar todos os testes de commit contra um banco de dados real.
A visão contrária foi defendida de forma mais firme pelas equipes do Atlanta e Jersey. Ruby tem uma funcionalidade poderosa que permite redefinir métodos em tempo de execução. Você pode usar isso para pegar uma classe active record e redefinir os métodos de acesso a banco de dados como stubs. A equipe iniciou uma gem chamada unitrecord para ajudar nisso.
Nesses três anos, não vimos um vitorioso aceito nesse debate. A equipe do Mingle roda milhares de testes contra um banco de dados postgresql real em cerca de 8 minutos. (Eles paralelizam os testes para se beneficiarem de múltiplos cores.) As equipes de Atlanta e Jersey consideram valioso que seus testes de commit rodem em 2 minutos com stubs em vez de 8 minutos sem. A troca de simplicidade de acesso direto ao banco de dados vs. construções de commit mais rápidos com testes stubados.
Embora ambas as equipes estejam felizes no geral com suas posições nesse debate, o uso de stubbing levou a outro problema para as equipes de Atlanta/Jersey. À medida que elas se familiarizam com o método de stubbing, usam mais e mais – caindo no inevitável problema de usar demais, onde testes unitários fazem stub de todos os métodos menos o que está sendo testado. O problema aqui, como acontece normalmente no uso de dublês, são testes frágeis. À medida que você muda o comportamento da aplicação, também precisa mudar montes de dublês que estão imitando o comportamento antigo. Esse uso excessivo levou ambas as equipes a saírem de testes unitários stubados e a usar mais testes funcionais no estilo do Rails, com acesso direto ao banco.
Active Record Vaza
Uma situação comum que as pessoas relatam é tempo gasto mexendo com SQL. Active Record faz um bom trabalho de esconder muito do acesso ao banco de dados do programador, mas ele falha em esconder tudo – essencialmente, a abstração vaza. Como um resultado as pessoas gastam uma quantidade razoável de tempo trabalhando diretamente com SQL.
Esse vazamento é uma funcionalidade comum em frameworks de mapeamento objeto/relacional. Praticamente todas as vezes que converso com as pessoas em projetos, eles dizem que o framework de mapeamento O/R esconde SQL eficientemente cerca de 80-90% do tempo, mas você precisa gastar algum tempo trabalhando com SQL de forma a conseguir performance decente. Então sobre esse respeito o Active Record não é realmente diferente de outros mapeadores O/R.
De fato um comentário que ouço é que com Active Record, a abstração quebra de forma mais limpa. Quando conversei com o DHH, ele sempre estressou que acredita que desenvolvedores que usam um banco de dados relacional devem saber trabalhar com SQL. Active Record simplifica os casos comuns, mas uma vez que você começa a chegar em cenários mais complicados ele espera que você use SQL diretamente.
Eu não vejo o vazamento de abstrações O/R como uma condenação a esses frameworks. O objetivo deles é melhorar a produtividade tornando mais fácil fazer as coisas comuns. Eles permitem a uma equipe focar seus esforços nos poucos casos que realmente interessam. O problema somente aparece quando uma equipe acredita que a abstração é perfeita, e não coloca nenhum esforço em trabalhar com SQL. É uma falha comum, mas não é uma razão para abandonar as reais vantagens de frameworks O/R quando usados corretamente.
Requisições Demoradas
Um problema comum que vimos são aplicações que caem em levar tarefas que demoram para terminar. Feitas de forma ingênua, isso pode resultar no controlador das requisições web de caírem no escuro por um longo e preocupante tempo enquanto lida com a requisição.
Isso é um problema muito comum com qualquer interface humana, e tem uma solução comum – jogar a tarefa a um processo ou thread em background. Qualquer um que tenha programado uma aplicação cliente de GUI reconhecerá que fez algo assim. As pessoas acabam caindo em problemas, entretanto, se essa troca e comunicação são feitas da maneira errada.
A rota que eu prefiro, e felizmente parece que a maioria dos ThoughtWorkers concordam, é usar um ator. Nesse modelo o controlador da requisição web pega qualquer tarefa demorada, embrulha em um comando e coloca em uma fila. O ator no background então monitora a fila, tirando comandos da fila e os executando, sinalizando ao ator de interação humana quando termina com cada um. A fila normalmente começa como uma tabela num banco de dados e então pode migrar para um sistema real de mensagens se precisar.
Sobre o vazamento do Active Record, eu aponto não porque é um problema de aplicações Rails, nós vemos isso em todo tipo de aplicação. Vale a pena apontar porque parece muito fácil para muitas pessoas usando Rails de esquecer que esse tipo de coisa acontece, e portanto precisam usar esse tipo de padrão. Descobrimos que Rails torna muitas das partes repetitivas de aplicações web fáceis e mais rápidas de fazer – mas as partes mais envolvidas permanecem.
Deployment
Aplicações Rails são fáceis de construir, mas infelizmente já foram mais chatas de fazer deployment. O cenário comum de usar um pacote de muitos servidores web mongrel é ruim de configurar. Isso era uma coisa que ficou marcada pelo contraste com a suavidade do resto da experiência ruby.
O consenso comum é que Phusion Passenger torna essa coisa toda muito mais simples agora e é o jeito recomendado de deployment com MRI.
Também vimos grandes fãs em usar JRuby para deployment. JRuby permite que as pessoas usem a pilha padrão de aplicações web Java, o que pode tornar muito mais fácil de lidar em muitas configurações corporativas. Mingle também usou esse jeito para facilitar a instalação para clientes. De fato a equipe Mingle faz todo o desenvolvimento com MRI mas faz deploy com JRuby. Eles fazem isso porque o tempo de início mais rápido do MRI torna o desenvolvimento mais rápido. (JRuby requer o início da JVM, que é perceptivelmente hesitante.)
Controlando Gems
Ruby inclui um sistema de gerenciamento de pacotes, Ruby Gems, que torna muito fácil instalar e atualizar bibliotecas de terceiros. Rails também tem plugins que faz uma tarefa semelhante para Rails. São boas ferramentas, mas é fácil equipes caírem numa cilada com máquinas diferentes configuradas com diferentes versões de diferentes bibliotecas.
Existem algumas maneiras de lidar com isso. O primeiro jeito envolve copiar o código fonte com todas as bibliotecas e colocar tudo no repositório de controle. Desta forma um simples checkout lhe dará todas as versões corretas das bibliotecas. Um segundo jeito é usar um script que faz o download e ativa as versões corretas de todas as bibliotecas. O script precisa ser mantido no repositório. (AkitaOnRails: o terceiro jeito é usar o próprio controle do Rails para indicar as versões corretas como eu explico neste artigo).
Na mesma linha, a maioria das equipes também colocam uma cópia do próprio código fonte do Rails. Isso lhes permite aplicar patches ao Rails diretamente para consertar qualquer bug ou outros problemas vitais. Esses patches podem ser enviados à equipe principal do Rails. Usar sistemas de controle distribuídos, como git, tornou isso um pouco mais fácil de gerenciar. É certamente muito mais fácil do que nossas lembranças de ter que decompilar servidores de aplicação Java para aplicar patches no passado.
Tempo Cronogramado de Atualizações
Ruby no geral, e Rails em particular, movem de forma rápida. Existem atualizações freqüentes ao sistema Rails, com funcionalidades que queremos usar. Descobrimos que precisamos garantir um tempo cronogramado para lidar com atualizações do Rails e incluí-los no nosso processo de planejamento. Eles são mais significativos que outras plataformas, mas a boa notícia é que existe uma linha constante de novas capacidades.
Desenvolvendo em Windows
Ruby nasceu num mundo unix, e muitas pessoas que trotaram à plataforma usam barras não invertidas para caminhos de diretórios. É possível rodar, fazer deploy e desenvolver para ruby na plataforma Windows, mas também é mais complicado. Nossa recomendação geral é usar uma plataforma unix para todo o desenvolvimento. Macs são mais comumente preferidos, mas muitas pessoas usam outros Unixes FOSS também.
Esperamos que essa situação vá mudar enquanto o Iron Ruby é desenvolvido. Seria legal ter a opção de fazer deploy de aplicações Ruby em Unix, JVM e CLR. De fato isso tornaria Ruby uma opção particularmente flexível para suporte de runtimes em múltiplas plataformas. Também ajudaria projetos .NET a ter Ruby como uma linguagem de script em conjunção com as linguagens mais populares em .NET.