Organização de pastas no React: Simplificando o caos com uma nova estrutura 🚀
Tags: react, javascript, webdev, softwareengineering
Published: 2023-06-03 02:06:58

Salve!

No mundo da engenharia de software, existe um ditado que é mais ou menos assim "organização de pastas é diferente de arquitetura de software", entendo isso, mas mesmo assim, gosto de estudar diferentes estruturas e entender suas vantagens e desafios.

Então, vou compartilhar com vocês a forma que tenho organizado as pastas nos meus projetos React recentemente. 

## Algumas contextualizações
Eu venho de um passado com fortes influências do C# (.NET), onde o padrão, ao menos naquela época (2016-2018), sempre foi MVC (Model-View-Controller). Inquestionável em qualquer projeto, onde a aplicação era separada em 3 camadas:

Model - Objetos que seriam armazenados no banco de dados, hoje em dia conhecidos como _Entidades_.

View - _Classes_ visuais da aplicação, nela ficavam formulários, páginas de login, página inicial, tudo que fosse visual, era a porta de entrada que apresentava os componentes e dados para os usuários, se conectava a um Controller e fazia uso de objetos (_Models_, ou na arquitetura MVVM _ViewModels_) de dados.

Controller - Meio de campo das aplicações, cuidava das validações, regras de negócio, acessava banco de dados, parseava Model, redirecionava para _Views_ e, bem, controlava a aplicação.

## Organização em pastas por tipo
Cada pasta armazenava arquivos de uma determinada camada. Com o tempo, criou-se também a camada de _Services_ e, dependendo do _Design Pattern_, _Repositories_.

Nessa arquitetura, os arquivos eram separados por tipo, ficando com uma estrutura mais ou menos assim.

```
src/
  controllers/
    LoginController
    UserController
  models/
    LoginModel
    UserModel
  services/
    LoginService
    UserService
  views/
    LoginView
    UserProfileView
```

Ao migrar para o React em 2018, encontrei um componente "reativo" construído à base de classes.

Com muitos 
- `this`
- `bind`
- `constructor`
- `this.setState({ ...this.state, count: this.state.count + 1 })`

Decidi que usaria "MVC" no React.

```
components/
  LoginForm.js
models/
  User.js
services/
  userProfile.js
views/
  UserProfile.jsx
```

### Vantagens
É fácil decidir onde criar qualquer arquivo.

Se é uma página, você cria dentro de _views_, se faz parte da integração da _UI_ com a _API_, é um _service_. 

Caso seja um objeto, guardo dentro de _models_ e se for algum componente compartilhado, dentro de _components_.

### Desafios
Com o tempo, o tamanho das pastas cresce bastante!

Com React, é comum (e recomendado) ter muitos componentes.

> A UI é composta de várias partes móveis, de diversos tamanhos, que são flexíveis, estilizáveis e, sobretudo, componentizáveis.

Com isso, fica difícil de encontrar arquivos, pior ainda de encontrar funções, você precisa procurar dentro de uma pasta enorme, comparando-os.

Mas o maior problema é que agora, para cada nova funcionalidade, você precisa criar X novos arquivos que ficarão espalhados em diferentes pastas, fica difícil de encontrá-los e, caso a aplicação não possua uma boa cobertura de testes unitários, mais difícil ainda de fazer mudanças.

