X. Paridade entre desenvolvimento e produção

Mantenha o desenvolvimento, homologação e produção o mais similares possível

Historicamente, houveram lacunas substanciais entre desenvolvimento (um desenvolvedor editando código num deploy local do app) e produção (um deploy acessado pelos usuários finais). Essas lacunas se manifestam em três áreas:

O App doze-fatores é projetado para implantação contínua deixando a lacuna entre desenvolvimento e produção pequena. Olhando às três lacunas descritas acima:

Resumindo o acima em uma tabela:

App tradicional App doze-fatores
Tempo entre deploys Semanas Horas
Autores de código vs deployers Pessoas diferentes Mesmas pessoas
Ambientes de desenvolvimento vs produção Divergente O mais similar possível

Serviços de apoio, como o banco de dados do app, sistema de filas, ou cache, são uma área onde paridade entre desenvolvimento e produção é importante. Muitas linguagens oferecem diferentes bibliotecas que simplificam o acesso ao serviço de apoio, incluindo adaptadores para os diferentes tipos de serviços. Alguns exemplos na tabela abaixo.

Tipo Linguagem Biblioteca Adaptadores
Banco de dados Ruby/Rails ActiveRecord MySQL, PostgreSQL, SQLite
Fila Python/Django Celery RabbitMQ, Beanstalkd, Redis
Cache Ruby/Rails ActiveSupport::Cache Memory, sistema de arquivos, Memcached

Desenvolvedores as vezes veem uma grande vantagem em usar um serviço de apoio leve em seus ambientes, enquanto um serviço de apoio mais sério e robusto seria usado em produção. Por exemplo, usando SQLite localmente e PostgreSQL em produção; ou memória de processo local para caching em desenvolvimento e Memcached em produção.

O desenvolvedor doze-fatores resiste a tentação de usar diferentes serviços de apoio entre desenvolvimento e produção, mesmo quando adaptadores teoricamente abstraem as diferenças dos serviços de apoio. Diferenças entre serviços de apoio significam que pequenas incompatibilidades aparecerão, fazendo com que código que funcionava e passava em desenvolvimento ou homologação, falhe em produção. Tais tipos de erros criam fricção que desincentivam deploy contínuo. O custo dessa fricção e do subsequente decaimento de deploy contínuo é extremamente alto quando considerado que vai acumular no tempo de vida da aplicação.

Serviços locais leves são menos tentadores que já foram um dia. Serviços de apoio modernos tais como Memcached, PostgreSQL, e RabbitMQ não são difíceis de instalar e rodam graças a sistemas modernos de empacotamento tais como Homebrew e apt-get. Alternativamente, ferramentas de provisionamento declarativo tais como Chef e Puppet combinado com ambientes virtuais leves como Vagrant permitem desenvolvedores rodar ambientes locais que são bem próximos dos ambientes de produção. O custo de instalar e usar esses sistemas é baixo comparado ao benefício de ter a paridade entre desenvolvimento, produção e deploy contínuo.

Adaptadores para diferentes serviços de apoio ainda são úteis, pois eles fazem a portabilidade para novos serviços de apoio relativamente tranquilas. Mas todos os deploys do app (ambientes de desenvolvimento, homologação, produção) devem usar o mesmo tipo e versão de cada serviço de apoio.