Pacotes, Camadas e M√≥dulos 

Feb/13
18

Em posts anteriores que remontam a 4 anos atr√°s falei sobre como as pessoas confundem o padr√£o MVC com o conceito de Separa√ß√£o de Camadas e o padr√£o ECB. E embora esta confus√£o ainda continue (como mostras posts recentes no GUJ) me parece que sua ra√≠zes se prendem a conceitos de arquitetura e algumas conven√ß√Ķes.

Pacotes

Come√ßando pelo b√°sico temo conceito de pacote. O conceito de pacote em java nada mais √© que uma pasta onde voc√™ coloca os arquivos .java. Mas o caminho desta pasta juntamente com o da classe do arquivo forma o nome completamente qualificado da classe ( que vc pode acessar em c√≥digo usando o m√©todo getName() do objeto Class). O caminho completamente qualificado √© importante para destinguir as classes que t√™m o mesmo nome ‘simples’. Por exemplo, na API Java SE temos duas classes List. A interface da API de collections, e a implementa√ß√£o da API de AWT. Sem o nome do pacote estas classes n√£o poderiam existir com o mesmo nome. Com o nome do pacote temos java.util.List e java.awt.List e n√£o ha confus√£o nenhuma.

Ent√£o suas classes tamb√©m devem existir dentro de pacotes. Primeiro para que n√£o haja problema se voc√™ criar duas classes com o mesmo nome, segundo para que n√£o haja problema se sua classe tem o mesmo nome de outra classe de outra API. Ent√£o, por conven√ß√£o, quando se vai criar uma API nova para um projeto ou para um sistema, criamos um pacote base onde iremos criar todos os outros pacotes. Para garantir que os nomes n√£o se repetem, precisamos de um √≥rg√£o mundial que ateste que os nomes s√£o √ļnicos. Isso n√£o existe, mas existe algo semelhante : o registro de dom√≠nios da internet.¬† Ent√£o, por conven√ß√£o se usa o dom√≠nio invertido da empresa ou do site do projeto. Um exemplo de dom√≠nio invertido seria com.javabuilding se o site fosse www.javabuilding.com.

Dentro do pacote base voc√™¬† ir√° criar suas classes. √Ä medida que as classes s√£o definidas, voc√™ vai querer organizar em sub pacotes para fica mais f√°cil de encontrar essas classes depois. Pacotes comuns s√£o util (para classes utilit√°rias), domain (para classes com regras de dominio) , services ( para servi√ßos) entre outros. Estes nomes n√£o t√™m qualquer rela√ß√£o com as camadas ou a arquitetura do sistema mas sim com as responsabilidades das classes. √Č a responsabilidade da classe que tem liga√ß√£o √† arquitetura e n√£o o nome do pacote. Ent√£o, √†s vezes o nome do pacote coincide com uma camada ( por exemplo, domain) , mas √°s vezes n√£o (utils, por exemplo). Em tese vc pode deixar todas as classes no pacote base e est√° tudo certo. apenas vai ser mais complicado de gerenciar, mas quando¬† tem uma duzia de classes est√° de bom tamanho usar s√≥ o pacote base.

Módulos

Módulo é um conceito que não existe diretamente em java (e existe a JSR 294 para o incluir), mas informalmente módulos são agrupamentos físicos de classes, ou seja, são arquivos .jar.  Mas é um pouco mais que isso. Quando você cria uma classe , você cria um agrupamento de elementos (atributos e métodos) e você define como eles são visíveis a outra classes ( usando os modificadores de acesso, public, private e protected), mas tudo o que for publico será visível a todo o mundo. Às vezes você não quer isso. Às vezes você cria subpacotes com detalhes do pacote principal e as classes que ali estão deveriam apenas ser visíveis ao pacote pai. contudo, para o java não existe o conceito de pacote pai, e é aqui que o pacote se diferencia de uma pasta. A JSR 294 tentar dar mais ferramentas para definir o acesso entre pacotes de forma mais fiel ao conceito que usamos na prática.

Por enquanto, sempre que você coloca suas classes no arquivo jar , todas as que são publicas, são utilizáveis por qualquer um.

