domingo, 26 de abril de 2015

Acessando o SQLite a partir de uma PCL e uma aplicação Windows Phone 8.1

Recentemente precisei acessar o SQLite a partir de uma Portable Class Library, por sua vez acessada por uma aplicação Windows Phone 8.1.

Passei por um bom perrengue até conseguir colocar a coisa toda pra funcionar e por essa razão decidi documentar o passo a passo para a solução final. Segue abaixo:

1) No assembly PCL em que você deseja acessar o SQLite, referencie o pacote NuGet "SQLitePCL.raw_basic". Este pacote fornece acesso ao SQLite sem conter o SQLite em si e portanto é independente de plataforma, podendo ser usado numa PCL. Ele não será usado em tempo de execução, mas permitirá que sua solução compile sem problemas.

2) Ainda no mesmo assembly, referencie o pacote "SQLite-net PCL". Esse pacote é quem fornece a API .NET que você utilizará para acessar o SQLite, como o objeto SQLiteConnection, por exemplo. Internamente, ele acessa o "SQLitePCL.raw" que é o pacote que de fato acessa a 'sqlite3.dll'.

3) No projeto que irá consumir a sua PCL, referencie o pacote NuGet "SQLitePCL.raw". Esse pacote vem com versões específicas para cada plataforma e apenas aquela referente à plataforma do seu projeto será utilizada. É este também o pacote que trás consigo a biblioteca 'sqlite3.dll'.

4) Por alguma razão que não consegui descobrir qual seja, ao compilar e executar o projeto neste ponto, quando tudo já deveria estar funcionando, o runtime informa que a 'sqlite3.dll' não pode ser carregada, mesmo ela estando presente junto aos binários do projeto. A forma como resolvi esse problema foi adicionar, e em seguida remover, uma referência ao pacote oficial do SQLite para Windows Phone 8.1. É necessário remover a referência após adicioná-la pois caso contrário o compilador irá reclamar de duplicidade da biblioteca 'sqlite3.dll', presente nessa extensão, com a outra, disponível no pacote "SQLitePCL.raw". Após esse 'recurso técnico' ser aplicado, tudo parece passar a funcionar sem problemas, mesmo após apagar completamente os binários do projeto e compilar novamente (sem repetir a gambiarra com o pacote oficial).

Escrevi uma breve aplicação para ilustrar essa solução.

quinta-feira, 9 de abril de 2015

Windows Nano Server - A maior evolução para o DevOps Microsoft

O grande gargalo para o uso de sistemas Windows em ambientes de nuvem e para uma boa infraestrutura de DevOps fora do Microsoft Azure é sem dúvida o footprint gigantesco do sistema. Manter uma maquina virtual onde apenas processos de backend precisam ser executados demanda a instalação do sistema operacional completo, incluindo ferramentas gráficas e tudo que as suporta, algo completamente desnecessárias nesse tipo de cenário. 

Atualmente, para preparar uma maquina Windows Server precisamos de cerca de 32GB de espaço em disco, com sorte, o que torna praticamente inviável o uso do sistema em muitos cenários, levando à preferência por ambientes mais leves e modularizados, casos das inúmeras distribuições Linux que temos hoje dominando os ambientes de nuvem e containers.

No entanto, neste último dia 8 de Abril, a Microsoft anunciou o desenvolvimento do Windows Nano Server, uma versão reduzida do sistema operacional, contendo apenas aquilo que é de fato necessário para a execução de uma infraestrutura de nuvem, removendo totalmente sua interface gráfica e demais funcionalidades desnecessárias. Com isso o footprint do sistema caiu expressivos 93%, o que nos leva a crer que poderemos ter uma maquina Windows Nano Server, totalmente viável para a execução de sistemas de backend, com razoáveis 2,3GB de espaço em disco, talvez até menos.

Isso torna viável também o uso do Windows Nano Server com Vagrant e, segundo a Microsoft, até Docker, simplificando absurdamente a criação de ambientes de DevOps para softwares desenvolvidos para a plataforma .NET, principalmente considerando o desenvolvimento do novo .NET Core 5 e ASP.NET 5, também bastante reduzidos em tamanho e muito melhor modularizados, se comparados às versões atuais.

