Os 12 fatores para um projeto web de excelência
Tags: architecture, beginners, webdev, devops
Published: 2022-06-11 02:41:51


## O que são os 12 fatores para um projeto web de excelência

Em projetos web, é comum um desenvolvedor novato (ou até mesmo experiente) acabe tendo dúvidas a respeito de como planejar a arquitetura de um software, muitas vezes por não conhecer todos os processos disponíveis como também por vícios de aprendizado que o acompanham na sua experiência profissional. Os _12 fatores_ trata dos requisitos mínimos necessários para que uma aplicação web seja compatível com escalonamento horizontal. Isto é, caso um sistema cumpra tais fatores, ele está minimamente compatível com um escalonamento eficiente, e caso não esteja, dificilmente será compativel com tal atividade de maneira funcional. Os _12 fatores_ foi proposto por [Adam Wiggins](https://adamwiggins.com/), cofundador do [Heroku](https://www.heroku.com/) e seu artigo a respeito dos [12 fatores](https://12factor.net/) (_referência direta para a criação deste artigo_) necessários em aplicações web é bem difundido e serve muito bem como referência e base de estudos para os interessados no processo.

## Vantagens da metodologia

Tal metodologia pode ser aplicada para qualquer sistema web, em qualquer linguagem e utilizando qualquer framework. Os principais motivos para se aplicar os 12 fatores em uma aplicação web são:

- Automatizar a configuração inicial do projeto, facilitando o ingresso de novos desenvolvedores nos projetos;
- Garantir a portabilidade do software em diversos sistemas operacionais, isto é, gerenciar todas as dependências de forma que não dependa diretamente de nenhum SO;
- Minimizar o esforço de implementação e manutenção de sistemas hospedados em serviços em nuvem, reduzindo o custo de administração dos sistemas;
- Promover o deploy contínuo da aplicação, evitando o acumulo de modificações e a necessidade de atualizações fora de expediente. Todo o processo de deploy ocorre de tal maneira que pode ser executado continuamente e sem prejudicar o ambiente de produção;
- Garantir a escalabilidade eficiente do sistema, sem perda de dados, e sem necessitar de modificações na arquitetura do sistema.

## Os doze fatores

### Base de código

Todo o código fonte de uma aplicação **DEVE** estar em uma ferramenta de versionamento de código, o que na prática nos tempos modernos convergem para a tecnologia mais eficiente, o **GIT**. Seja no github, ou gitlab, azure devops ou qualquer outra ferramenta que utilize o git, o sistema deve estar disponível sempre em um _repo_ externo. Seja em um único repositório com todo o sistema ou em vários (neste caso, um sistema distribuído), o importante é que todos os desenvolvedores tenham uma cópia dessa aplicação e que façam deploy frequentemente na mesma, de modo que os outros desenvolvedores tenham acesso a aquilo que foi feito. Também não se deve ter 2 aplicações utilizando a mesma base de código, nesse caso, deve-se disponibilizar _libs_ para que ambos os sistemas possam utilizá-la por meio de gerenciamento de dependências.

![git](https://upload.wikimedia.org/wikipedia/commons/e/e0/Git-logo.svg)

### Dependências

Uma aplicação não deve confiar na existência implícita de pacotes no sistema, isto é, toda e qualquer dependência do sistema deve estar no seu _manifesto de dependências_. Um bom exemplo de tal arquivo seria o _package.json_ do Nodejs, onde o mesmo deve conter todas as dependências do sistema, de forma que quando um novo desenvolvedor deve ser capaz de configurar todo o sistema apenas com o arquivo de manifesto com um _npm install_ no diretório do mesmo. Isso garante também que o sistema poderá ser executado nos mais diversos sistemas operacionais.

### Configuração

Na configuração, é comum (e esperado) que os mais diversos ambientes (desenvolvimento, homologação, produção, entre outros) tenham diferentes _configurações_, como nomes de host, credenciais de acesso, configurações dos bancos de dados, etc. Deve-se garantir a **separação de código e configuração**. Um bom exemplo de tal prática são os arquivos **.env**, que armazenam as variáveis de ambientes e permitem a correta conexão dos ambientes de dev, homolog e pro, além das credenciais do banco de dados, sem que nada esteja diretamente escrito no código. Uma boa prova de fogo de tal conceito é validar se o código poderia ser exposto ao público sem comprometer nenhuma variável sensível. Os arquivos que armazenam _env vars_ devem ser ignorados pelo versionamento do git.

### Serviço de apoio

Todos os serviços de apoio da aplicação (bancos de dados como MYSQL ou MONGODB), serviços de mensageria como RabbitMQ, entre outros, devem ser consumidos como se fossem aplicações externas, acessados por meio de URLs ou outra forma de localização e credenciamento. Deve-se ser possível trocar de um banco de dados próprio por um serviço de terceiros (como o RDS da amazon) sem que qualquer alteração de código seja feita, apenas trocando as credenciais de acesso dos mesmos. Um bom método para identificar o cumprimento desse passo é transformar todos os elementos da aplicação em containers, já que os mesmos devem se comunicar como serviços externos. 

![External services](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fiuxt0bwvme20gesk87e.png)

### Build, release, run

Um deploy em uma aplicação se dá em 3 estágios:

- **Build**, que é onde o repositório é convertido em uma imagem (semelhante ao que o Docker faz ao criar imagens), onde o mesmo obtêm todas as dependências do projeto;
- **Release**, que é onde o build é enviado a um servidor e é obtido todas as configurações necessárias para a execução;
- **Run**, que é a inicialização de todos os processos para a disponibilização dos serviços para os usuários.

![build release run](https://12factor.net/images/release.png)

A metodologia de 12 fatores dita que tais estágios devem ser totalmente separados, impedindo a alteração de códigos em produção, já que seria impossível propagar tais mudanças aos estágios anteriores de build e release. Toda alteração deve ser feita inicialmente no repositório para por fim ter seu processo de build, release e run. A maioria das ferramentas de deploy oferecem mecanismos para gestão de lançamentos, bem como para retorno a *builds* anteriores estáveis em caso de problemas em produção

### Processos

A aplicação web deve obrigatoriamente ser **stateless**, isto é, sem estado. A mesma não deve armazenar nenhum dado que precise ser persistente na aplicação. Na prática, todo dado que trafega na mesma deve ser tratado como um *cache* temporário. Um bom exeplo disto seria uma aplicação rodando em um container Docker que armazena seus uploads em uma pasta dentro do próprio sistema chamada *uplodas*, onde basta o container ter qualquer problema e ser desativado que todos os uploads feitos na aplicação serão perdidos. Tais dados deveriam estar armazenadosem algum serviço de cloud de armazenamento de arquivos (AWS S3, Google Cloud Storage) ou até mesmo em um *volume persistente*, desde que fora do container, ou no caso de dados em algum banco de dados (MYSQL, MONGODB, entre outros),  O container acessa qualquer destes serviços sem armazená-lo em sua build, garantindo que o mesmo será *read only*.

![persistent volume](https://docs.docker.com/storage/images/types-of-mounts.png)

### Vínculo de portas

Como regra, toda aplicação web deve exportar o HTTP como um serviço através de uma porta, e escutar as requisições que chegam na mesma. Tal aplicação terá poder de servir outro app ou receber requisições por meio dessas portas sem a necessidade de um serviço como o NGINX ou o Apache, apesar da utilização dos mesmos nos sistemas para a configuração de *virtual hosts*.

### Concorrência 

A aplicação deve ser compatível com escalonamento horizontal. Como consequência dos fatores anteriores, a aplicação web deve ser independente de qualquer estado do sistema operacional e é organizado como builds, é possível escalar o sistema de forma que mais de uma aplicação em paralelo possa receber processos e dividir o trabalho executado, geralmente por meio de um *load balancer*.

![load balancer](https://www.cloud4u.com/upload/medialibrary/5a6/0_CCK15OF3DizmOITk.png)

### Descartabilidade

Para facilitar o escalonamento, aumentar a velocidade de deploy e mudanças nas *configurações* e dar maior solidez no sistema, aplicações web devem ser **descartáveis**, isto é, possa ser parada ou reiniciada a qualquer momento sem qualquer perda de dados ou problema com dependências. Isso garante que o processo de deploy de uma nova release, rollback para imagens anteriores, ou a criação de novos container em caso de escalabilidade horizontal seja feita de maneira simples e prática, sem a necessidade de intervenções manuais.

### Paridade entre desenvolvimento e produção

Sistemas ineficientes geralmente detém de diferenças consideráveis entre seus ambientes, como por exemplo:

- Demoras semanais para o código do desenvolvedor chegar a produção;
- Desenvolvedores commitam o código e gerentes de projeto fazem o deploy dele;
- Diferença entre bancos de dados, sistemas operacionais entre outros fatores do ambiente de desenvolvimento para o de homologação e produção.

Em tese, deve-se manter os ambientes de desenvolvimento, homologação e produção o mais similares possível, garantindo a rapidez e eficiência e permitindo a utilização de *continuos deployment*, diminuindo muito a lacuna entre os ambientes.

![Tabela comparativa](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gj8p8022mr136p455fd7.png)

Utilizando *continuos deployment*, evita-se de ter a espera muitas vezes mensal ou semanal para fechar-se releases, para aí sim enviar para homologação ou produção. Tal metodologia permite que, ao ser enviado um commit ao repositório, o ambiente automaticamente realize uma série de testes automáticos (caso implementado), garantindo a solidez do sistema, e permitindo a configuração automática do envio de tais alterações para ambientes de homologação, que podem ser validados ou não de forma manual para serem enviados à produção.

### Logs

Logs são, em essência, um formato de texto com um evento por linha (*alguns podem ocupar mais que isso*), onde temos um fluxo de eventos sendo apresentados continuamente durante a execução de uma aplicação. Os 12 fatores dita que todos os logs de uma aplicação devem ser enviados para o **stdout**, onde os mesmos podem ser capturados e apresentados utilizando ferramentas externas via **tail**. Um bom exemplo de tal fenômeno seria uma aplicação rodando em Docker cujo qual seja possível acessar os logs do mesmo via algum serviço como o *Papertrail* e ser visualizado sem a necessidade de consumí-los diretamente do container.

### Processos Administrativos

Em aplicações web, é comum a necessidade da execução de algumas tarefas administrativas, como por exemplo rodar uma *migration* de um banco de dados, rodar scripts para execuções de tarefas rotineiras, entre outros. Em uma aplicação 12 fatores, deve-se criar um ambiente idêntico ao da aplicação, onde ao rodar os comandos necessários, as devidas alterações sejam executadas sem a necessidade das mesmas concorrerem com as requisições dos usuários comum. Tal procedimento pode ser automatizado, já que existem ferramentas para quase todos os tipos de tarefas administrativas. Um bom exemplo seria uma aplicação rodando em docker onde fosse necessáŕia alguma intervenção. Neste caso, criamos outro container docker idêntico ao original (onde o mesmo não recebe requisições, ou seja, fora do *load balancer*), executamos as devidas tarefas e após isso excluimos o mesmo, não comprometendo o funcionamento do outro Docker em produção. Eventualmente se necessário, criamos outra imagem docker com as alterações e excluimos a antiga, garantindo a continuidade do deploy e do funcionamento da aplicação.

Por fim, conclui-se que uma aplicação que atenda os 12 fatores terá uma excelente qualidade de construção, facilidade para escalar horizontalmente e simplicidade para se executar deploys. Associado a testes automatizados bem escritos, integração contínua associada a uma ferramenta baseada em git que permita builds automatizados e a execução de tais testes, com certeza tem-se um software com ótima qualidade de escrita.