Existem dois tipos especiais de jar, o war e o ear que s√£o empacotamentos especiais conforme os padr√Ķes da JEE. Al√©m das classes estes arquivos jar cont√™m arquivos xml ou outros, que definem propriedades do arquivo como um todo e servem para serem interpretados pelos containers (de web e ejb respectivamente).¬† A especifica√ß√£o JEE moderna √© mais flex√≠vel em rela√ß√£o a como empacotar suas classes nestes arquivos, mas em certas circunstancias ( como o uso de tecnologia RMI, por exemplo) torna necess√°rio uma divis√£o judiciosa de cada pacote dentro de cada arquivo jar. Dentro de cada modulo.

Camadas e Andares

O conceito de camada (Layer) nada mais √© que o conceito abstrato que classes que trabalham juntas devem estar juntas. Mas este “estar juntas” significa “trabalharem juntas” e n√£o “estarem fisicamente no mesmo lugar”. Por isso, um camada pode compreender classes de mais de um pacote. Esta agrega√ß√£o em camadas √© abstrata e √© a vis√£o da arquitetura sobre como √© a estrutura do sistema em run time. √Č apenas um conceito. Porque fisicamente as classes est√£o todas juntas na memoria da JVM a todo o momento.

A separação em camadas é conceptual e não se traduz na separação de pacotes ou em uma organização especial dos pacotes.

O conceito de Andar (Tier) √© mais f√≠sico que o conceito de camada e n√£o t√™m apenas que ver com a responsabilidade das classes, mas com o seu papel no fluxo da informa√ß√£o.¬† Uma estrutura importante compreender antes √© o conceito de nodo. O Nodo √© uma normalmente uma JVM. Uma m√°quina f√≠sica pode ter mais do que um nodo e pode ter mais do que uma instancia do mesmo nodo. O conceito de nodo √© especialmente importante em aplica√ß√Ķes distribu√≠das. Em aplica√ß√Ķes web temos o browser e o servidor. O Browser √© um nodo, e o Servidor √© outro nodo, para ser mais exato, Browser √© uma instancia de um nodo do tipo Brwoser, e Servidor √© uma instancia de um nodo do tipo Servidor. O usu√°rio pode abrir mais que um browser e a empresa pode criar mais do que um servidor.

Dentro de um nodo ha um processo de entrada e sa√≠da e entrada de informa√ß√£o. Normalmente o nodo tem acesso a algum tipo de informa√ß√£o ou servi√ßo que algu√©m quer usar. Ent√£o para estruturar como o nodo vai processar a informa√ß√£o, o nodo √© dividido em Andares. Andares definem responsabilidades do nodo. Cada andar ser√° implementado usando um conjunto de classes. Estas classes ser√£o organizadas em camadas. Um nodo t√™m mais que um andar e cada andar pode ter mais do que uma camada e as classes de cada camada serem agrupadas em um ou mais do que um pacote.¬† Alguns pacotes podem ser usados em mais do que uma camada ( √© normal por exemplo usar o pacote de entidades em todas as camadas) contudo as camadas em si, e os andares seguem uma regra de cadeia onde o andar ou camada de cima apenas comunica com o andar o camada de baixo. Isto significa que existiram camadas nas fronteira dos andares e possivelmente com “uma metade de um lado e a outra metade do outro”. Isto √© t√≠pico quando se usa comunica√ß√£o remota em que o cliente envia ao servidor alguma informa√ß√£o as classes que est√£o no cliente enviando os dados e as que est√£o no servidor lendo esses dados fazem parte da mesma camada (porque fazem parte da mesma responsabilidade de comunica√ß√£o), mas de andares diferentes, porque est√£o em nodos diferentes.