A partir do lançamento desse novo sistema, com pouco investimento, será possível a distribuição e gestão do ciclo de vida de serviços de backend executados sobre a plataforma .NET e Windows em ambientes como o IBM BlueMix, ou Amazon AWS, de forma tão prática quanto é feita hoje para sistemas Java executados sobre uma distribuição Linux.

Essa foi sem dúvida a melhor notícia dos últimos tempos para desenvolvedores .NET e administradores de infraestrutura Windows. Ansioso para ver tudo isso funcionando na prática. Que 2016 chegue logo.

Atualização: Na Build 2015, foi anunciado que o Nano Server tem uma imagem de cerca de 400MB, contra quase 5GB da versão Server Core, a menor disponível atualmente. Além disso, o sistema gasta cerca de 40 segundos para ser instalado, 15 segundos para ser inicializado e ocupa apenas 63MB de memória. Números realmente impressionantes, mesmo em comparação ao atual Server Core.

Vejam mais detalhes em:

sábado, 29 de novembro de 2014

Resista à tentação de criar seu próprio monstro.

Há algum tempo falei aqui sobre a sindrome do arquiteto astronauta, e retomo o tema hoje.

Caso você seja um arquiteto de software, ou tenha tendências a se tornar um, provavelmente está nesse momento implementando ou criando em sua mente algum SeiLaOQueFX, aquele framework que irá satisfazer a tara que todos nós temos por reuso, coesão, simplicidade. Simplicidade? Sim, ao menos é o que normalmente pensamos.

Com o SeiLaOQueFX você e os demais programadores da sua equipe não terão mais dificuldade em implementar um processo de negócio qualquer, poderão se abstrair dos requisitos não-funcionais e focar apenas no que interessa ao negócio. A produtividade da equipe será foda, ninguém mais precisará repetir código, reimplementar padrões, ter que conhecer tais padrões, pra começo de conversa.

Claro que o fato de todo mundo agora ter que conhecer o SeiLaOQueFX mais que qualquer coisa que já estudou ou usou na vida é um mero detalhe, e você está ali para resolver qualquer problema. O fato de você reescrever todas as rodas e engrenagens possíveis também é só outro detalhe. É necessário, afinal o que tem por ai para ser reutilizado é genérico demais e não é bom o suficiente para satisfazer nossa tara por reuso.

Mas aqui vai o que lhe espera, e não negue esta verdade, será pior pra você: Riscos, risco em toda parte. E alguém pagará a conta; se não for você, será sua equipe, ou seu empregador. Sua satisfação inicial em criar o tão sonhado SeiLaOQueFX dará lugar a um sentimento de frustração, de impotência, afinal o fracasso não será culpa sua. E neste ponto não estou sendo apenas irônico. Provavelmente não será mesmo. Mas contará com a sua conivência em todo caso.
Mas o que fazer para não cair nessa armadilha, e não ser um eterno frustrado por nunca ter dado vida ao SeiLaOQueFX?

Uma primeira alternativa é fazer isso fora do trabalho. Se é tão importante pra você, você encontrará tempo. Isso evita que você comprometa seu emprego, sua equipe e seu empregador com os vários riscos que um framework escrito do zero traz.
"Mas sem o SeiLaOQueFX meu trabalho será tedioso, repetitivo, ineficiente". Provavelmente, pois é justamente isso que nos leva a querer ser pai de uma criatura como esta. Mas há outra motivação, interna e quase sempre negada, para fazermos isso. A preguiça. Isso mesmo, preguiça. Palavra forte, mas é o que acontece. Desenvolver nosso próprio EntityFramework, nosso próprio ASP.NET MVC, nosso próprio WCF é sempre mais motivador que aprender a usar estes aí.

Mas é aí que os riscos entram em cena. Todos sabemos que nunca temos à nossa disposição o prazo que precisamos para fazer o trabalho como queremos. Além disso, nosso empregador está pouco se lixando para o SeiLaOQueFX; o que interessa pra ele, e ele está certo em pensar assim, é o produto que ele está lhe pagando para entregar aos clientes dele. Com um framework desenvolvido do zero, inúmeros problemas inerentes ao framework, e não ao software que o utiliza, precisarão ser resolvidos, e quando estes problemas surgirem, não adianta ir tentar explicar ao seu empregador que o SeiLaOQueFX é foda e precisa de mais tempo. Você não está sendo pago para desenvolver frameworks, está sendo pago para desenvolver produtos de software e o desenvolvimento do SeiLaOQueFX está por sua conta e risco. Resultado: Gambiarras. Gambiarras em toda parte. Como você não tem tempo para aplicar o seu brilhantismo e resolver os problemas do seu framework com dignidade, você o fará sem dignidade mesmo, e a culpa é do seu empregador, que não lhe deu tempo pra isso. Portanto, ele que se ferre com a perda de qualidade.

