Pular para o conteúdo principal

A regra de dependência

Separar o código em camadas só ajuda se cada camada usar apenas as que estão mais para dentro: se o gerador importasse o menu, ele voltaria a ficar preso ao programa. Esta página diz quem pode importar quem. O único caso em que essa regra parece impossível de cumprir fica para a próxima página.

Quem pode importar quem​

Lembrando: uma camada é um grupo de classes com o mesmo tipo de trabalho, e cada uma mora numa pasta. A tabela diz o que cada pasta guarda e de quais outras ela pode importar código; dentro da própria camada, um arquivo sempre pode importar outro.

Três nomes da tabela só ganham página própria mais adiante; por enquanto, basta isto:

  • um use case ("caso de uso") é uma operação completa do programa; aqui há uma só, gerar um labirinto e gravá-lo;
  • um repository ("repositório") é uma classe que lê ou grava arquivos;
  • uma porta é a descrição do que uma classe precisa de outra (os métodos e os tipos), sem dizer quem vai fornecer. Os nomes das classes servem só para situar: o papel de cada uma é explicado com calma em Os papéis das classes, e cada classe é construída numa parte do tutorial.
PastaO que guardaPode importar
a_maze_ing.pyo ponto de entrada, que cria e liga as peçastudo
amazeing/uiMenu: o menu, o único que lê o teclado; imprime o labirinto e o menu, e só ele e o a_maze_ing.py (que mostra a mensagem de erro final) imprimemuse_cases, services, domain, utils, errors
amazeing/servicesRenderService: o desenho do labirinto em texto coloridodomain, utils, errors, mazegen
amazeing/repositoriesFileConfigRepository, que lê o config, e FileMazeRepository, que grava o arquivo de saídadomain, utils, errors
amazeing/use_casesGenerateMaze, a operação "gerar um labirinto e gravá-lo", e MazeRepository, a sua porta (explicada na próxima página)domain, errors, mazegen
amazeing/domainos dados do programa: MazeConfig (as opções lidas), GeneratedMaze (o labirinto pronto) e ViewState (o estado da tela)utils, errors, mazegen
amazeing/utilsValueParser (converte texto em número, booleano ou coordenada) e Ansi (os códigos de cor do terminal)só a biblioteca padrão
amazeing/errors.pyAppError e as suas variações: os tipos de erro da aplicaçãosó a biblioteca padrão
mazegeno gerador reutilizávelsó a biblioteca padrão (e os próprios módulos do mazegen)

O diagrama mostra os imports que o código tem de fato. Cada seta quer dizer "importa", ou seja, "usa código de":

Toda seta do diagrama está permitida na tabela. O contrário não vale: a tabela permite um pouco mais do que o código usa. O Menu, por exemplo, poderia importar algo de utils, mas não precisa. O que a tabela proíbe, nenhuma seta faz: só a seta do a_maze_ing.py aponta para ui, nenhuma camada interna aponta para ela, e nenhuma seta sai de mazegen, utils ou errors.

A tabela e os anéis​

A regra dos anéis da primeira página desta parte diz que uma camada só importa a si mesma e anéis mais para dentro. Ela é o limite máximo. A tabela é a regra do projeto, mais restrita: ela também proíbe alguns imports para dentro que os anéis deixariam passar, cada um por um motivo.

Import que os anéis permitem e a tabela proíbeMotivo
ui → repositoriesa ui não abre arquivo: ela pede o labirinto ao use case GenerateMaze, e é ele que manda gravar
ui → mazegena ui não gera labirinto: recebe o labirinto pronto do use case, já como um objeto do domain, e o passa ao desenho
services → use_caseso desenho só transforma um labirinto pronto em texto colorido; não lê, não grava e não gera
repositories → use_cases e mazegeno repository só converte entre texto e os objetos do domain (as opções lidas, o labirinto pronto); ele encaixa na porta do use case sem importá-la, como mostra a próxima página
use_cases → utilso use case só coordena (pede o labirinto ao gerador e manda gravar); converter texto ou escolher cor não é trabalho dele
utils e errors → mazegensão peças de apoio da aplicação (conversão de texto, cores, tipos de erro) que não precisam saber nada de labirinto

Quanto menos uma camada importa, menos coisas a obrigam a mudar. Se uma dessas proibições precisar ser quebrada, é sinal de que o código está na camada errada.

Por que nessa direção​

O que está no centro muda pouco e não depende de detalhe nenhum: a regra "uma célula tem quatro paredes" vale com ou sem terminal. O que está na borda muda mais: o formato de um arquivo, as cores, o texto do menu.

Com as setas sempre apontando para dentro, uma mudança na borda nunca obriga a mexer no centro. Exemplo concreto: trocar o desenho no terminal por uma janela gráfica muda só services e ui. O mazegen e o domain nem ficam sabendo.

Como conferir​

Basta ler os import do topo de cada arquivo e comparar com a tabela. Um import que aponta para fora é um erro de arquitetura. Por exemplo, esta linha dentro de qualquer arquivo de mazegen/ estaria errada, porque o gerador passaria a depender do menu:

from amazeing.ui.menu import Menu