Como organizar os pacotes da sua aplicação?

Abra seu projeto atual e dê uma olhada na divisão de pacotes. Você consegue entendê-la? Ela faz sentido? Agrupar classes em pacotes pode ser sim um desafio. E justamente por isso, é comum a dúvida: quais pacotes devo criar?

Essa é uma pergunta bastante difícil de ser respondida, e gera discussão entre desenvolvedores de todos os níveis de experiência. Utilizamos pacotes porque sentimos a necessidade de agrupar classes de acordo com algum critério. É bem comum então vermos pacotes como br.com.caelum.dao, onde colocamos todos nossos DAOs, ou mesmo, br.com.caelum.dominio, onde colocamos todas as nossas classes de domínio.

Não há uma “verdade” sobre como criar ou nomear pacotes. Mas quais são as boas práticas na hora de se criar um pacote?

Um bom pacote é aquele que facilita o reuso. Mas como isso acontece? A ideia é que todas as classes em um pacote sejam reutilizáveis, ou que nenhuma seja. Ou seja, não misture classes que são reutilizáveis com classes que não são. Com essa separação, conseguimos levar pacotes específicos de um projeto para outro, sem levar classes “inúteis”.

Evite também dependências cíclicas. Uma dependência cíclica acontece quando um pacote “depende” do outro. Ou seja, temos classes no pacote1 que dependem de classes do pacote2, e vice-versa. Mas qual o problema disso? Manutenção e reuso. A partir do momento que pacotes passam a depender entre si, o reuso diminui, afinal, precisamos reutilizar ambos sempre juntos. A manutenção também torna-se mais complicada, afinal mudanças em um pacote podem impactar em mudanças também no outro pacote.

Pacotes devem ser totalmente estáveis ou totalmente instáveis. Por estável, quero dizer que o pacote tende a mudar menos. Pacotes estáveis são geralmente aqueles em que você coloca suas interfaces ou classes abstratas. Pacotes voláteis (ou instáveis) são aqueles onde queremos mudar. Geralmente guardamos as nossas classes de domínio, serviços e outras regras de negócio concretas lá. Essa separação é importante para facilitar a implementação do próximo princípio.

Pacotes devem sempre depender de pacotes mais estáveis do que ele próprio. A ideia é que cada pacote dependa sempre de pacotes mais estáveis do que ele próprio. Dessa forma, a propagação de mudanças é reduzida, e a manutenção torna-se mais fácil. Ou seja, os seus pacotes que contém regras de negócio (e é um pacote mais volátil) deve depender de pacotes mais estáveis, como o pacote onde você põe suas interfaces de acesso a dados (repositórios) ou mesmo as interfaces dos serviços que essas regras consomem (pacotes esses que são compostos por interfaces e, por consequência, são mais estáveis).

Resumindo, pense em deixar classes perto, ou para facilitar o reuso do pacote entre outros projetos, ou para agrupar classes que mudam juntas.

Veja que essas ideias também fazem sentido para classes, e foi o que discuti em meu post anterior sobre os princípios SOLID. Os princípios que comentei acima, aliás, também são discutidos pelo Robert Martin em seus livros e artigos.

Gerenciar dependências entre pacotes é tão trabalhoso quanto gerenciar dependências entre classes. Mas, sem dúvida, a longo prazo, o esforço se paga. Discutimos boas práticas de código em nosso curso presencial de arquitetura e design, em nosso livro sobre o assunto, e mesmo no meu livro e curso online sobre TDD.

E você, como tem separado seus pacotes? Usa alguma regra diferente das que mencionei aqui?