Nesse momento sua equipe estará entrando em colapso. Muitos não irão mais querer usar aquilo que você diz que eles tem que usar e alguns pularão do barco até; outros seguirão paralisados, com uma produtividade cada vez mais baixa. Por fim, tudo aquilo que você sonhou como produto do SeiLaOQueFX se manifestará com sinal invertido, e em um nada belo dia você brigará com todos, discutirá com seu empregador e seguirá seu rumo; irá para algum lugar onde seu brilhantismo seja reconhecido. E ai, ai ferrou pra quem herdou a criança. Sua reputação estará manchada e no fundo você saberá que enfiou os pés pelas mãos, embora dificilmente admita.

Portanto, resista à tentação de criar seu próprio monstro.



sexta-feira, 15 de agosto de 2014

Obtendo sucesso com Arquitetura de Microserviços

Muito tem-se falado em Arquitetura de Microserviços recentemente. Resumidamente, trata-se de um estilo arquitetural em que a lógica da aplicação é dividida em pequenos (micro) serviços os quais podem ser escalados e distribuídos independentemente. Parece simples, mas na prática surgem inúmeras dúvidas sobre como interpretar cada um dos conceitos envolvidos e como implementar cada um deles.
Neste artigo darei algumas dicas baseadas na experiência positiva que tenho tido com a implementação desse estilo nos últimos tempos.

Primeiramente, não se trata de integração de aplicações. Microserviços não é SOA. É muito parecido, mas não tem o mesmo objetivo. Está mais para objetos distribuídos de um mesmo sistema do que para integração de diferentes sistemas, embora os mecanismos usados para a integração entres esses 'objetos' seja muito mais semelhante aos usados em SOA que aos usados em estratégias convencionais de objetos distribuídos, como CORBA, EJBs ou .NET Remoting.

Em segundo lugar, também não se trata de objetos distribuídos tradicionais. Não pense em criar seus objetos de modo que possam ser usados tanto localmente quando de modo distribuídos e deixar alguma infraestrutura de comunicação tomar conta da integração entre eles. Isso é lento e foi o que deu a fama negativa que as tecnologias citadas no paragrafo anterior tem no que se refere a performance.

Se não são aplicações distintas, nem objetos comuns de uma única aplicação sendo integrados, o que são portanto esses microserviços?

Quando iniciei minha experiência com esse estilo arquitetural, o termo Arquitetura de Microserviços ainda não me havia sido apresentado, portanto não precisei me preocupar em seguir uma definição ao pé da letra para poder dizer que era isso o que eu fazia. E isso vale para quem já conhece os termos. Padrões servem para nos apontar o caminho, não para serem seguidos como religiões. Mas voltando ao meu caso, só percebi que o que eu havia construído era aderente a esse estilo depois que já estava quase tudo pronto. Foi um processo bastante natural e como fui guiado pelos mesmo requisitos arquiteturais que levaram à definição do termo Arquitetura de Microserviços, minha implementação já nasceu naturalmente aderente a ele.

A resposta para a última pergunta, no meu caso, veio da metodologia conhecida como Domain-Driven Design (DDD). Embora possa parecer àqueles que a desconhecem que tal metodologia trate apenas de técnicas para organizar objetos de domínio, ela é muito mais que isso. DDD é por si só um estilo arquitetural, o qual define a estrutura de toda a aplicação, não apenas dos objetos de domínio.

Um dos conceitos mais importantes em DDD é o conceito de Serviço de Aplicação. Um Serviço de Aplicação tem a função de coordenar tarefas recebidas de um cliente externo, seja uma IHM ou outra aplicação/serviço, orquestrando a interação entre seus objetos e serviços de domínio, e por fim consolidando o resultado da operação solicitada. As operações executadas por um Serviço de Aplicação devem ter início e fim, sem depender de outros Serviços de Aplicação. E embora um serviço de aplicação possa realizar diferentes funções, cada uma delas deve ser muito bem definida, bem de acordo com o princípio da responsabilidade única, além é claro de estarem de algum modo bem relacionadas.

