PythonBrasil 11
          
          Matando um Monolítico Django: de Pluggable Apps aos Microservices
          
          Bernardo Fontes
          
          São José dos Campos/SP
          09 de Novembro de 2015
        
        
        
        
        
          ## Nosso Cenário
          ### Sistema para um empresa de **medicina do trabalho** realizar atendimentos de **medicina ocupacional** por todo o Brasil e fornecer uma **análise inteligente** sobre o perfil dos colaboradores de uma empresa.
        
        
            Maaaaaaas...
            Tudo começou só com uma filinha:
          
        
        
            Hoje em dia...
            
          
        
        
            ## Histórico do Projeto
            - ### + de **5 anos**
            - ### + de **10 devs** passaram
            - ### Python e **Django 1.4**
            - ### Hoje: 4 devs e **únicos Pythonistas**
            - ### Empresa com **12 devs**
        
        
            ## Histórico do Projeto
            - ### Em **Outubro de 2014**
            - ### 3 devs
            - ### 1 saindo em Dezembro
            - ### Django com **uma única aplicação**
            - ### 3k LOC de **models.py** (Banco de Dados)
            - ### ~3k LOC de **views.py** (Controllers)
            - ### ~2,5k LOC de **services.py**
        
        
            ## Menos de 50% de coverage
            
        
        
            ## Infra do Projeto
            - ### 9 filials == 9 máquinas
            - ### 1 ambiente de clientes
            - ### 1 única máquina do banco
            - ### **11 máquinas**
        
        
            ## $ fab all_hosts deploy
            
        
        
            ## Cliente
            - ### **Novos módulos** no sistema
            - ### **Melhorias** nos antigos
            - ### Correção de **bugs**
        
        
            
        
        
            ### Estudamos
            
        
        
            Estudamos
            
        
        
            ## Microservices
            Um estilo arquitetural para o desenvolvimento de **serviços enxutos** em que cada um possa ser **executado em um processo próprio** e se comunicando através de mecanismos de fácil implementação como o protocolo HTTP. Esses serviços são **construídos focando capacidades de negócio** e devem poder ser **deployados independentemente** através de um processo automatizado. A **necessidade de gestão centralizada deve ser mínima** para os serviços visando viabilizar a independência entre eles.
        
        
            ## Componentes por Serviços
            - ### Componentes: unidades de software **independentes**
            - ### Serviços: **componentes externos** com comunicação por API
        
        
            ## Foco em Capacidades do Negócio
            - ### Serviços limitados ao **contexto do problema**
            - ### Equipe precisa saber só do **contexto específico** e não mais do todo
        
        
            ## Pensamento em ~~Projeto~~ Produto
            - ### Fim da **Lei de Conway**
            - ### Domínio menor == entendimento mais simples
            - ### Entendimento mais simples == equipe responsável por **todo o serviço**
            - ### Deploy independentemente
        
        
            ## Smart Endpoints & Dumb Pipes
            - ### Foco em **coesão** e **desacoplamento**
            - ### Chamadas por métodos em memória viram **chamadas ao serviço**
            - ### HTTP >> **síncrono**
            - ### Mensageria >> **assíncrono**
        
        
            ## Governança Descentralizada
            - ### **Decisões específicas** para o microservice
            - ### **Right tool** for the job
            - ### **Independência** no processo de desenvolvimento da equipe
        
        
            ## Armazenamento de Dados Descentralizados
            - ### Dados sendo visualizados de **acordo com o contexto**
            - ### **Perde-se** a gestão de transações automática
        
        
            ## Design orientado a Falhas
            - ### **Falhas de comunicação** são sempre reais
            - ### A comunicação deve ser sempre **desenvolvida pensando o cenário de falha**
            - ### Código **mais estável**
        
        
            ## Conclusões do que poderíamos
            - ### Desenvolver em **outras tecnologias**
            - ### Ter rotinas de **deploy mais simples**
            - ### Envolver **mais devs** no projeto
            - ### Entregar **mais rápido**
            - ### Gerar software de **maior qualidade**
            - ### Focar em entregar **mais valor** para o cliente
        
        
            ## Nossa reação
            
        
        
            ## E começamos...
            - 
        
        
            ## Trade-offs que Encontramos
            - ### Aumento da **complexidade operacional**
              - ### Ambiente de dev mais burocrático (resolvemos com o Docker)
              - ### Diferentes processos de deploy
            - ### Problemas para garantir a **consistência dos dados**
            - ### Todos os overheads de **comunicação em sistemas distribuídos**
        
        
            ## Killer Problems
            - ### Nossas regras de negócios estavam **completamente acopladas** entre os módulos services.py, models.py e views.py
            - ### A **modelagem acoplada** do nosso banco de dados
            - ### Impossível de mudar
            - ### Todos esses problemas foram refletidos pros novos serviços
        
        
            
        
        
            
        
        
            ## Solução
            - 
        
        
            ## *"É preciso **tirar o legado da cabeça**"*
            - Isaac Souza
        
        
            Então estudamos mais...
            
            
        
        
            ## Focos no Mindset
            - ### Definição dos **Bounded Context** dos serviços
            - ### Utilização de **Domain Objects** na implementação
            - ### Criação de **Use Cases** orquestrando a troca de mensagem entre os objetos
            - ### Implementação de **Anti-Corruption Layer** nos serviços
        
        
            ## Implementação em Etapas
        
        
            ## 1º Caso: Isolar lógica de um domínio (sem microservice)
            - Objetivo: **aprender a isolar a lógica**
            - Modelos de dados continuaram no legado
            - Nova aplicação interna somente lidando com um tipo de atendimento
            - Já existiam testes
            - Migramos os controllers, services, rotas e testes isolando a app
            - Ponto de acoplamento: import dos models do legado
        
        
        
            ## 2º Caso: Nova funcionalidade com baixo acoplamento (sem microservice)
            - Objetivo: aprender a **organizar o código** para ser **consumido por clientes externos**
            - Modelos, controllers, services e urls próprios em nova app
            - Utilização de eventos para não mexer no meio legado
            - Integração através de import em listeners no legado
            - Ponto de acoplamento: único import para o model legado de Paciente
        
        
        
            ## 3º Caso: Autenticação como Microservice
            - Objetivo: validar **participação de outros devs** no projeto
            - App SSO em Sinatra (Ruby)
            - **Todo** o ambiente isolado
            - No legado mudamos a fina camada autenticação
        
        
        
            ## 4º Caso: Nova funcionalidade agnóstica (microservice interno)
            - Objetivo: ser possível **deployar isoladamente** no futuro
            - App plugável do Django
            - Criação de UC para encapsular orquestração de domínio
            - Integração através de disparo de mensagens via RabbitMq
            - Modelos sem semântica alguma do domínio do legado
            - Banco de dados próprio (máquina própria pro banco)
        
        
        
            ## 5º Caso: Nova Aplicação em Microservice
            - Objetivo: implementar **microservices por completo**
            - App Flask de ambiente isolado
            - Utilização de comunicação por RabbitMq **e** API Rest
            - Tivemos que desenvolver uma API para expor o legado
        
        
        
            ## 6º Caso (atual): Kill the Legacy!
            - Guideline de arquitetura 1: ter o **domínio isolado** em libs
            - Guideline de arquitetura 2: **atrasar** decisões
        
        
        
        
            ## Conclusões
            - ### Tem **muitos** trade-offs para serem pensados
            - ### Não usamos microservices para tudo
               - ### Foco em **modularização**
            - ### Diminuímos o **tempo de entrega**
            - ### Diminuímos a **barreira de entrada** no projeto
        
        
            ## Conclusões
            - ### Aumentamos o **nível técnico** da equipe
            - ### **Monitoramento efetivo** é muito importante
            - ### **Logs** são nossos melhores amigos
            - ### Qualquer operação feita 2 vezes, deve ser automatizada