O padr√£o atual √© usar 5 andares : Cliente, Apresenta√ß√£o, Dom√≠nio, Integra√ß√£o e Recursos. Em um sistema desktop standalone (por exemplo o word) o Cliente √© a parte gr√°fica com que o ser humano interage, ou o protocolo com que outro sistema interage. O cliente interpreta o input do usu√°rio (seja humano interpretando movimento do mouse e teclas) e cria um output (normalmente gr√°fico). Os inputs s√£o intepretados como gestos. Por exemplo, apertar com o mouse o bot√£o “salvar” significa o gesto “salvar” e apertar com o mouse o bot√£o “sair” significa o gesto “sair”. Contudo utilizar teclas de atalho podem significar o mesmo gesto. E no caso do “sair” , simplesmente fechar a aplica√ß√£o no OS representa o mesmo gesto. O conceito de Gesto √© portanto mais direcionado √† inten√ß√£o do usu√°rio e n√£o a como ele expressou essa inten√ß√£o.¬†¬† A Apresenta√ß√£o √© o andar ondes os gestos s√£o traduzidos em a√ß√Ķes. Estas a√ß√Ķes podem ser a√ß√Ķes que alteram o estado do sistema (persistem algo), que comunicam com outros sistemas ou que simplesmente descrevem como ser√° o pr√≥ximo output do andar Cliente.¬† O andar de dom√≠nio cont√©m as regras de negocio. As entidades, as rela√ß√Ķes entre elas e o que acontece quando uma entidade √© criada, destru√≠da, associada a outra , etc.. O andar de Integra√ß√£o permite que o nodo se comunique com outro nodos para obter informa√ß√Ķes ou requisitar a invoca√ß√£o de servi√ßos e o andar de Recursos s√£o esses servi√ßos ou informa√ß√Ķes em si. Arquivos, Bancos de dados, Servi√ßos de Dados s√£o recursos de uso comum.

A cada andar , corresponde uma ou mais camadas. Poder√≠amos por exemplo usar swing para construir nosso andar cliente. O swing permite que sejamos avisados quando o usu√°rio aperta um bot√£o ou uma tecla. Mas criar uma tela swing implica no uso de muitos objetos e composi√ß√£o de uns nos outros. Mas a resposta ao gesto do usu√°rio n√£o precisa dessa complexidade. Ent√£o provavelmente iremos criar um pacote com as classes de tela criadas usando Swing, e um pacote com as classes que t√™m os m√©todos que representam os gestos do usu√°rio. E umas ser√£o ligadas √†s outras. Quando o usu√°rio apertar um bot√£o ou digitar um texto a classe no outro pacote ser√° alertada, ela decidir√° o que fazer. √†s vezes √© apenas mostrar outra tela ou pintar algo com alguma cor. Ou seja, l√≥gica de navega√ß√£o interna ao pr√≥prio cliente. Outras vezes √© a invoca√ß√£o de um gesto como “salvar” ou “validar” ou “calcular” e ai temos que chamar o andar de apresenta√ß√£o.No andar de Dom√≠nio termos nossos servi√ßos, entidades, validadores e outras classes que contenham regras. Poder√≠amos colocar tudo num pacote s√≥, mas possivelmente √© mais agrad√°vel criar um pacote entities para as entidades, services para os servi√ßos, validators para os validadores e assim vai.

Existe uma correspondência entre um conjunto de pacotes e uma camada, e entre um conjunto de camadas e um andar, e nada impede de termos uma relação um-para-um-para-um, mas simplesmente quando maior for o sistema, quantas mais classes precisar, colocar tudo num pacote só, mesmo que na mesma camada, começa a ficar confuso.

andares-camadas-pacotes

Representação da relação entre andares (em cinza) , camadas (em amarelo) e pacotes (em azul). O fluxo seria da esquerda para a direita e de cima para baixo

N√£o existe uma nomenclatura especial para os pacotes, excepto a conven√ß√£o para o pacote base ser o dom√≠nio invertido de algum site relacionado √† API ou √† empresa. Conforme a arquitetura que voc√™ usar , podem existir mais ou menos nodos, e em cada nodo mais ou menos das camadas que referi ( por exemplo, no nodo Browser raramente voc√™ usa o andar de Recursos, mas ele est√° l√° quando voc√™ tem um upload na sua p√°gina ou usa o novo recurso de webstore do html5. Mas s√£o s√£o todas as aplica√ß√Ķes que t√™m isso.)