8 Comentários

  1. Rafael Ponte 18/02/2014 at 10:41 #

    Excelente post, Aniche.

    Que bom que citou o artigo do Uncle Bob, é uma ótima referência.

    Ainda hoje não tenho opinião formada sobre como organizar e nomear pacotes. Isso costuma variar de projeto para projeto e equipe para equipe, mesmo que no final eles tenham uma boa semelhança.

    O Uncle Bob também aconselha organizar os pacotes por feature ou caso de uso, pois fica mais próximo do domínio, da linguagem ubíqua. Tanto é que ele condena a convenção de pacotes do Ruby On Rails (controllers, models etc).

    Eu não concordo muito com o Uncle Bob (mesmo achando interessante e relevante a opinião dele), pois acredito que a linguagem técnica dentro da equipe é tão importante quanto a linguagem ubíqua do domínio, e ter o equilíbrio entre as duas é fundamental.

    Enfim, é um assunto polêmico que gera muitas discussões em todos os lugares. O que importa é que seja uma decisão da equipe e que no fim todos sigam a convenção para que não exista ruídos na comunicação.

    Parabéns pelo post.

  2. Daniel Oliveira 18/02/2014 at 12:50 #

    Aniche, parabéns pelo post. Trazer assuntos “polêmicos” mas importantes e com esta clareza de argumentos é de grande valor!

  3. Alexandre Aquiles 18/02/2014 at 13:31 #

    Com certeza, um assunto polêmico!

    Particularmente, eu gosto de organizar pacotes pelo domínio. Concordo com o argumento do Uncle Bob, que o Rafael Ponte mencionou. A estrutura de alto nível do seu código não deve “gritar” Rails ou nenhum outro framework. Deve “gritar” os grupos conceituais do problema que você está resolvendo.

    Dessa maneira, há a possibilidade de separar facilmente em módulos (jars no Java ou gems no Ruby), se for o caso. Já sofri com aplicações monolíticas e gigantescas que poderiam ser quebradas em alguns módulos relativamente independentes entre si.

    ___

    Sobre ciclos, em alguns casos, dá pra usar “Dependency Inversion” para quebrar o ciclo. Recomendo o capítulo 5 do livro “Java Modularity Patterns” como referência inicial: http://www.kirkk.com/modularity/2009/12/chapter-5-taming-the-beast/

    Dito isso, sempre acabo com ciclos quando uso JPA! 🙁

  4. Erick 19/02/2014 at 15:21 #

    Bom texto!
    Vou deixar uma referência q eu achei quando estava estudando pra montar minha estrutura.
    Ele organiza por feature e depois por layer
    http://stepaheadsoftware.blogspot.com.br/2012/06/java-package-name-structure-and.html

  5. Stélio Moiane 21/02/2014 at 02:56 #

    Muito boa dica, parabens Aniche. Realmente este é um assunto que se tem deparado quase todos os dias pois os paoctes sempre crescem.

    Valeu mesmo!

  6. Jairton Junior 08/04/2014 at 19:25 #

    É bacana ver mais alguém entrando nessa discussão sobre pacotes. Às vezes acho que estou fazendo tempestade em copo de água por querer organizar as coisas…

    Anyway, geralmente eu me preocupo com “contextos” e configurações na hora de pensar em pacotes.
    Por exemplo, tendo pacotes de “negocio”, “web” e “modelo” fica mais simples configurar algumas coisas:

    ou para as entidades

    Já trabalhei num projeto com diversos módulos onde tive que separar bem alguns contextos (de segurança, administrativo, etc) e esse tipo de organização me ajudou, facilitou o reuso posteriormente e facilitou alguns testes.

  7. Gustavo Bitencourt 14/05/2014 at 14:08 #

    Excelente post Maurício, parabéns!

    Tive a necessidade de ver algo em prática.
    Tudo isso que você falou aparenta ser válido, mas para uma aplicação de grande porte modular dessa forma os pacotes talvez torne o entendimento para novos colaboradores no projeto um pouco confuso.

    Para eu ter uma melhor visão desses seus detalhes, terias alguma imagem de exemplo de um projeto que siga essas recomendações?

    Valeu, e parabéns!

Deixe uma resposta