Essa é uma dúvida que sempre surge: como organizo meu projeto frontend? Hoje vou compartilhar como eu faço essa organização, e como pode te ajudar.
Costumo utilizar essa mesma estrutura para todo projeto frontend que eu desenvolvo, independente do framework: pode ser React, pode ser Flutter, pode ser Vue, nada disso importa, pois tudo parte do mesmo princípio básico, seguindo as boas práticas de programação: cada função é independente, com sua própria responsabilidade e o mais simples possível.
Cada coisa em seu lugar
Existem alguns modelos que costumam trabalhar com “módulos”, trazendo todos os componentes e funcionalidades para dentro de um cenário bem específico. Por mais que uma organização como essa até faça sentido, gosto de separar bem cada coisa.
Componentes são organizados como componentes, repositórios são organizados como repositórios, services são organizados como services, estilos são organizados como estilos.
Dessa forma consigo trazer uma grande independência a cada etapa do desenvolvimento, melhorando bastante o compartilhamento dessas funções, afinal, se não existe um módulo que é dono desse componente, então o componente é de todo mundo.
É um conceito que vem adaptado do Atomic Design, que já conversamos por aqui. Não só componentes, mas cada função cresce em responsabilidade conforme o que e onde é utilizado, focando ao máximo no compartilhamento de código.
Não precisa complicar demais
Levo isso para qualquer código que eu faço: todo código deve ser o mais simples possível. É claro que cuidados ainda são tomados e as boas práticas de programação continuam sendo seguidas como devem ser, mas não há necessidade de complicar demais, abstrair funções em excesso ou ter mais camadas que o necessário.
Justamente por cada função ter a sua independência e própria responsabilidade já consigo simplificar o processo bastante, e continuo aplicando isso em todas as etapas, com um código bastante objetivo até.
A Estrutura
.
├── components/
│ └── button/
│ ├── button.jsx
│ └── index.js
├── styles/
│ ├── colors.js
│ ├── fonts.js
│ └── index.js
├── usecases/
│ └── products.js
├── services/
│ └── products.jsx
├── repositories/
│ └── product.jsx
├── plugins/
│ ├── axios.js
│ └── sentry.js
├── utils/
│ ├── cpf.js
│ ├── validators.js
│ └── date.js
├── configs/
│ └── index.js
└── pages/
├── index.jsx
└── products.jsx
Organizo os componentes todos dentro de uma única pasta components
e eles são os responsáveis por montar toda a estrutura da página. Os componentes trazem muita informação de estilos, também organizados em uma única pasta styles
, assim consigo ter um estilo “global”, e quando alterado todos recebem a mesma atualização. Os componentes são todos agrupados, em uma etapa final, como uma página, e por isso, um diretório pages
para organizar todas as páginas da aplicação.
Ainda nos componentes, estes não trazem função alguma, exceto se seja referente ao próprio componente —por exemplo, uma alteração de estado singular a este componente, mas todas as “integrações” com outras funcionalidades da aplicação vem de um “use case”.
Crio esses use cases justamente para realizar as integrações de acordo com seu próprio contexto. Por exemplo, em um e-commerce, um use case de produtos que traz todas as funções e informações referentes aos produtos: listagem, filtro, etc. A função de um use case, é apenas “agrupar” as funcionalidades que vem dos services
, repositories
ou plugins
da aplicação. Em React, costumo até criar como um “hook”, assim tenho acesso a todas funcionalidades do React e o código fica bem mais limpo.
Dito isso, um use case é o responsável por se comunicar com os services
, que trazem de fato as funções da aplicação: a aplicação de um filtro, o gerenciamento de um local storage, a comunicação com um store e a interação com os repositories
. Algo bem comum é uma função no service interagir com um repository, responsável por fazer as chamadas as APIs, e essa mesma função armazenar a resposta em uma store para posteriormente ser utilizada em um use case. Um service também interage com os plugins
, funções e pacotes externas a nossa aplicação. Os plug-ins contém todas as funções que usam estes pacotes, construídos de forma que estes pacotes e funções possam ser abstraidas e utilizadas segundo o nosso contexto — abrindo espaço também para facilitar futuras mudanças e atualizações, algo que vem lá do
É sempre bom também ter uma pasta utils
para funções de utilidades, bem genéricas como uma validação de CPF, formatação de datas, etc. Da mesma forma, crio uma pasta para as configurações do nosso projeto como a URL base da api.
Esteja aberto a adaptações
Aqui não digo que o seu código esteja preparado para uma adaptação, mas você mesmo desenvolvedor estar preparado para adaptar essa estrutura de acordo com a sua realidade.
A depender da sua experiência, equipe e até linguagem de programação ou framework utilizado, essa estrutura pode crescer em alguma funcionalidade, ou limitada a algum recurso. Esteja preparado para isso, e lembre-se que nada em programação é uma lei e tudo pode mudar.
Para os projetos de frontend que iremos desenvolver na DevGo utilizaremos uma estrutura como essa. Participe de nosso canal no Discord, se inscreva na nossa newsletter e fique atento aos nossos próximos conteúdos.