Dessa forma, uma vez que recebida uma solicitação e um conjunto de dados de entrada, um Serviço de Aplicação irá realizar a função solicitada por completo e produzir um resultado também completo. E isso é exatamente o que precisamos ter em um Microserviço para que ele não nos traga problemas. Na solução a qual me refiro neste artigo, cada função de um Serviço de Aplicação foi implementada como um Microserviço*. Sendo assim, um Serviço de Aplicação não era pra mim uma unidade computacional única, mas sim um agrupamento lógico de Microserviços intimamente relacionados**. Desse modo, cada Microserviço poderia residir em sua própria unidade computacional ou compartilhar uma mesma unidade computacional com demais microserviços que escalassem de maneira semelhante.

No caso de uma aplicação .NET, uma unidade computacional pode ser criada como um Windows Service, por exemplo, enquanto que um Serviço de Aplicação poderia ser composto por uma Class Library contendo os Microserviços que representam suas funções. Já em Java a unidade computacional poderia ser um WAR enquanto que o Serviço de Aplicação poderia ser um simples JAR, apenas para contextualizar.

Mas como seria feito o acesso a esses Microserviços? Para serviços consumidos diretamente por uma página WEB, uma API Web, no formato REST, seria uma boa escolha, no entanto a maior parte dos serviços de um sistema desenvolvido sobre uma Arquitetura de Microserviços só terão interação com outros serviços de backend. Imagine por exemplo uma função de cálculo extremamente complexa e composta por inúmeras etapas. Um primeiro serviço poderia receber a solicitação através de uma página web, via API Web, e então iniciar a primeira etapa do processo de cálculo. Ao concluir essa etapa, o Microserviço que a realizou publicaria o resultado e se colocaria novamente à disposição para o recebimento de outras solicitações. Nesse momento, um segundo Microserviço, responsável pela segunda etapa do cálculo, receberia o resultado publicado pelo primeiro Microserviço e executaria a segunda etapa usando o resultado do primeiro como insumo, por fim publicando o seu resultado para que possa ser usado por um eventual terceiro Microserviço, até que todo o processo de cálculo esteja concluído. Eventualmente a página WEB receberia uma resposta contendo o resultado do cálculo e notificaria o usuário.

Nesse momento chegamos a um ponto extremamente importante. A integração entre Microserviços é quase sempre assíncrona e desacoplada. Um Microserviço deve publicar seu resultado e esquecer dele. Alguém irá recuperá-lo em algum momento e fazer bom uso dele, mas o Microserviço não deve se preocupar com isso, ou aguardar um reconhecimento do Microserviço que porventura dará continuidade a seu trabalho. Microserviços são como aquele colega de trabalho que você um dia teve, que faz a sua parte do trabalho e diz um foda-se para o restante da equipe. E é isso que garante sua alta disponibilidade, sua robustez, e permite que ele seja facilmente substituído caso necessário.

Para alguns casos no entanto, como o caso do primeiro serviço desse nosso exemplo, que recebeu a solicitação da página WEB e deve devolver uma resposta a ela, pode ser necessário aguardar o término do processo por algum tempo, ou considerar que ele falhou. Ou pode-se também iniciar um outro serviço que terá como única função notificar a página WEB quando todo o processo tiver terminado, de modo que o primeiro serviço irá responder à página WEB de imediato, informando apenas que recebeu e encaminhou sua solicitação para que fosse processada. Em todo caso as características marcantes são a assincronia e o desacomplamento.

Okay, mas como realizar esse troca de mensagens entre esses malditos Microserviços? A resposta no meu caso foi o padrão publish-subscribe, implementado através de um Middleware de Mensageria, sobre o padrão AMQP.

Acredito que eu já tenha escrito demais por hoje. Se você chegou até aqui é porque se interessa pelo tema, e estou a disposição para falar mais sobre o assunto. Deixe suas dúvidas ou sugestões no campo de comentários abaixo que procurarei responder, diretamente ou em forma de um novo artigo.

