E Ottaviani Aragão Blog Projetos Sobre Mim

Arquitetura e Camadas de abstração — Uma proposta para Front End — Parte 3 — Estrutura de pastas

Folders by Viktor Talashuk —unsplash.com

Nos posts anteriores eu tentei detalhar e especificar cada uma das abstrações para que faça sentido na hora da implementação, saber em qual contexto a sua feature deveria se encaixar.

Agora é hora dos detalhes da tecnologia e de estrutura de pastas, coisas que deixei para o final, indo na linha de raciocínio do Uncle Bob, quando ele diz que você deve postergar ao máximo os detalhes de implementação na sua arquitetura no contexto do conceito de Clean Architecture.

Estrutura de Pastas

Eu concordo com muitos que dizem que arquitetura não diz respeito à estrutura de pastas, porém não acredito que essa parte esteja completamente disconectada do conceito, eu acho muito improvável, por melhor que seja a arquitetura, funcionar bem um sistema onde todos os arquivos estão jogados em apenas uma pasta.

Isso para mim significa, que um depende do outro. É claro que usei um caso muito extremo, mas já me deparei com situações onde independentemente da arquitetura, se o projeto não estava bem organizado na sua estrutura de pastas a manutenção também se tornava morosa, e nesse caso fica difícil para quem está dando manutenção dizer se o problema é a arquitetura ou a organização dos arquivos.

Usando alguns elementos que observei no DDD e logicamente tentando revisitar esses conceitos de maneira prática e talvez até subvertendo alguns, percebi que estes elementos se encaixavam bem nesta arquitetura, o conceito de domínio e use cases me pareceram muito interessantes.

Pastas de Domínio — Pages

Independentemente de considerarmos ou abstrairmos os sistemas web como aplicações (apps) no final ele é percebido pelo usuário final como páginas e muitas vezes nos diagramas e nos protótipos "layoutados" tudo são páginas e esse é o contexto principal da aplicação pra mim, então:

├── src/
│ └── pages/
│ ├── home
│ ├── catalog
│ ├── pdp
│ ├── cart
│ └── checkout

Trazendo para o contexto do front end são nossos domínios. Uma página tem um princípio e um propósito. Pense em um e-commerce, a home serve como um ponto de entrada para seu usuário, lá podem estar as chamadas principais para engajar o seu usuário, com promoções, sugestões etc. Este é um propósito especifico e assim segue sucessivamente paras as demais páginas: Página de detalhe de produto ( PDP ), página de pagamento, carrinho, etc.

Se cada uma delas representa um domínio ( lembrando aos mais puritanos que estou trazendo para o contexto do front end ), todas as abstrações da nossa arquitetura deveriam estar sendo representadas em cada uma dessas páginas, então:

src/
└── pages/
└── home/
├── components/
├── services/
├── entities/
├── use-cases/
├── index.js
└── index.scss

O index.js e o index.scss são os entrypoints da página Home. No final das contas, cada página tem o seu conjunto de definições CSS e conjunto de definições em Javascript. O resto são as abstrações que foram mencionadas nos posts anteriores.

Então se cada pasta vai conter esse conjunto de abstrações e você deve estar se perguntando…

tá… mas e as coisas gerais da aplicação? Desta forma você está definindo que tudo vai ser específico, mas na prática, temos várias coisas que são compartilhados, como serviços por exemplo…

Pasta de Compartilhamento — Shared

Você tem toda a razão! Mas é super fácil resolver isso, na minha concepção basta criar uma pasta cujo o propósito seja ter essa característica de compartilhar abstrações.

src/
├── pages/
│ └── home/
└── shared/
├── components/
├── services/
├── entities/
├── use-cases/
├── utils/
├── store/
├── main.js
└── main.scss

Ela tem o shape de uma pasta de uma página comum com algumas pastas extras de compartilhamento, possuindo também alguns arquivos de configurações e definições em sua raiz que nesse exemplo chamei de main . Agora, todas as páginas podem referenciar nos seus imports a pasta shared quando precisarem importar algo de propósito geral.

A grande vantagem de se separar as pastas nesse formato é que tudo o que é específico você deveria criar para a página que está desenvolvendo, isso te dá uma visibilidade maior sobre o que é específico e o que está sendo reaproveitado no projeto, refactories ou mesmo a remoção de uma página pode ser feitos sem a preocupação de afetar outras áreas, além de te poupar um trabalho moroso de sair buscando referências desta página no projeto inteiro quando esta página sair do ar.

Um detalhe importante a se notar, por uma questão de bom senso, a pasta utils só vai aparecer em shared e não em cada página, porque geralmente são itens de propósitos muito genéricos e de interesses externos ao contexto de páginas. Usar o bom senso é importante porque: padrão sem questionamento vira burocracia.

Uma coisa que talvez seja novo aqui é a pasta use-cases e aqui eu colocaria todas as definições ( actions, reducers se você usa redux ) de ações de seu sistema que podem aparecer em mais de uma página e que serão centralizadas em uma store. Eu só consegui ver sentido a definição de use-cases no contexto de regras de negócio / regras de aplicação dentro de uma store que pode inclusive ser testada fácilmente, pois terá todas as transições dos estados do seu sistema. Lembrando que queremos um sistema com apenas 1 store, então esta também aparecerá de forma compartilhada e portanto dentro de shared.

Pasta de Identidade Visual — UI-system

Faltava a nossa última abstração, que tem como principal foco exportar para o nosso sistema as configurações de elementos visuais que darão todo o aspecto e identidade visual do projeto, a UI System.

Você não precisa começar seu projeto logo de cara com um design system, talvez você não saiba ainda o quanto seu projeto vai crescer e é muito comum no começo que muitas definições mudem com uma frequência maior, portanto, não é vantajoso criar um design system separado pois terá de atualizá-lo de maneira muito frequente e isso fatalmente irá impactar na sua produtividade, pois agora você tem dois projetos / repositórios para gerenciar.

Fazer um split de projetos e cuidar da gestão de como fazer essas integrações e interações é custoso à curto prazo, o melhor que você faz é postergar ao máximo o momento em que tomará essa decisão de quebrar.

Isso não significa que já não possa se preparar para o futuro com baixa complexidade, basta na sua pasta de UI-System deixar todas as suas definições globais do projeto, quando precisar de um design system, basta trocar a referência dessa pasta no seu projeto para outra que talvez você integrará a partir de uma instalação via pacotenpm .

src/
├── pages/
│ └── home/
├── shared/
│ ├── components/
│ ├── services/
│ ├── entities/
│ ├── use-cases/
│ ├── utils/
│ ├── store/
│ ├── main.js
│ └── main.scss
└── ui-system/
├── /variables/
├── /colors/
├── /animations/
├── /typography
└── main.scss

Finito

Esta é a estrutura básica e inicial que pensei para refletir a arquitetura que planejei nos postas anteriores. A arquitetura no meu ponto de vista não deveria atrapalhar nas abstrações adicionais e conforme a necessidade vai aparecendo, você pode e deve ir introduzindo e criando novas pastas irmãs para ajudar na escalabilidade do seu sistema, como: imagens, downloads, icons, layouts, etc.

Se seu framework possui estruturas e abstrações próprias, eu olharia para essa organização e tentaria entender se não cabe dentro de uma pasta pré-existente, como por exemplo hooks do React, eu colocaria por exemplo, dentro de shared. Quanto menos pastas desnecessárias na raiz src melhor…

É isso… cobrimos então aqui todas as abstrações e suas devidas localizações dentro da estrutura de pastas do nosso projeto, no próximo e último post mostrarei um exemplo de implementação na prática para validar a tese.