The Twelve-Factor App

X. Parità tra Sviluppo e Produzione

Mantieni lo sviluppo, staging e produzione simili il più possibile

Storicamente, ci sono sempre state differenze sostanziali tra gli ambienti di sviluppo (lo sviluppatore che effettua delle modifiche live ad un deploy in locale) e quello di produzione (un deploy in esecuzione raggiungibile dagli utenti finali). Differenze (o gap) che si possono raggruppare in tre categorie:

Un’applicazione twelve-factor è progettata per il rilascio continuo, tenendo così queste differenze al minimo possibile. A proposito di queste tre tipologie di differenze appena viste:

Riassumendo tutto in una tabella:

Maruku could not parse this XML/HTML: 
<table>
  <tr>
    <th></th>
    <th>App Tradizionale</th>
    <th>App Twelve-factor</th>
  </tr>
  <tr>
    <th>Tempo tra i Deploy</th>
    <td>Settimane</td>
    <td>Ore</td>
  </tr>
  <tr>
    <th>Sviluppatori e Ops</th>
    <td>Sono diversi</td>
    <td>Sono gli stessi/td>
  

Sviluppo e Produzione Divergenti Il più simili possibile

I backing service, come il database dell’applicazione o la cache, sono una delle aree in cui la parità degli ambienti è molto importante. Molti linguaggi offrono delle librerie che facilitano l’accesso a questi servizi, tra cui anche degli adattatori per questi tipi di servizi. Eccone alcuni:

Tipologia Linguaggio Libreria Adattatore
Database Ruby/Rails ActiveRecord MySQL, PostgreSQL, SQLite
Code Python/Django Celery RabbitMQ, Beanstalkd, Redis
Cache Ruby/Rails ActiveSupport::Cache Memory, filesystem, Memcached

Gli sviluppatori, inoltre, trovano utile usare dei servizi “leggeri” in fase di sviluppo, passando quindi a qualcosa di più serio e robusto in produzione. Ad esempio, usando SQLite localmente e PostgreSQL in produzone. Ancora, un sistema di cache in locale in fase di sviluppo e Memcached in produzione.

Lo sviluppatore twelve-factor “resiste” a questa necessità, anche se gli adapter ci sono e funzionano in modo tale da astrarre in modo sufficiente tutte le differenze nella gestione. Nulla impedisce, infatti, a qualche altra incompatibilità di uscire allo scoperto quando meno ce lo si aspetta, soprattutto se in ambiente di sviluppo funziona tutto e poi, magari, in produzione i test non vengono superati. Il costo di questa differenza può risultare abbastanza alto, soprattutto in situazioni in cui si effettua il rilascio continuo.

Rispetto al passato, usare dei sistemi “light” in locale è una prassi poco convincente. Si pensi al fatto che alcuni servizi moderni come Memcached o PostgreSQL si possono installare ed usare senza difficoltà tramite alcuni sistemi di packaging come Homebrew ed apt-get. In alternativa, esistono anche alcuni tool di provisioning come Chef e Puppet, che combinati con sistemi di ambienti virtuali come Vagrant permettono agli sviluppatori di riprodurre in locale delle macchine molto simili, se non identiche, a quelle in produzione. Ne risente quindi positivamente il costo di deploy.

Tutto questo, sia chiaro, non rende gli adapter meno utili: grazie ad essi infatti il porting verso nuovi servizi, in un secondo momento, rimane un processo indolore. Nonostante questo, comunque, rimane scontato che sarebbe buona norma usare uno stesso backing service su tutti i deploy di un’applicazione.