* Atenção ao fato de que me refiro a funções dos Serviços de Aplicação, as quais possuem uma granularidade bastante grande. Modelar funções de Objetos ou Serviços de Domínio como Microserviços seria voltar aos tempos dos objetos distribuídos, e voltar a ter os problemas de desempenho característicos destes.

** E antes de dizer que não é isso que dizem os livros do Evans ou do Vernon, lembrem-se que padrões são guias, não religiões.

Artigos Recomendados:
https://rclayton.silvrback.com/failing-at-microservices
http://highscalability.com/blog/2014/4/8/microservices-not-a-free-lunch.html

quinta-feira, 24 de abril de 2014

TDD está morto?

Nesta semana o chão estremeceu após a declaração de David Heinemeier Hansson (@DHH), autor de livros como Getting Real, Rework, Remote, além do framework Ruby On Rails e do Basecamp, postada recentemente em seu blog, de que para ele TDD está morto. O texto original pode ser encontrado aqui.

Nos últimos anos quem busca estar sempre atualizado com as práticas modernas de desenvolvimento de software tem ouvido sempre que praticar TDD, ou seja, escrever testes unitários antes de escrever o código que será testado, deve ser uma prática obrigatória para se garantir a qualidade do trabalho realizado. Livros e livros foram escritos sobre o assunto, e provavelmente alguns mais ainda serão.

O desenvolvimento utilizando TDD é conceitualmente simples: Para cada método público que pretende escrever em cada uma das entidades que compõem seu software, escreva antes um ou mais testes unitários que entreguem a esse método algumas combinações de parâmetros de entrada, o executem e por fim verifiquem se o resultado de sua execução é aquele esperado para cada um dos conjuntos de parâmetros informados. Faça isso escrevendo primeiro os testes, em seguida, antes mesmo de escrever o conteúdo do método a ser testado, execute os testes para garantir que eles não estão indicando um falso positivo, em seguida escreva apenas o mínimo de código necessário para fazer com que aquele teste passe e por fim refatore o código para torna-lo mais claro e/ou eficiente. Ao terminar essa refatoração seus testes passaram novamente e você terá um indicador para lhe dizer caso alguém faça uma besteira e acabe alterando o comportamento do seu método.

Tudo muito lindo, até se colocar em prática. Na prática, é muito difícil determinar o que testar, além de a arquitetura e o desenho do software mudarem bastante à medida em que sua implementação evolui. E quanto mais granulares os seus testes, mais difícil será mantê-los atualizados. Sem falar no inferno de mocks, fakes e stubs que acabam sendo necessários para permitir que apenas aquele método, aquela unidade de código, esteja de fato sendo testada naquele momento, e não tudo que é executado como dependência a partir dela.

Diante dessas dificuldades, muitos desistem do TDD. Creio que a maioria desista, por elas e pela falta de disposição em aprender e treinar o calhamaço de novas habilidades necessárias para se praticar TDD. Em Janeiro de 2012 o maior advogado do TDD, Uncle Bob (@unclebobmartin), autor de livros como PPP, Clean Code e The Clean Coder, escreveu um artigo em que falava justamente sobre a mudança de posicionamento necessária ao desenvolvedor para que ele pudesse finalmente virar o bit e se tornar um praticante de TDD. Esse artigo pode ser visto aqui, e é um interessante contraponto ao que foi apresentado ontem pelo David.

Pelo que já coloquei acima, já da pra perceber que minha posição se assemelha mais à posição do David nesse caso. Sempre fui extremamente pragmático, e escrever quilos e quilos de mocks e testes para verificar o comportamento de um método que em poucos dias provavelmente nem existirá mais nunca ganhou minha simpatia. Estudei muito a respeito, ainda tenho livros na minha estante sobre o assunto que lerei em breve, mas nunca consegui assumir essa prática (TDD) como uma religião, como muitos tem feito e advogado que deve ser feito. No entanto, assim como David, não me coloco no outro extremo, não sou de modo algum um Programmer Motherfucker que quer apenas escrever código do jeito que bem entender, sem critério algum por que é isso que fazermos, programar. Não estaria me dedicando a este blog agora se fosse esse o caso.

A saída pra mim foi encontrada na verdade em um irmão mais novo do TDD (Test-Driven Development) o BDD (Behavior-Driven Development). Ao qual tenho me referido bastante ultimamente como Especificação por Exemplo.

