Aplicações Node.JS não possuem uma estrutura padrão definida, o que é uma faca de dois gumes: por um lado dá a liberdade para programadores experientes definirem a melhor estrutura para o contexto da sua app. Por outro, deixa programadores pouco experientes perdidos.

O objetivo nesse post é guiar esse segundo grupo de programadores a estruturar a sua app de uma forma que favoreça a manutenção e organização do código. Já o primeiro grupo de programadores têm a oportunidade de conhecer mais alguns boilerplates, e assim, ter mais algumas opções.

MVC Boilerplate

Para você que está começando, boilerplate pode ser um termo novo. Um boilerplate nada mais é do que algo que pode ser copiado de um contexto para outro e, ao copiar, pouco ou praticamente nada altera o original. No nosso caso, a estrutura do código é um boilerplate, já que você pode usar como base, para diferentes aplicações MVC.

O padrão MVC tem como característica principal a separação da aplicação em 3 camadas:

  • Model: é responsável por gerenciar os dados e seus comportamentos. Em geral, é onde está toda a lógica de negócio da aplicação;
  • View: a sua responsabilidade é prover a interface para o usuário. Ela irá renderizar os dados do model;
  • Controller: é responsável pela comunicação entre Model e View, e vice-versa. Nessa camada que os dados serão recebidos e depois tratados pelo model. Assim como os dados do model serão passados para a view.

Quando adotamos um padrão de arquitetura, ele guia a organização do nosso código. Alguns exemplos da influência do MVC podem ser notados em frameworks como no Sails.js.

Bem, mas se você está aqui, provavelmente não usa um framework opinativo como o Sails.js. Portanto, você é o responsável por definir a estrutura da aplicação.

Para aplicações pequenas e médias, o que é muito subjetivo, vamos considerar aplicações de até 10 entidades, o seguinte boilerplate é recomendado:

project/
  config/
    routes.js
    settings.js
    index.js
  controllers/
    index.js
    movies.js
  models/
    index.js
    movie.js
  repositories/
    index.js
    movie.js
  views/
    index.jade
    movies/
      index.jade
  tests/
    controllers/
      index.js
    models/
      index.js
    repositories/
      index.js
  index.js
  package.json

Como pode ser visto acima, a organização da aplicação é guiada por camadas e, como dissemos anteriormente, cada camada possui uma responsabilidade. Na estrutura acima, fizemos duas adições aos models, views e controllers:

  • Repositories: fazem parte da camada de Models. É onde estarão os repositórios, responsáveis por fazer a persistência e recuperação dos dados. Preferimos separar o acesso aos dados como sendo uma responsabilidade apenas do repositório, tirando assim do model tal responsabilidade;
  • Config: a pasta config é simplesmente uma forma de organização, do que uma camada da aplicação. É nela que teremos as configurações para a infra-estrutura da aplicação, como rotas e configurações como variáveis globais.

Agora, para grandes aplicações, é recomendável que a estrutura de camadas esteja dentro de cada módulo. Ou seja, iremos separar as nossas aplicações em módulos e cada módulo reflete uma entidade de negócio.

project/
  config/
    routes.js
    settings.js
    index.js
  common/
    index.js
  movies/
    routes/
      index.js
    controllers/
      index.js
      index-test.js
    models/
      index.js
      index-test.js
    repositories/
      index.js
      index-test.js
    views/
      index.jade
  views/
    layouts/
      index.js
  index.js
  package.json

Na estrutura acima, é importante observar que cada módulo é auto-sustentável, facilitando assim o trabalho de vários times na mesma aplicação.

Algumas mudanças que fizemos e valem ser comentadas:

  • Criação da pasta “common”: mesmo quando trabalhamos orientados a criar módulos que conhecem o mínimo do lado de fora, ainda há situações que valem reusarmos códigos entre diferentes módulos. São esses códigos que estarão na pasta common, como por exemplo: parsers, funções de manipulação de data, etc;
  • Adicionamos os testes para dentro de cada camada. Assim, não precisamos ficar repetindo a estrutura de camadas dentro de uma pasta “tests” e os testes ficam ao lado da implementação, facilitando o seu acesso;
  • Cada módulo expõe as suas rotas, e continuamos tendo um arquivo de rotas na pasta config, para adicionarmos na nossa aplicação;
  • Ainda temos uma pasta chamada “views”, mas agora apenas para armazenados os layouts gerais da aplicação.

API Boilerplate

Quando trabalhamos com Node.JS, costumamos criar muito mais APIs do que aplicações monolíticas.

A sua estrutura será similar a estrutura que apresentamos, com a única diferença, que não teremos mais a pasta das views. Portanto, para não nos tornamos repetitivos, lembre-se: basta remover as pastas de views para ter o boilerplate da sua API.

Lib Boilerplate

Por fim recomendamos o seguinte boilerplate para a sua lib em Node.JS:

lib/
  index.js
  mylib.js
test/
  index.js
  mylib.js
package.json

A estrutura de uma lib é bem direta. Afinal, o contexto de uma lib é menor e, assim, camadas e abstrações não são necessários. Precisamos apenas da pasta lib que irá conter a nossa implementação e a pasta test para os testes da implementação.

Conclusão

Como vimos, estruturar a nossa aplicação pode parecer algo difícil, mas, no final, a maior dificuldade é saber decidir diante de tantas opções de como estruturar uma aplicação. Por isso, é bom ter em mãos referências, como as apresentadas neste post.