Arquivo de setembro \20\-03:00 2009
Desenvolvimento Ágil e Processos
Publicado por Alexandre Valente em Desenvolvimento em 20/09/2009
Esta semana tive a oportunidade de conversar com vários clientes sobre o desenvolvimento ágil e a quantidade de controles e processos que devemos utilizar para suportá-lo. No meu caso, a virada de 180 graus de um desenvolvimento waterfall clássico (com especificação, aprovação e execução) para um desenvolvimento ágil teve como conseqüência inicial a abolição completa de controles e processos – até porque os controles e processos waterfall não se aplicam a um desenvolvimento ágil.
Porém, esta abolição completa está começando a gerar efeito colateral negativo, em dois aspectos: rastreabilidade de decisões e controle de faturamento. A deficiência nestes dois aspectos me foi apontada por clientes e vem sido também sentida internamente pela equipe de desenvolvimento.
A questão da rastreabilidade significa entender, às vezes muito tempo depois da implantação, porque uma determinada funcionalidade foi implementada de uma certa maneira ou porque determinada decisão de negócio (ou de arquitetura) foi feita em detrimento de outras. E, em um desenvolvimento ágil, isto comumente se perde já que os itens de backlog vão sendo implantados e código produzido, ainda que bem comentado, não é suficiente para se manter a visão destas características. Embora as práticas ágeis não sejam contra a documentação (muito ao contrário), fica a questão do quanto e como se documentar. Uma documentação que não seja realmente útil significa gastar horas que poderiam estar melhorando o ROI gerando novas funcionalidades.
A questão do faturamento do trabalho produzido por uma equipe ágil também é um ponto problemático.Mesmo assumindo que o cliente já tenha comprado a idéia de usar uma metodologia ágil, ainda assim ele vai querer uma contabilização do que foi gasto e aonde. E embora o product manager e o cliente específico da funcionalidade tenham uma comunicação extensiva, muitas vezes existem outras pessoas para as quais é importante prestar conta das atividades realizadas. Ainda que a produtividade seja alta, algumas vezes é difícil se ter uma visão do trabalho gerado em cada interação, especialmente em longos períodos de tempo.
Desta forma, nestes dois aspectos, é necessário se definir artefatos e processos mínimos que sejam capazes de gerar e armazenar estas informações. No nosso caso, o que temos feito é tentar automatizar estes processos através de sistema interno específico, para minimizar o tempo despendido na geração destes artefatos e para padronizar as informações produzidas. Assim, para a gestão do backlog, controle das atividades realizadas em cada iteração e armazenamento de notas referentes às tarefas realizadas, estamos desenvolvendo um produto web específico que denominamos Iterator. Nele, teremos a gestão do backlog, a definição das iterações com as específicas tarefas, um amplo suporte a notas, descrições e arquivos anexados a cada tarefa e uma visibilidade por perfil. Ele possui também um módulo windows que é utilizado pelos desenvolvedores para apontar, de maneira simples, rápida e minimamente intrusiva, as atividades em que atuou, permitindo a visibilidade pelos membros da equipe e stakeholders do projeto.
Alguns podem achar que desenvolver um sistema internamente para isto é um overkill, já que existem alguns produtos voltados à gestão e controle do desenvolvimento ágil. Porém, os melhores que analisamos ou são caros (outro conceito relativo, mas caros no nosso cenário) ou são voltados exclusivamente para a gestão de backlog (sem o lado de faturamento) ou simplesmente são muito complexos para se adotar, gerando custo excessivo de treinamento e adaptação. Desta forma, acredito que o custo de desenvolvimento do Iterator (que com o framework, não é tão alto assim), acaba sendo compensado por estes fatores. Finalmente, existe o objetivo de transformá-lo em um produto, o que traz outras compensações.
Se alguém possuir necessidades similares ou que use um produto que não atenda completamente e quiser influenciar no desenvolvimento, basta entrar em contato. Conforme formos evoluindo e quando tivermos algo disponível publicamente, eu notifico a todos por aqui. Até a próxima.
Produtividade – Conclusão
Publicado por Alexandre Valente em Desenvolvimento em 11/09/2009
Oi pessoal, este é um último post da série sobre produtividade. Nos anteriores, eu descrevi a infra-estrutura de desenvolvimento que é usada pela minha equipe atualmente. Toda esta infra-estrutura nada mais é do que uma ferramenta utilizada por nós para se realizar a construção de sofware. Nossos clientes, na grande maioria dos casos, não se preocupam se o software é feito em C# ou em Clipper, ele quer saber se o que ele precisa é barato pra fazer e manter e se é simples e fácil de usar.
Assim, eu vejo esta infra-estrutura toda muito com esta visão pragmáticas, de ser algo que deve permite entregar ou modificar rapidamente uma funcionalidade de negócio, sendo produtivo na hora de atender uma necessidade. Isto faz a diferença para mantermos o nosso cliente satisfeito, com retorno que ele julgue satisfatório para o que ele gasta para se construir software.
Neste sentido, estou bastante satisfeito com a nossa infra-estrutura. Ela é rápida para se iniciar algo do zero, muito rápida para se fazer coisas triviais (como CRUDs) e tão ou menos complexa que outras alternativas para se fazer coisas complicadas. Acho que isto o máximo que podemos esperar de qualquer framework. O meu pragmatismo é aplicado todo o tempo e qualquer alteração no framework (que é sempre caro pra fazer) se justifica somente se ela vai trazer mais produtividade em algum aspecto. Usando o framework atual, estamos conseguindo colocar no ar uma aplicação nova, com controle de acesso (vou detalhar mais isto em posts futuros), estrutura básica e layouts iniciais em poucas horas. Fazer um CRUD de uma entidade leva menos de 15 minutos, considerando do tempo de criação da tabela ao final da tela!
Claro que a produtividade final não depende somente da infra-estrutura. Na minha experiência, 90% do tempo de construção (ou manutenção) de qualquer aplicativo grande fica restrito a umas poucas telas de maior complexidade. Assim, é importante saber trabalhar com o cliente no sentido de minimizar a existência deste tipo de interface. Neste sentido, acho que fazer software não é só entender a necessidade de negócio, é também saber o que é simples ou não de fazer e propor soluções funcionais que sejam mais fáceis de desenvolver. Desta forma, a maneira como se desenvolve acaba também influenciando a necessidade, em uma via de duas mãos. Daí a importância de quem está entendendo a necessidade conhecer muito bem como aquilo vai ser feito, sob pena de se orçar muito mal ou se gastar muito para fazer, com prejuízos para o cliente ou para a própria empresa que desenvolve. Este é um conceito que parece que muitas “analistas” não compreendem, e a causa da falha ou prejuízo de muitos projetos.
Ainda tenho muitas melhorias a serem feitas neste framework. Ainda existem tipos de telas que podem ser melhor suportados, novas funcionalidades que podem ser integradas e alguns serviços que estão sendo refatorados a todo tempo. Porém acho que ele já está maduro o suficiente pra ser empregado em qualquer sistema. Existem áreas para as quais eu ainda não tenho uma solução boa. A geração de relatórios é uma delas. Gerar relatórios na web em geral é algo complexo, pois é difícil montar os layouts e nós sempre encontramos com uma série de limitações de desempenho e banda causadas pelo volume transitado. Não gosto de nenhuma das alternativas existentes atualmente e ainda estou buscando uma que me permita fazer gerar uma DSL e que tenha um comportamento preditível. Informo aqui quando encontrar!
Espero ter contribuído para quem teve a paciência de ler até aqui. Como citei no início, esta infra-estrutura é um exemplo que é difícil de ser replicado para outras equipes ou de suportar uma escalabilidade maior, já que ele exige um treinamento e conhecimentos muito específicos. Mas acredito que os princípios sejam gerais, e possam ser aplicados a outros cenários. Nos próximos meses eu vou adicionar adendos a esta série toda vez que houver uma evolução ou fato novo referente ao framework ou relativo à produtividade em si. Até a próxima.
Produtividade – Camada de Interface Parte 2
Publicado por Alexandre Valente em Desenvolvimento em 09/09/2009
Este post é a continuação da descrição da camada de interface, da série sobre produtividade. No post anterior, mencionei a criação de uma DSL específica para a construção dos elementos de interface e o uso de layouts baseados em XSLT para transformar a DSL + Dados para o HTML final.
O último componente desta estrutura de interface é o próprio controller. Neste são executadas as ações que vão fazer uso dos serviços de domínio. Na minha visão, controllers devem ser bastante simples de construir e manter. Assim, eu utilizo um BaseController, que integrado à ViewEngine específica, encapsula todo o processo de execução de ações e geração do esqueleto do retorno, ficando somente à cargo do desenvolvedor a criação das rotinas de preenchimento do DataIsland e do chamada a regras de negócio.
A exemplo do que é feito nos frameworks MVC, as ações são decoradas para retorno de Html ou Xml puro. E utilizando uma biblioteca javascript específica, pode-se criar uma metalinguagem para, por exemplo, preencher uma área da tela, redirecionar para um outro endereço ou mostrar uma mensagem. Assim, da própria ação, fica super simples para se coordenar o que se quer fazer. Abaixo, um exemplo de controller da tela de login.
public class LoginController : BaseController {
[XmlResult]
public ViewResult Login(string login, string senha) {
var result = Agent.Login(login, senha, SessionID);
var address = HttpContext.Current.Request.UrlReferrer.Query;
if (result.LoginResult != LoginResult.Succeeded)
return CancelAction(“Login inválido”);FormsAuthentication.SetAuthCookie(login, false);
SendRedirect(address);
return View();
}
}
Do lado do cliente, esta ação é chamada com um “onclick=’’Execute(Login)”’. Com estes facilitadores, utilizar AJAX é transparente para o desenvolvedor, e toda a lógica de controle da tela fica automatizada. O único trabalho é descrever a tela na DSL e fazer a chamada às camadas de serviço nos ações dos Controllers. A ViewEngine em conjunto com as bibliotecas javascript fazem todo o trabalho de wiring, execução de chamadas e controle de erros.
Além do suporte às ações, o controller de base também possui um suporte à carga de dados. Um grande efeito colateral de uma orientação a objeto na camada de domínio é que para se mostrar consultas e resultados em tela, é necessário abrir e navegar por um grande número de instâncias em memória. Isto é um problema para desempenho, pois dependendo da profundidade da árvore que se navega, o acesso pode ficar inviável. A maneira que o framework resolve isto é indo direto ao banco para consultas pesadas, de detalhamento ou de listas. O elemento de dados (também conhecido como DataIsland) possui métodos apoio para executar consultas (views) em um formato especialmente definido, preenchendo-o com o XML resultante. O exemplo a seguir ilustra isto:
protected override void DoFillDataIsland(DataIsland dataIsland, int page) {
dataIsland.CreateNameValueItemList(“Projects”, CurrentUser.AllowedProjects, PNP.Name, PNP.Id, false);
dataIsland.GetFormItem(“Filter”).Add(PN.Project, filterProject);
dataIsland.CreateListFromView(ListName, page, Filter.Criteria, GetFilterDescription(), OrderBy);
base.DoFillDataIsland(dataIsland, page);
}
Neste exemplo, é criada uma lista de Name/Value para uso em uma combobox a partir de uma coleção de projetos. Logo a seguir, é definida uma variável no DataIsland que vai ser usado para se definir qual o projeto selecionado na combobox. Finalmente, é criada uma lista de itens a partir de uma view com o nome ListName, paginada e com os filtros definidos por Filter. Fica bastante simples para o volume de dados gerado!
Claro que existem muitos outros detalhes referentes à orquestração e manipulação de dados, integração com a parte de segurança, validação etc. Mas acho que deu pra se ter uma idéia de onde se pode chegar com uma estrutura destas. Tem toda a parte de suporte de componentes de cliente, que são implementandos com bibliotecas comuns como jQuery e controles javascript. O jQuery em específico é uma grande ferramenta de produtividade para a manipulação de conteúdo HTML, porém sempre em códigos pequenos, para complementar alguma necessidade de tela que não faz sentido ser contemplada pelo framework.
Com o uso do framework, eu tenho visto os índices de produtividade estão se elevando cada vez mais. Com o framework, incluir uma nova entidade com a criação da tabela, definição da entidade de domínio, criação da tela de lista e de edição para CRUD, é uma tarefa que não leva mais do que alguns minutos. Isto é comparável aos geradores das melhores linguagens dinâmicas atuais, mantendo a tipagem do C#. Claro que um sistema tem somente pequena parte do esforço gasto em CRUD, mas com estes recursos é possível definir e construir telas que são simples de dar manutenção, de maneira extremamente rápida. O nosso processo atual é pedir pro designer gráfico gerar o HTML; a gente quebrar o HTML em layout e DSL e depois fazer os controllers. Claro que isto tudo só vale se o investimento na construção de todos estes componentes for amortizado em muitos sistemas em produtos.
Isto conclui a descrição dos componentes do framework. No próximo post, a conclusão desta série, com a minha visão de como a produtividade é afetada por todos estes artefatos. Até mais.
Produtividade – Camada de Interface Parte 1
Publicado por Alexandre Valente em Desenvolvimento em 05/09/2009
Em mais um post sobre a série sobre produtividade, vou escrever sobre a camada de interface. Por interface eu me refiro à web, já que é raro nós termos grandes desenvolvimentos de aplicativos Windows – e mesmo nestes casos não é algo problemático, o desenvolvimento em Windows Forms do .NET é bastante tranqüilo para aplicações de pequeno porte. Intrefaces baseadas em serviços também são super simples para serem construídas, ainda mais usando a WCF Factory. Assim, o foco é a construção de páginas web. Para não tornar este post muito longo, eu o dividi em duas partes.
Na minha experiência, o desenvolvimento de interfaces web é onde se gasta mais de 90% do tempo de desenvolvimento e manutenção de qualquer sistema de médio ou grande porte. É também onde a evolução tecnológica se faz mais sentir, a disseminação de uso do AJAX, por exemplo, mudou completamente o modo como se desenvolve para web. E para os usuários, a qualidade da interface e navegabilidade muitas vezes é um dos maiores fatores de sucesso ou fracasso de um sistema, fazendo com que o investimento nestes artefatos seja primordial.
Para ilustrar o que busco, vou começar descrevendo o que pra mim é o pior cenário possível para interfaces. Tenho certeza que quem desenvolve para web já viu algo assim em algum momento da carreira. Todo sistema começa bem e o ASP.NET WebForms ainda é o método mais comum de construção utilizado. Assim, no início da vida do sistema, as telas são feitas de maneira mais ou menos rápida. Porém com o tempo, os usuários pedem evoluções para suportar algo pouco usual, um ou outro desenvolvedor menos experiente acaba colocando sua “contribuição” para as telas e o que antes era simples se torna extremamente complexo. Depois de alguns anos (ou meses, dependendo do sistema), o que temos é uma coleção de aberrações, cada tela com código específico, com coisas indo pra sessão outras para viewstate, código inline (com o famigerado <% %>), regras de negócio em .cs de páginas (ou ainda, pesadelo dos pesadelos, no mais famigerado <% %>). Se o sistema foi portado do ASP então, a visão dantesca se completa, pois nestes caos é difícil encontrar qualquer coisa minimamente estruturada. O uso de componentes de terceiros ou frameworks só complica, pois também tendem a gerar ainda mais telas fora do padrão, com todos os tipos de “puxadinhos” imagináveis. Ou seja, em casos como este é muito mais fácil refazer a aplicação do que tentar arrumar. Porém quando se resolve reconstruir, o ciclo se repete e daqui a alguns anos (ou meses!) está tudo como era – normalmente deixando mais um legado para se manter, para a infelicidade de quem ficou.
Como resolver isto? Como desenvolver rapidamente e ainda assim gerar sistemas que não se autodestruam com a manutenção/evolução? A solução que eu uso são frameworks de interface que tentam garantir a estruturação das interfaces de uma maneira que facilite que os desenvolvedores fiquem em um padrão pré-estabelecido e ao mesmo tempo tentando gerar o máximo de flexibilidade possível. Nesta linha, eu tenho sistemas desenvolvidos há quase oito anos que continuam bem estruturados. Naquela época a amarração era tão forte que as telas produzidas eram muito simples, gerando sistemas de usabilidade ruim, comparando com os atuais. Porém existem vários operando até hoje que são simples de manter e (até hoje) de evoluir. De lá pra cá a evolução do framework já permite gerar telas extremamente amigáveis, mantendo ainda os níveis de manutenabilidade originais. Claro que esta não é uma solução para qualquer empresa ou time, o nível de treinamento e envolvimento com o framework é muito alto para ser facilmente replicável. Mas no nosso caso está sendo muito bem sucedido.
O framework utiliza um tipo de padrão MVC, porém com uma separação clara em 4 componentes: 1) Estruturas de Interface – aqui entram caixas de texto, checkbox, botões, listas etc. São itens que contém os dados sendo apresentados e que serão manipulados pelos usuários. 2) Layout – que é como as estruturas de interface são mostradas em tela. No layout entra toda a parte visual como estilos, manipulação visual (via jQuery por exemplo), controles, figuras e até coisas como uso de janelas popup ou chamadas AJAX. 3) Dados – utilizando um conceito que também utilizado no Microsoft Sharepoint, definido em uma ilha de dados XML que contém todas as informações que serão utilizados pela interface. 4) Controllers – controladores da interface, onde os dados são construídos e as ações executadas, fazendo uso das entidades de domínio e chamando os serviços da mesma.
Separando desta forma, fica fácil notar quais elementos são afetados quando há uma mudança, fazendo com que a mesma impacte o menos possível os demais. Esta estruturação faz com que o desenvolvimento de novas telas seja concentrado em 2 pontos, na definição de estrutura de interface e nos controllers. A clara separação existente evita que uma área afete outra.
Na minha experiência, o Layout é um dos pontos que mais evoluem na interface. Embora em linha gerais ele fique estático (p. ex., pode se definir que o sistema vai ter um cabeçalho com o nome do sistema, usuário logado e menu; no meio com uma área de formulários e listas e com inclusões em popup, tudo usando Ajax), as pequenas modificações acabam sendo freqüentes. É a inclusão de um novo elemento no cabeçalho, o suporte de uma lista hierárquica, um novo tipo de componente e assim por diante. Para garantir que não aja uma mistura de responsabilidades, eu uso XSLT para a definição de todos os artefatos de layout. Este é um dos pontos de maior dificuldade de aprendizado no framework, já que não é usual que desenvolvedores usem diariamente XSLT. Mas, como falei no post sobre princípios, o XSLT é uma linguagem declarativa que evita o uso de código imperativo e o uso de artefatos como sessão, viewstate etc. E uma vez dominado, o XSLT é extremamente eficiente para se gerar o HTML final (sem falar que já gera o HTML correto!).
Para gerar o HTML final, os arquivos XSLT de layout utilizam duas fontes de transformação: os dados e a estrutura de interface. Isto já faz com que os dados tenham que ser facilmente descritos em XML. Eu vou a um ponto mais extremo, fazendo com que todos os nossos dados sejam descritos somente em XML – também como é feito no Microsoft Sharepoint. Com isto, minimizamos o uso de objetos DTO e tornamos a estrutura de dados da interface completamente maleável e fácil de evoluir.
Finalmente, a estrutura de interface também deve ser descrita em XML, para que seja facilmente transformável. O que fizemos foi criar uma DSL, integrada ao Visual Studio (com intellisense, claro), para descrever cada elemento de interface. Vejam como fica um exemplo simples de um formulário de login:
Exemplo de DSL de Interface:
<Form defaultFocus="Login">
<Field data="Login" type="textbox" required="true" label="Login" />
<Field data="Senha" type="textbox" required="true" label="Senha" password="true" />
<Command label=”Logar” action=”Login”/>
</Form>
Exemplo de XSLT de Layout (super reduzido para efeito de ilustração):
<xsl:stylesheet version="1.0" >
<xsl:template match="Form">
<html>
<body>
<form method="post">
<xsl:apply-templates select=”Field|Command” mode=”Control”/>
</form>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
No XSLT acima, cada Field é transformado em um input box e o Command em um button. Percebam que não há código inline – não existe o <% %>. Este tipo de arquitetura era muito dificil de ser construída e mantida no ASP.NET Webforms, o que tornava o framework bastante complexo. Felizmente com o advento de bibliotecas MVC, isto ficou muito mais simples. Inicialmente, criamos uma View Engine para suportar esta DSL no Castle Monorail. Com o advento posterior do ASP.NET MVC, criamos uma a View Engine para ele que funciona com exatamente a mesma DSL e os mesmos arquivos de layout. Esta migração mostrou a capacidade de evolução do framework, o que me deixa tranquilo para encarar a manutenção dos nossos sistemas por, quem sabe, outros 8 anos por vir.
No próximo post vou explicar como as ações são executadas e entrar nos detalhes dos controllers, mostrando como isto tudo se integra.
Até breve!
Produtividade – Camada de Domínio
Publicado por Alexandre Valente em Desenvolvimento em 01/09/2009
Continuando a série sobre produtividade, vou falar neste post sobre a camada de domínio. A camada de domínio é a que contem todas as entidades e regras de negócio, sendo utilizada pela camada de interface e fazendo uso do banco de dados para armazenamento de informações.
Inicialmente existe a questão da impedância objeto-relacional. Para o desenvolvimento o usual é trabalhar com objetos em código para representar objetos do mundo real, com seus vários atributos e relacionamentos. Uma tabela de banco é uma representação mais pobre e difícil de manipular, por isto trabalhar com objetos é mais simples. No entanto, o banco de dados relacional é necessário (bancos de dados orientados a objeto ainda são praticamente inviáveis, por uma série de razões), logo, deve haver uma maneira de converter classes em tabelas e instâncias em registros. Assim, o uso de um ORM é fundamental, pois esta tarefa tem que ser simples, não faz sentido gastarmos tempo de desenvolvimento escrevendo e debugando comandos SQL básicos.
Nosso ORM de escolha é o nHibernate (NH). No entanto, escrever arquivos de configuração paro nHibernate é trabalhoso (e não queremos trocar o trabalho de escrever SQL para o de escrever configurações), assim utilizamos também o Castle ActiveRecord (AR). O AR permite definir objetos com simples atributos de decoração e ele já traz também uma série de implementações pra facilitar o uso do NH. Apesar de ser mais simples, decorar classes e atributos ainda é trabalhoso (e erros nesta etapa podem causar graves conseqüências para aplicação), então para simplificar ainda mais, utilizamos o ActiveWriter (AW), que é uma DSL gráfica que permite descrever as entidades e ele gera todas as classes e propriedades já decoradas. O AW tem outras vantagens, descritas a seguir.
Até aqui super simples, mas existem duas guerras religiosas envolvidas que acho importante citar. As duas têm relação com o chamado “modelo anêmico”, definido pelo Fowler. A primeira é sobre se todos os objetos de domínio devem ou não ter representação direta em banco. Em um modelo OO puro isto não seria desta forma. Porém a minha opinião é de que é muito mais simples, pra efeito de desenvolvimento, manutenção, extração e até conversa com os usuários avançados, que haja o mapeamento 1:1. Ou seja, cada classe é uma tabela, cada registro uma instância. Os puristas afirmam que isto não é OO, pois o modelo de entidades de negócio acaba sendo só uma representação do banco. Na minha visão sim, pode ser… Porém como o banco na verdade é criado para suportar as classes, há um caminho de duas vias aí. E os benefícios que tenho colhido nos últimos 10 anos trabalhando desta maneira são muito grandes pra tentar mudar simplesmente pelo purismo. Assim, no nosso caso, há o mapeamento 1:1 sempre.
A segunda guerra religiosa tem a ver como onde as regras de negócio são implementadas. No Domain-Driven Design (DDD), existe o conceito de serviços, porém muitos acham que regras específicas de objetos devem estar na classe. Eu não. Eu acho que TODAS as regras de negócio devem estar definidas em Serviços (com exceção de regras de consultas, que estão nos repositórios e de regras de construção que estão nas fábricas). Com isto o nosso modelo é por definição, completamente anêmico. Nossos objetos são somente POCO e todas as regras estão sempre localizadas nos serviços. Apesar de alguns acharem isto extremo, no meu caso eu tenho tido muito sucesso trabalhando desta forma. Quando se tenta colocar regras em objetos, muitas vezes há a dúvida de se uma regra pertence a uma ou outra classe. Com o tempo, ninguém sabe onde está o que. Além disto, fica muito mais difícil trabalhar com AOP desta forma, pois em caso de um objeto chamar outro, fica difícil definir de quem é a responsabilidade e controlar transações, segurança, erros etc. Da maneira como eu faço, que é tudo na camada de serviços, ninguém nunca tem duvida de onde procurar uma regra, todos os aspectos estão lá e a manutenção do sistema é super tranqüila. Tenho sistemas de mais de 10 anos (com objetos ainda em C++!) onde continua sendo fácil mesmo pra quem não conhece, de identificar e alterar regras de negócio.
Assim, na nossa implementação, temos um repositório e uma fábrica para cada entidade de negócio (que por sua vez representa uma tabela). E os serviços são criados conforme necessário, onde cada regra é stateless e completamente procedural. Puristas falam que isto não é DDD. Pode ser. Mas é muito produtivo!
Para gerar serviços e repositórios, utilizamos arquivos de template (.TT) do visual studio. Eles utilizam a definição gerada pelo AW e automaticamente já constroem todos os repositórios, fábricas, operadores e demais artefatos de auxílio. Ou seja, ao arrastar graficamente uma tabela para o nosso diagrama AW, todos os artefatos mínimos para uso da entidade já estão prontos! Claro que iremos expandir os repositórios e fábricas com novos métodos e isto é feito através de classes parciais. Todos os repositórios, fábricas e serviços são implementados através de um container IoC, o Castle Windsor. Com isto uma troca futura de qualquer destes componentes é super simples – p. ex., a única dependência para NH que temos são as implementações de repositórios. Tudo fica em um único assembly que chamamos de assembly de domínio.
Finalmente, temos algumas classes estáticas de apoio como, por exemplo, uma com todos os nomes de propriedades de todas as entidades, outra com um acesso rápido para repositórios e fábricas e uma com todos os serviços do projeto. Outra classe muito útil é a de geração de consultas. Em repositórios, as consultas podem ser feitas via HQL do NH ou via consulta direta. Como a maior parte das consultas é simples, elas são feitas por critérios diretos e pra isto utilizamos uma interface fluente para ajudar a escrever. Exemplo:
return Query.Where(Restrictions.Eq(PN.User, user)).And(Restrictions.IsNotNull(PN.ClosedOn)).Count();
A consulta é feita para uma entidade chamada “Incident” e retorna o total aberto para um usuário. Query é a classe de apoio de consulta e PN são os nomes de propriedades – usamos isto para evitar strings e com isto minimizar o número de erros de digitação.
Estou muito satisfeito com a qualidade e a produtividade gerada pela nossa camada atual de domínio. Fazer e dar manutenção em objetos é algo que para nós é super simples e podemos nos dedicar e escrever regras de negócio e interface. O próximo post vai ser sobre a camada de interface.