Após Dan North (@tastapodintroduzir a técnica denominada BDD, muitos afirmaram que BDD não seria mais que TDD feito da forma correta, e a forma correta nesse caso seria dar ênfase ao comportamento a ser apresentado pelo software a ser testado, e não a um único método, uma única unidade de código. Neste link e neste link vemos respostas de Uncle Bob a esse tipo de afirmação.

Dando ênfase a um comportamento, favorecemos a modularização, damos um norte ao desenvolvedor, que pode ter liberdade para criar o desenho do software, tendo como parâmetro o comportamento descrito. Tal comportamento pode ser definido por ele mesmo, ou em conjunto com outros envolvidos, como testadores e analistas de requisitos, mas será no fim parte do código fonte do sistema, será compilado, traduzido para código e testado, num ciclo muito semelhante ao ciclo do TDD, no entanto sem a ênfase absurda à unidade. Serão testes maiores, mais lentos, integrados, embora não necessariamente end-to-end. É uma técnica que com certeza vale a pena conhecer. Obtém-se muitas das vantagens do TDD, sem trazer consigo a maioria de seus problemas.

Enfim, não vou me estender demais. Queria apenas aproveitar a polêmica do momento e escrever esse texto contrastando as duas técnicas e expondo minha posição a respeito do uso de TDD.

Recentemente fiz um trabalho acadêmico sobre o assunto: Melhorando a Eficiência no Desenvolvimento de Software através da Aplicação de Técnicas de Especificação por Exemplo. Tal trabalho pode ser encontrado aqui.

terça-feira, 15 de abril de 2014

Módulos de Negócio vs Módulos de Infraestrutura

Módulos de Negócio versus Módulos de Infraestrutura. Essa é uma das discussões que me deixam mais empolgados quando o assunto é Arquitetura de Software. Mas antes de mais nada, uma breve revisão sobre o que são Módulos.

Um Módulo de Software pode ser visto como uma peça de software que implementa uma determinada especificação e realiza um determinado trabalho conforme especificado. Tais módulos podem ser compostos por um arquivo, uma classe, uma DLL, ou até mesmo um conjunto de DLLs, dentre outras possibilidades, desde que em conjunto esses artefatos implementem uma dada especificação e realizem um determinado trabalho conforme especificado.

Sempre que falamos em Módulos de Software, é comum alguém fazer a comparação com Módulos de Hardware, e gosto bastante dessa comparação. Um módulo de hardware, um componente eletrônico normalmente, pode ser facilmente substituído por um outro semelhante, desde que este outro implemente as mesmas especificações. Os demais módulos que interagem com aquele que for substituído se quer perceberão a mudança. E este seria o Santo Graal da modularização de software, poder simplesmente remover um módulo e substituí-lo por outro que implemente a mesma especificação, sem que os demais módulos reclamem da mudança.

Infelizmente isso ainda é uma realidade pouco comum. Arrisco dizer que a grande maioria das aplicações desenvolvidas no país, ainda que considerando apenas a pequena amostra a que tive acesso, são mal modularizadas e acabam mantendo um alto acoplamento entre seus módulos. E isso prejudica não apenas a possibilidade de fazer substituições de uma implementação por outra, algo que apesar de muito bonito não é tão necessário assim, mas também a definição das fronteiras do escopo de cada módulo, e é ai que está o grande prejuizo em modularizar mal uma aplicação.

De volta ao tema desta postagem, vamos supor que estamos trabalhando no desenvolvimento de um sistema em que há uma boa modularização, em que o papel de cada módulo está bem definido, o acoplamento está baixo e as fronteiras entre os módulos muito bem definidas.

Se tivermos essa realidade, será fácil identificar a separação entre Módulos de Negócio, aqueles que implementam exclusivamente funcionalidades específicas do negócio que está sendo automatizado pelo software, e Módulos de Infraestrutura, que implementam funcionalidades de suporte, drivers de acesso a bancos de dados ou sistemas de mensageria, ferramentas de log e auditoria, gerenciamento de usuários e tantas outras que estarão presentes, sem muita variação, em praticamente toda aplicação que viermos a desenvolver.

Módulos de Infraestrutura são componentes genéricos, reutilizáveis, que podem ter seu desenvolvimento e manutenção totalmente desacoplado dos sistemas que os utilizam. E ai está a grande vantagem em sermos capazes de fazer essa distinção. Quando baixamos um módulo como o Json.NET ou o FluentAssertions através do NuGet, recebemos uma peça de software pronta que apenas consumiremos. Por que não pode ser assim com os Módulos de Infraestrutura desenvolvidos pela própria equipe que consome esses módulos desenvolvidos por terceiros?

Pense que há na empresa em que você trabalha, e não há porque não haver caso você desenvolva aplicações .NET, um repositório NuGet privado, assim como uma política de Gestão de Reuso que defina que todo Módulo de Infraestrutura deva ser desenvolvido de modo independente das aplicações que os consomem, e que devam ser disponibilizados neste repositório uma vez que atinjam uma versão estável. Isso permitirá que esses módulos sejam utilizados pelas equipes de desenvolvimento da empresa, incluíndo as equipes que os desenvolveram, pois estas também deverão consumí-lo através do repositório NuGet, e não através de referências diretas a projetos da mesma solução.

Num cenário como este, teriamos uma solução limpa, composta apenas por Módulos de Negócio se referenciando entre si e consumindo, via NuGet, os Módulos de Infraestrutura que precisam.
Pensem nas possibilidades que um cenário como esse lhe proporcionaria. Pense em possibilidades como abrir alguns desses módulos como projetos Open Source, ganhando a contribuição de desenvolvedores de todo o mundo. Ou a vantagem de poder vender a seus clientes apenas o que realmente precisa e deve ser entregue exclusivamente a esses clientes: seus Módulos de Negócio. Afinal, se você pode consumir componentes de terceiros não relacionados ao negócio do seu cliente sem ter que fornecer a ele a propriedade sobre o código desses componentes, por que não poderia fazer o mesmo com o código dos Módulos de Infraestrutura que você mesmo desenvolve?

Por hoje era isso! Deixem suas opiniões nos comentários.

quinta-feira, 3 de abril de 2014

.NET Native

Recentemente tenho conversado com alguns colegas sobre as impressões que tenho tido ao ler Advanced .NET Debugging, livro que recomendo a todo desenvolvedor .NET que queira realmente entender como o framework funciona (mas ressalto que há uma nova edição no forno, do mesmo autor mas com outro nome, .NET Internals and Advanced Debugging Techniques).

Resumidamente, após entender como .NET funciona de verdade, analisando suas entranhas, percebemos que trata-se basicamente de um Assembly Loader, um JIT Compiler e um Garbage Collector (claro que estou sendo bastante simplista, mas é basicamente isso). Após carregados e JITados os programas .NET se tornam programas muito semelhantes a programas nativos, contando no entanto com o Garbage Collector para gerenciar a memória utilizada pela aplicação. Ainda assim, tudo está disponível para inspeção usando as mesmas ferramenta de debug nativo do Windows SDK, tanto que a passagem de objetos de e para aplicações nativas em tempo de execução é feita de modo bem direto, embora perca-se com isso a conveniência e segurança do Garbage Collector.

Uma vez JITadas, as aplicações .NET tornam-se código nativo, otimizado para o computador em que serão executadas, por isso a MSIL é distribuída nos assemblies ao invés de código nativo. No entanto, é possível gerar imagens nativas, pré-JITadas, dos assemblies e distribuí-las já prontas para uso, através da ferramenta NGen, já existente desde as primeiras versões do .NET, eliminando a etapa de compilação no momento do carregamento desses assemblies.

Essa contextualização é necessária para entender a estratégia .NET Native, anunciada em 02 de Abril de 2014. Tal estratégia consiste no uso de uma ferramenta que, resumidamente, irá pré-JITar as aplicações enviadas para distribuição pela Windows Store para todas as plataformas (modelos específicos de tablets, celulares e PCs) antes que seja feita distribuição para as máquinas clientes. Com isso, espera-se que tais aplicações tenham um carregamento 60% mais rápido, além de serem mais eficientes no uso de memória. Além da pré-compilação, também foram feitas algumas alterações na CLR para otimizar a execução de aplicações .NET Native. Bastante interessante, principalmente sabendo-se que o objetivo é estender de alguma forma esse benefício a demais aplicações .NET, não ficando restrito a aplicações da Windows Store.

Veja mais neste link.