Eu sei que não é todos os dias que você tem que pensar no conceito de nodo e andar e especialmente não se você está mais interessado e criar código. Mas ao falarmos de pacotes, camadas e andares não estamos mais pensando em código, estamos pensando em organização. E se você está pensando em organização,  você tem que conhecer estes conceitos. Caso contrário é como tentar arrumar sua casa sem conhecer o conceito de caixa, e saber que existem vários tipos de caixa e que umas encaixam nas outras.

7 comentários para “Pacotes, Camadas e M√≥dulos”

  1. √ďtimo artigo Sergio. Gostaria de fazer uma pergunta.

    Você diz

    O conceito de camada (Layer) nada mais √© que o conceito abstrato que classes que trabalham juntas devem estar juntas. Mas este ‚Äúestar juntas‚ÄĚ significa ‚Äútrabalharem juntas‚ÄĚ e n√£o ‚Äúestarem fisicamente no mesmo lugar‚ÄĚ.

    Eu concordo, mas uma coisa que tenho tentado fazer √© “transformar” minhas camadas em pacotes. Assim, associo o conceito com uma organiza√ß√£o f√≠sica. Fa√ßo isso porque antigamente eu organizava os pacotes conforme a “l√≥gica” da opera√ß√£o que eles executavam. Um exemplo. Uma classe de dominio Cliente ficava no pacote dominio.cadastros, por√©m muitas vezes essa classe era usada somente em opera√ß√Ķes do financeiro por exemplo. A meu ver n√£o fazia muito sentido deixar a classe no pacote de cadastros e acabava retirando e o colocando-a mais pr√≥xima da onde seria usada e isso fez com que esse tipo de pacote acaba-se sumindo das minhas aplica√ß√Ķes! Ent√£o fa√ßo a pergunta, n√£o seria melhor tentar aplicar aos pacotes o conceito de camadas na aplica√ß√£o? Claro que uma camada continuaria e poderia usar mais de um pacote, mas tenho come√ßado a transformar meus pacotes em “camadas” e tenho gostado do resultados, o que voc√™ acha disso?

  2. Se eu bem entendi voc√™s est√° removendo os subpacotes por exemplo “dominio.cadastros” e ficando apenas com o pacote “dominio”. Numa primeira perspetiva isso seria porque o nome “cadastro” √© horr√≠vel (n√£o √© uma boa abstra√ß√£o) e a experiencia lhe mostrou isso. Se vc usasse “dominio.financeiro” em vez, provavelmente n√£o teria removido o subpacote. N√£o ficou claro o que vc quer dizer com “mais pr√≥xima de onde seria usada”. Por outro lado, se vc simplesmente tem os pacotes “apresenta√ß√£o”, “dominio”, “integra√ß√£o” isso significa que os pacotes refletem andares, e n√£o camadas. E os seus subpacotes tlv reflitam camadas desses andares como por exemplo “dominio.entidades” e “dominio.servicos” e “dominio.repositorios” e “dominio.validadores”.

    Como disse no texto d√° para fazer de muitas formas. Eu pessoalmente use os andares para o nome do pacote “macro” ( o que fica logo abaixo do pacote base) e depois l√° dentro vou pondo conforme √© pr√°tico. Normalmente pela responsabilidade , tipo todos os presenters em um pacote, todos os servi√ßos, todos os repositorios, etc.. √†s vezes t√™m que ser assim porque uso funcionalidade de discovery (autowire do spring) e quero que ele veja um pacote especifico e n√£o misture as classes. Outras vezes n√£o. Mas sempre ha o pacote utils da vida que n√£o √© um andar. Por isso que eu falo que √© dif√≠cil um para um, mas pelo menos ha alguma coer√™ncia.

    Se transformar os pacotes em camadas é bom para você e não ha violação de nenhuma regra ( por exemplo, circularidade de dependência ) ótimo. Vá em frente. Não ha uma receita de bolo para o jeito certo. Apenas sinais para os jeitos errados. E o jeito é errado quando viola os conceitos. Como disse é uma questão de caixas. E tudo depende de como as organiza.

  3. Humm.. n√£o √© bem isso, vamos definir alguns padr√Ķes para ficar mais claro.
    Bom digamos que, como você colocou, os pacotes principais sejam os andares. Então meus sub pacotes podem ser minhas camadas!
    S√≥, que, como tu colocaste, a camada √© uma abstra√ß√£o l√≥gica. Ent√£o, voc√™ separa as classes em dominio.servi√ßos, dominio.entidades. Nesse contexto, voc√™ esta classificando as classes conforme o que elas “represetam”, conforme as opera√ß√Ķes que realizam. Assim, digamos que eu tenha uma entidade chamada Venda e essa entidade utiliza alguns servi√ßos. Os sevi√ßos e a classe Venda se relacionam entre si, mas ficam em pacotes separados. J√° no pacote de servi√ßos, posso ter diversas classes que nem se relacionam entre si! Sendo assim, o que quero colocar √©:

    Por que n√£o colocar as classes em pacotes mais significativos e onde fiquem perto das classes que s√£o utilizadas?

    Exemplo. Eu posso retirar a entidade Venda e coloca-la em um pacote chamado dominio.departamentoDeVendas. Ali tamb√©m coloco os servi√ßos que s√£o utilizados pela Classe Venda e quaisquer outras classes do “dominio” que estajam relacionados com o departamentoDeVendas. Assim, ao inv√©s de agrupar as classes em pacotes, conforme o que elas “representam” (entidades, servi√ßos) voc√™ as organiza conforme suas rela√ß√Ķes. Assim, classes que est√£o relacionadas ficam dentro do mesmo pacote e o pacote acaba se transformando em uma “Camada”, ou seja o conceito praticamente deixa de ser abstrato.

  4. Entendi o seu ponto. Realmente nunca pensei nisso. Suponho que seja uma op√ß√£o v√°lida. O problema ai √© acesso entre as classes. Por exemplo, a interface do servi√ßo X ficar no mesmo pacote que a implementa√ß√£o n√£o tem problema (√† priori) pois vc pode isolar no modulo ( no jar) , mas fica mais complicado programar o ant ou o maven para fazerem a separa√ß√£o. √Č s√≥ isso que vejo – a facilidade de modularizar (colocar nos jars certos as classes certas) – mas suponho que se poderia resolver com um subpacote, ou um regex de algum tipo, ou mesmo explicitando as classes na n√£o. E claro que em deploy onde n√£o √© preciso v√°rios m√≥dulos isso fica simples (war , por exemplo). Teria que pensar melhor para saber se isso n√£o viola regras de acesso. Referencia circular, por exemplo. N√£o acontece do pacote X precisar do Y que precisa do X ? Por outro lado, estando tudo no mesmo pacote fica mais f√°cil usar acessos especiais e diminuir as coisas publicas.
    √Č interessante. Vou explorar isso na pr√≥xima oportunidade. De certa forma, realmente parece mais vantajoso.

  5. Nunca tive problemas, mas tamb√©m nunca desenvolvi nada muito complexo para ter problemas. Esse estalo eu tive quando estava lendo o DDD do Eric Evans, tem uma parte que ele fala exatamente sobre isso. Quanto a diminuir a visibilidade de m√©todos p√ļblicos √© fato. Isso j√° me ajudou muito na realiza√ß√£o de testes, as vezes tem algo que eu quero testar, com alguma l√≥gica sacana, mas que n√£o faz sentido ter acesso p√ļblico ou nem pode te-lo, assim utilizo visibilidade de pacote para essa l√≥gica e posso acess√°-la tranquilamente de outra classe do mesmo pacote para os testes.

  6. bom dia
    Qual a diferen√ßa de se ter as 3 camadas em um √ļnico servidor ou te-las em servidores diferentes?

  7. A diferença é que não é possível ter 3 camadas em servidores diferentes.
    Camadas s√£o separa√ß√Ķes no c√≥digo de um √ļnico nodo (servidor).
    Mesmo que você tenha um servidor web para a ui um servidor de aplicação e um servidor de dados (aka banco de dados) em cada um destes ainda terá 3 camadas em cada um.
    Leia http://sergiotaborda.javabuilding.com/2012/02/arquitetura-ecb para ver se ajuda a esclarecer.

Comente

Artigos