## Organização em pastas por funcionalidade
Para resolver isso, a estrutura de pastas foi reinventada em [artigos](https://medium.com/front-end-weekly/structuring-react-and-redux-applications-255361d24f84) e [discussões](https://softwareengineering.stackexchange.com/questions/338597/folder-by-type-or-folder-by-feature).

Ela sugere que a aplicação deve ser quebrada não mais em tipos, mas agrupada por "funcionalidades" do sistema.

Ela segue a seguinte filosofia
> Apagar uma funcionalidade deve ser tão fácil quanto apagar uma pasta.

### Vantagens
Os arquivos ficam mais organizados, todos arquivos dentro de uma pasta estão diretamente conectados, é fácil de navegar pela estrutura **modular** de `features`.

```
components/
  button/
  input/
features/
  authentication/
    Login.js
    LoginForm.js
    useAuth.js
    AuthService.js    
    AuthSlice.js
  profile/
    Profile.js
    UserProfile.js
    ProfileService.js
```

### Desafios
Arquivos compartilhados.
- Componentes não globais
- Interfaces
- Hooks

Arquivos compartilhados são um problema na estrutura de `features` porque é difícil decidir onde um arquivo deve morar, caso ele seja compartilhado por mais de uma funcionalidade, mas não seja algo global.

Caso exista um componente `UserAvatar` compartilhado pelas duas features, se optarmos por colocá-lo na pasta de `components`, isso significa que com o passar do tempo, essa pasta abrigará todos os componentes não-privados da aplicação.

E ficará grande e, mais uma vez, será difícil de encontrar relação entre os componentes.

Cada nova pasta que você criar, com o tempo, se for uma aplicação grande, vai crescer e se tornar desorganizada, pois serão **pastas  por tipo**.

Além de que, caso você possua _UserProfile_, _UserSettings_ e outras funcionalidades relacionadas a Usuário, elas também não ficarão agrupadas, mas soltas em diferentes partes da aplicação. 

Ou seja, caso você queira deletar tudo relacionado à usuário na aplicação, você não conseguirá fazer isso apagando **apenas uma** pasta.


```
components/
  userAvatar/
features/
  profile/
    Profile.js
    UserProfile.js
    ProfileService.js
  settings/
    Settings.js
    UserSettings.js
```

## Proposta para solucionar os problemas
Depois de alguns anos e muitos projetos, debates e discussões, decidi propor uma abordagem híbrida de folder-by-feature-by-type, ou melhor, pasta-por-funcionalidade-por-tipo, e adicionar uma nova pasta para arquivos globais.

Percebi também que `features` acabava sendo um limitante excludente para partes da aplicação que, embora funcionais, nem sempre são **entidades** macro.

Resolvi adicionar um novo conceito (muito famoso e em alta no BackEnd) para a organização de pastas, o **domínio**.

## Estrutura Pasta-Por-Domínio-Por-Tipo
Percebi que agrupar items por **tipo** resulta em uma grande quantidade de arquivos em uma mesma pasta e que isso resulta em quebra de agrupamento por proximidade.

Logo, sugiro que em níveis mais altos da aplicação, seja seguida uma estratégia de **pasta-por-domínio**, onde o domínio é uma seção da aplicação que representa uma **entidade** ou **funcionalidade**, visando evitar o acúmulo de arquivos "precoce" que, eventualmente, poluirão a estrutura de pastas.

E em níveis menores, **apenas quando necessário**, utilizar a abordagem **pasta-por-tipo**.

```
assets/
domains/
  /user
    /components
      UserAvatar.js
    /enums
    /features
      /profile
      /settings
    /types
    /hooks
global/
  /components
  /enums
  /hooks
  /routes
  /store
  /types
```

### Quando não é necessário
Quando há apenas 1 arquivo de determinado tipo em uma pasta, por exemplo:

```
domains/
  /user
    UserAvatar.js
    /features
      /profile
        UserProfile.js
        ProfileService.js
``` 
Eu defendo que, caso a pasta conte com menos de 2 arquivos de um determinado tipo, como por exemplo `UserAvatar.js`, **não precisa** criar uma pasta por tipo para abrigar 1 único arquivo.

Neste caso, até a pasta `domains` seria desnecessária enquanto não houvesse um segundo domínio para a aplicação, ficando assim:

```
src/
  user/
    UserAvatar.js
    features/
      /profile
        UserProfile.js
        ProfileService.js
```

A ideia dessa estratégia é ser fluída e utilizar o melhor dos dois mundos.

- Organização por tipo, quando uma pasta ajuda a "agrupar" dois arquivos do mesmo tipo.
- Organização por **domínio** nos níveis altos, para promover uma rápida movimentação entre seções da aplicação.

Comparar/Navegar por pastas é mais fácil do que comparar arquivos.

### Quando criar uma pasta-por-tipo

Quando uma pasta abriga dois arquivos do mesmo tipo.

Esse número é uma sugestão, caso você queira mudar para 3, a fim de reduzir o número de pastas, é uma opção também.

Por exemplo, se o domínio user começar a incluir um grande número de hooks, como useUser.js, useUserPreferences.js, useUserSettings.js, etc., seria útil criar uma pasta hooks para manter todos esses arquivos relacionados juntos:

```
domains/
  /user
    /components
      UserAvatar.js
      UserBadge.js
    /hooks
      useUser.js
      useUserPreferences.js
      useUserSettings.js
    /features
      /profile
        UserProfile.js
        ProfileService.js

```
Neste caso, a nova pasta ajuda a manter a estrutura do diretório clara e organizada, facilitando a localização dos arquivos relevantes quando necessário e permitindo minimizar (com a ajuda do IDE) seções ou tipos que não sejam interessantes para sua busca.

## Conclusão
A estratégia proposta de pasta-por-domínio-por-tipo é um método híbrido visando equilibrar os benefícios das abordagens pasta-por-tipo e pasta-por-funcionalidade. 

Com ela, a aplicação é dividida em domínios que representam entidades ou funcionalidades, e cada domínio é subdividido por tipo apenas quando necessário.

A flexibilidade deste modelo permite ajustes baseados nas necessidades específicas do projeto e da equipe.

A organização de pastas e arquivos é uma arte, e espero que esta proposta possa te inspirar a encontrar a estratégia ideal para os seus projetos. 

Independentemente da estratégia escolhida, lembre-se que o objetivo final é sempre tornar o código mais legível, navegável e fácil de manter.