Continuando o assunto do post anterior, o livro de Uncle Bob é uma verdadeira salada. Só para se ter uma idéia, aqui vão alguns dos assuntos tratados: Manifesto Ágil, Extreme Programming, Design Ágil, Princípios de OO e Patterns, Princípios de Design de Pacotes, UML, vários casos de estudo e pra fechar a divertida “Sátira de duas companias” e um fabuloso artigo de Jack Reeves, de 1992, entitulado “What is Software Design”. Leitura mais que obrigatória!
A leitura deste livro me levou a algumas boas reflexões sobre como coisas escritas há anos, até decadas atrás estão presentes (às vezes nas entranhas às vezes na cara) nos assuntos mais “badalados” e buzzwords dos artigos e foruns a fora.
Quem inicia seus estudos em desenvolvimento de software acha que nunca irá “saber tudo”, afinal de contas “é muita coisa pra estudar”. A notícia ruim é que vocês têem razão, nunca saberão tudo. Mas nem tudo está perdido. Para a maioria dos softwares corporativos que são desenvolvidos, sólidos conhecimentos de Orientação à Objetos e algumas Práticas Ágeis de desenvolvimento já te deixarão anos luz à frente da maioria dos profissionais do mercado.
Mas o que quero tratar neste post e ouvir a opinião de vocês, é justamente um de meus devaneios durante a leitura.
Um dos temas que me interessou bastante, pois não tinha lido nenhum livro que tratasse do assunto foi sobre Design de Pacotes.
Imaginemos um caso de estudo: Um sistema bem simples para armazenar fotos. A pessoa cria um pefil. Cada perfil pode armazenar diversas fotos. Além disso cada perfil pode estar associado a vários amigos. Você só pode ver as fotos de quem for seu amigo.
Solução 1:
Consegue enxergar algum problema neste design?
Vamos imaginar que a atual implementação de FotoDaoImpl salve as fotos no sistema de arquivos da própria máquina. O primeiro release tinha que sair rápido, seria uma aplicação desktop e essa solução resolveria o problema por hora. Contudo, no próximo release será entregue uma versão web da aplicação e agora as fotos devem ser salvas em um SGDB, porém a versão desktop da aplicação continuará sendo usada (por qualquer razão que seja). Então, como reutilizar o pacote Domain sem ter que “levar de brinde” o pacote de Infra já que a classe Perfil busca as fotos a serem exibidas atraves da interface FotoDao, que por sua vez possui uma implementação para salvar e carregar as fotos do sistema de arquivos local da máquina?
O grande problema é que o pacote domain possui uma dependência direta com o pacote de infra estrutura. O que é uma péssima idéia. As classes de domínio devem depender apenas de classes do mesmo nível de abstração, ou seja, classes que fazem sentido ao negócio, nunca de classes de infra-estrutura. Quanto maior a dependencia do pacote Domain com outros pacotes, maior será o número de razões para este sofrer mudanças. Isso significa que, sempre que o pacote Infra alterar, você terá de revalidar o pacote Domain e verificar se nada foi quebrado.
Uma regra simples é: Pacotes instáveis dependem de pacotes estáveis. Pacotes estáveis não devem depender de pacotes instáveis.
A estabilidade de um pacote tem a ver com o “esforço necessário para se fazer uma mudança”. O que isso significa?
Imagine a siguinte situação: os pacotes B, C e D todos dependem do pacote A. Logo o esforço para realizar uma mudança no pacote A é muito grande, pois afetará outros três. A é um pacote estável!
Por outro lado se, nenhum outro pacote depende de B, então ele é instável. O esforço para uma mudança é muito baixo, só afeta ele próprio.
Muitas vezes a estabilidade de algo é confundida com a frequencia com que essa coisa muda, ou seja, se muda muito é instável se muda pouco é estável. Cuidado isso é um equivoco.
Uncle Bob dá o seguinte exemplo em seu livro: Coloque uma moeda em pé. Se ninguém mexer com ela, continuará ali, quietinha, sem nenhuma alteração. Por isso ela está estável?
Não, pois o esforço para mudar sua posição é mínimo. (outra tentativa de metáfora para esse problema)
Uma solução é colocar a interface FotoDao no pacote Domain. Dessa forma aplicamos DIP (dependency-inversion principle) e magicamente a dependencia é invertida. O pacote Infra é quem passa a depender do pacote Domain. Com essa mudança nosso pacote de maior nível de abstração, o domínio, passa a ter apenas um bom motivo para sofrer alterações. Ele próprio!
Solução 2:
Aplicar DIP foi uma boa solução. Mas ainda não fiquei satisfeito. Como a classe FotoDao faz parte do domínio da aplicação? O zé que vai publicar suas fotos sabe que raios isso significa?
O que precisamos é de um local para guardarmos e recuperarmos nossas fotos. Uma espécie de repositório de fotos (buzzword++), algo como FotoRepository. Assim não incluimos em nossa linguagem (ubiquotous language) conceitos especificos de tecnologia. Certo? Huunnn… ainda não.
Invertemos a dependencia, assim consiguimos reutilizar o pacote Domain. Retiramos o cheiro de termos tecnicos da nossa comunicação. Então o que falta?
Será que em uma conversa com com o usuário ele citaria o termo “repositorio de fotos”? Acho pouco provavel. Que tal album? Um album nada mais é do que uma coleção de fotos. Onde podemos incluir, retirar e consultar nossos fotos. Não? Um repositório de fotos. Aaahh, mas você só mudou o nome, grande coisa. Sim só mudamos o nome. Nomes são muito importantes e fazem toda a diferença.
Então ficariamos com alguma coisa mais ou menos assim:
Veja como conceitos de Orientação à Objetos, Design de Pacotes, Patterns como DIP (e outros SRP, LSP, OCP), Domain Driven Design, Refactoring, Design Ágil, Iterações curtas e pequenos releases, etc se sobrepoem e se completam. No fim das contas, quando você estudar DDD por exemplo irá aproveitar conceitos de OO que aprendeu. Quando for aplicar Refactoring idem, e por aí vai.