SlideShare une entreprise Scribd logo
1  sur  56
Télécharger pour lire hors ligne
Construindo e mantendo
aplicações multi-tenant (multi-
cliente)
Aryel Tupinambá
PHP Conference 2015
Sobre o palestrante
Co-fundador e CTO da LQDI Digital
Projetos para empresas como Porto Seguro, Nestlé, Garoto,
Editora FTD, Tishman Speyer e Ambev
12 anos trabalhando com PHP
Desde a época que o PHPClasses era a onda :)
Aryel Tupinambá
Single tenant
- Um único "cliente" para a
aplicação
- Forma tradicional, instalada no
servidor do cliente
- Faz sentido quando a aplicação
é um PROJETO
Agora com mais um cliente… e mais outro...
- Seu PROJETO se tornou um
PRODUTO
- Diversos clientes usando a mesma
aplicação
- Estruturas separadas para cada novo
cliente
- Nada é compartilhado; tudo é isolado
E agora, como faço...
… atualizações de segurança?
… correção de bugs?
… features novas para todo mundo?
E o espaço que toda essa galera ocupa?
E o custo que tudo isso gera?
Arquitetura multi-tenant
- Tenant = inquilino
- Uma única aplicação para vários
clientes
- Uma estrutura comum entre os clientes
- As benfeitorias servem para todos
- A customização de um cliente não
interfere nos demais, nem previne que
ele utilize da estrutura comum
Principais desafios
DATA STORAGE CODEBASE CUSTOMIZAÇÃO
Como segmentar a
base de dados para
cada cliente?
Como segmentar os
arquivos enviados?
Como fica o código
fonte da aplicação?
Como ficam as
customizações?
Como lidamos com
updates e novas
features?
Como podemos
customizar as
funcionalidades da
aplicação?
Como permitir que
atualizações e novas
features não sejam
impedidas por
customizações?
Não existe escolha certa ou errada
O que existe são escolhas que fazem mais sentido para determinados cenários.
Data storage
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Cada cliente possui uma instância do seu SGDB (MySQL,
Postgres, Mongo, etc), com seus dados isolados.
Mais isolado
Mais compartilhado
Cada cliente tem um banco de dados (ou schema) diferente,
na mesma instância
Todos os clientes estão na mesma base de dados; o cliente é
identificado por meio de uma coluna nas tabelas (tenantID)
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Todos os clientes estão na mesma base de dados; o cliente é
identificado por meio de uma coluna nas tabelas (tenantID)
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Cada cliente tem um banco de dados (ou schema) diferente,
na mesma instância
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Cada cliente possui uma instância do seu SGDB (MySQL,
Postgres, Mongo, etc), com seus dados isolados.
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Sugestão de uso:
- Aplicações com pouca ou nenhuma variabilidade /
customização
- Aplicações em que a principal customização é visual
- Aplicações com alto número de usuários (500k+)
Mais isolado
Mais compartilhado
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Sugestão de uso:
- Aplicações em que deve haver maior flexibilidade para
customização
- Aplicações em que a infra-estrutura sempre será
responsabilidade sua
- Planos baseados em volume de consumo ou
performance
Mais isolado
Mais compartilhado
Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Sugestão de uso:
- Projetos em que a separação física do hardware se faz
necessária (instalações on-premises, compliance
corporativo ou governamental, decisões de
performance);
- Alta disparidade no volume de dados ou de acessos
entre clientes (quando alguns clientes consomem
demais)
- Quando você precisa monitorar o consumo individual de
hardware para cada cliente (e seu SGDB não faz isso
por database/schema)
Mais isolado
Mais compartilhado
- Em regra geral, a FLEXIBILIDADE necessária deve ser o fator decisório
- Customizar funcionalidades pode ser um desafio quando você tem um modelo de
dados fixo; alterar o modelo de dados de toda uma aplicação só para atender um
cliente / uma feature pode gerar inconsistência e dificultar a manutenção
- Use o pattern de "migrations" e "seeds" para criar e manter o database schema;
muito importante criar migrations que sejam, na medida do possível, 100%
reversíveis.
- Você não necessariamente precisa escolhar um único modelo para todos os dados
da aplicação; se sua aplicação tem interações entre os clientes mas é altamente
customizável, por exemplo, faz sentido segmentar o que faz parte do core em um
único database, e o que faz parte da customização em um database separado
Data storage
Relembrando: não existe escolha certa ou errada
Data storage: na prática
Data storage: na prática
Modelo compartilhado (via tenant ID)
Data storage: na prática
Modelo isolado (instâncias diferentes)
Codebase
Codebase
- Dois cenários: uma instância para todos, ou uma instância por tenant
app
código fonte
cliente1.app.com
cliente2.app.com
cliente3.app.com
config 1
config 2
config 3
cliente1.app.com
código fonte
config 1
cliente2.app.com
código fonte
config 2
cliente3.app.com
código fonte
config 3
custom code
Uma instância para todos
Uma instância por cliente
Codebase
- Uma instância para todos
- Atualizações são sincronizadas sem custo ou esforço
- Nenhum ou pouquíssimo "housekeeping" necessário
- Não é muito flexível para customizações
- Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante
app
código fonte
cliente1.app.com
cliente2.app.com
bigcorp.app.com
config 1
config 2
config 3
Codebase
- Uma instância para todos
- Atualizações são sincronizadas sem custo ou esforço
- Nenhum ou pouquíssimo "housekeeping" necessário
- Não é muito flexível para customizações
- Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante
app
código fonte
cliente1.app.com
cliente2.app.com
bigcorp.app.com
config 1
config 2
config 3
Nginx sitesvia DB, cachedGit repository
Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em
algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
custom code
Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em
algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
Git repo
.env files
custom code
Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em
algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
Nginx sites + PHP-FPM pools
v1.4.0 v1.4.1 v1.4.0
custom code
Codebase
- De novo, o maior fator decisório aqui deve ser a FLEXIBILIDADE: o quanto você
espera que o código da aplicação se altere com customizações de clientes?
- A escalabilidade, embora seja um desafio (e mereceria uma palestra a parte), não
deve ser dificultada em nenhum dos cenários, DESDE QUE você automatize
todos os processos e fique de olho na consistência
- Instâncias isoladas permitem que você escale clientes mais "barulhentos" (alto
volume) para hardware melhor
- Você pode também trabalhar com instâncias segmentadas por tier ou plano, e
"empacotar" menos clientes por instâncua em tiers mais elevados/caros.
Variabilidade e customização
Variabilidade e customização
- O calcanhar de aquiles da arquitetura multi-tenant
- Requer bastante meditação sobre os requisitos
- Aqui é um dos melhores lugares onde design patterns e uma arquitetura sã e
consistente brilham de verdade
- Vou falar sobre algumas técnicas e formatos interessantes
Relembrando: não existe escolha certa ou errada
Variabilidade e customização
- Para configuração:
- Para instâncias de código isoladas: um arquivo de configuração (biblioteca DotEnv)
- Para instâncias unificadas: parâmetros de configuração no banco/repositório de tenant data
.env
Variabilidade e customização
- Para o data storage:
- Migrations: funcionam como um controle
de versão do seu modelo de dados
- A maioria dos frameworks/ORMs possuem
suporte built-in (Laravel, CakePHP,
Doctrine), e há libs standalone para outros
formatos.
- Sempre criar migrations "reversíveis", ou
seja, que possam sofrer rollback
Variabilidade e customização
- Para o código / funcionalidade: EVENTS
Transação de negócio
(ex: novo pedido realizado)
Gerenciador de eventos
(via Framework, biblioteca ou
hand-made)
Envio de e-
mail para o
usuário
Registro no log
de atividade do
usuário
Sub-serviços do core app
Módulo customizado: NF-E
Geração de NF-E
Módulo customizado: Tracking
Registrar nova carga à entregar
dispatchEvent('order_created', $order);
- Para o código / funcionalidade: EVENTS
Variabilidade e customização
Transação de negócio
(ex: novo pedido realizado)
Gerenciador de eventos
(via Framework, biblioteca ou
hand-made)
Envio de e-
mail para o
usuário
Registro no log
de atividade do
usuário
Sub-serviços do core app
Módulo customizado: NF-E
Geração de NF-E
Módulo customizado: Tracking
Registrar nova carga à entregar
dispatchEvent($order);
CORE APP
CUSTOM CODE
return [
['Entregas','abc.delivery.index'],
['Configurar Frete','abc.delivery.config']
];
- Para o código / funcionalidade: HOOKS
Variabilidade e customização
Renderizar menu principal Gerenciador de hookstriggerHook('render_menu');
return [['Pedidos','core.orders.index']];
return [['Estoque','core.inventory.index']];
Módulo de Pedidos
Módulo de Estoque
Módulos do core app
Módulo de Entregas
Custom code do cliente ABC
return [...];
Variabilidade e customização
- Para o código / funcionalidade: DEPENDENCY INJECTION
Order
BillingGatewayContract
PayPalBillingGateway
implementa
DI Container
registra
recebe PayPalBillingGateway
pede BillingGatewayContract
Variabilidade e customização
- Para o código / funcionalidade: DEPENDENCY INJECTION
Order
BillingGatewayContract
PayPalBillingGateway
Core app
Order
BillingGatewayContract
PayPalBillingGateway
Core app
Order
BillingGatewayContract
PayPalBillingGateway
Core app
TENANT 1 TENANT 2 TENANT 3
PagSeguroBillingGateway
Variabilidade e customização
- Para o código / funcionalidade: DEPENDENCY INJECTION
Order
BillingGatewayContract
PayPalBillingGateway
Core app
Order
BillingGatewayContract
PayPalBillingGateway
Core app
Order
BillingGatewayContract
PayPalBillingGateway
Core app
TENANT 1 TENANT 2 TENANT 3
Custom code
Variabilidade e customização
- Para o frontend / interface:
- Dê preferência para usar uma engine de templates (Blade, Twig, etc);
Variabilidade e customização
- Para o frontend / interface:
- Use Sass ou outro pré-compilador de CSS
- Você pode gerar o config via PHP, e então rodar
o compilador (automático ou manual)
Variabilidade e customização
- Para infraestrutura / deploy:
Variabilidade e customização
- Para infraestrutura / deploy:
Variabilidade e customização
- Para infraestrutura / deploy:
http://forge.laravel.com
http://deployhq.com
http://envoyer.io
Use ferramentas ou serviços de automatização de deploy
(imagine atualizar manualmente a versão de 600 clientes)
Variabilidade e customização
- Para infraestrutura / deploy:
Use o Composer para gerenciar core
app e código customizável
Variabilidade e customização
- Para infraestrutura / deploy:
Automatize (se aplicável) o processo de provisionamento para novos clientes
Novo cliente cadastrado
Script / microservice de
PROVISIONAMENTO
Criar pasta no servidor e site no Nginx
Criar banco de dados
Gerar .env de configuração
Criar registro no DB de tenants
Cadastrar no Envoyer e realizar primeiro deploy
Gerar composer.json com Core + Custom code
Disparar e-mail para o cliente
Gerar config do Sass e compilar CSS final
Variabilidade e customização
- Para infraestrutura / deploy:
Automatize (se aplicável) o processo de provisionamento para novos clientes
Novo cliente cadastrado
Script / microservice de
PROVISIONAMENTO
Criar pasta no servidor e site no Nginx
Criar banco de dados
Gerar .env de configuração
Criar registro no DB de tenants
Cadastrar no Envoyer e realizar primeiro deploy
Gerar composer.json com Core + Custom code
Disparar e-mail para o cliente
Gerar config do Sass e compilar CSS final
Variabilidade e customização
- Para infraestrutura / deploy:
- O custo e tempo para provisionamento interfere diretamente em um KPI de negócio,
o CAC (Custo de Aquisição de Cliente)
- Provavelmente toda sua infra-estrutura pode ser administrada via API; use isso a seu favor
- Amazon EC2 e DigitalOcean tem APIs para provisionamento de servidores
- Amazon S3 e Rackspace Cloud tem APIs para criação de novos "buckets" de arquivos
- Amazon Route 51 e DigitalOcean tem APIs para gerenciar o DNS (domínios customizáveis)
TL;DR
- Oriente sua arquitetura principalmente pela sua
necessidade de flexibilidade e customização
- Mais customizável -> mais isolada
- Mais uniforme -> mais compartilhada
- Use as melhores práticas de SOLID, principalmente no
que diz respeito a Inversão de Dependência; a
arquitetura multitenant é provavelmente o melhor use-
case de substituição de implementações de uma
interface em runtime
TL;DR
- Automatize TUDO que diz respeito a provisionamento,
deploy e housekeeping de infraestrutura: manutenção
manual de instâncias é uma eterna dívida técnica que se
acumula
- TDD é PRIMORDIAL; lembre-se que em um ambiente
sincronizado, uma atualização impacta TODOS os seus
clientes
Perguntas?
A está contratando!
Procuramos desenvolvedores front-end e back-end, de TODOS os níveis de experiência,
apaixonados pelo que fazem e a fim de aprender e ensinar
Ambiente de trabalho bacana, descontraído, com remuneração competitiva, horários
flexíveis e bastante abertura para novas idéias. Sem melindres, sem preciosismo e
puxação de saco :D
Plano de carreira sólido e flexível, com espaço para crescimento em gestão e
especialização, e programas de feedback contínuo entre a equipe e os gestores.
Manda um e-mail pra work@lqdi.net e cite a palestra da PHP Conference
Ou me chame pessoalmente agora para trocarmos uma idéia
Começe 2016 de trampo novo!
Obrigado!
E-mail / Hangouts: aryel.tupinamba@lqdi.net
Facebook: http://facebook.com/aryel.tupinamba
Twitter: http://twitter.com/DfKimera
LinkedIn: http://linkedin.com/in/aryeltupinamba
Slides da palestra: http://slideshare.net/aryeltupinamba
http://lqdi.net

Contenu connexe

Tendances

Introdução à Servlets e JSP
Introdução à Servlets e JSPIntrodução à Servlets e JSP
Introdução à Servlets e JSPledsifes
 
JSP - Java Serves Pages
JSP - Java Serves PagesJSP - Java Serves Pages
JSP - Java Serves PagesAmanda Luz
 
Sqlite - Introdução
Sqlite - IntroduçãoSqlite - Introdução
Sqlite - IntroduçãoJoao Johanes
 
L'esprit de l'escalier
L'esprit de l'escalierL'esprit de l'escalier
L'esprit de l'escalierGleicon Moraes
 
Sistema S2DG e Tecnologias Web
Sistema S2DG e Tecnologias WebSistema S2DG e Tecnologias Web
Sistema S2DG e Tecnologias WebElenilson Vieira
 
Dicas para Turbinar o servidor de Aplicações JBoss 7
Dicas para Turbinar o servidor de Aplicações JBoss 7Dicas para Turbinar o servidor de Aplicações JBoss 7
Dicas para Turbinar o servidor de Aplicações JBoss 7Claudio Miranda
 
PORTUGUESE SquashBrochure
PORTUGUESE SquashBrochurePORTUGUESE SquashBrochure
PORTUGUESE SquashBrochureAndr Moura
 
Desenvolvimento web - conceitos, tecnologia e tendências.
Desenvolvimento web - conceitos, tecnologia e tendências.Desenvolvimento web - conceitos, tecnologia e tendências.
Desenvolvimento web - conceitos, tecnologia e tendências.Valmir Justo
 
Apresentação zend framework 2 parte 1
Apresentação zend framework 2   parte 1 Apresentação zend framework 2   parte 1
Apresentação zend framework 2 parte 1 Edgar Dantas
 
TDC 2017 - Borg até o Prometheus: Site Reliability Engineering
TDC 2017 - Borg até o Prometheus: Site Reliability EngineeringTDC 2017 - Borg até o Prometheus: Site Reliability Engineering
TDC 2017 - Borg até o Prometheus: Site Reliability EngineeringFelipe Klerk Signorini
 
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXF
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXFIntrodução ao JBoss Fuse 6.x: criação e implantação de um serviço CXF
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXFRafael T. C. Soares (tuelho)
 
Escalabilidade e alta disponibilidade no php com nginx
Escalabilidade e alta disponibilidade no php com nginxEscalabilidade e alta disponibilidade no php com nginx
Escalabilidade e alta disponibilidade no php com nginxSaveincloud
 

Tendances (20)

Introdução à Servlets e JSP
Introdução à Servlets e JSPIntrodução à Servlets e JSP
Introdução à Servlets e JSP
 
JSP - Java Serves Pages
JSP - Java Serves PagesJSP - Java Serves Pages
JSP - Java Serves Pages
 
Sqlite - Introdução
Sqlite - IntroduçãoSqlite - Introdução
Sqlite - Introdução
 
Entrega ebook-gratis
Entrega ebook-gratisEntrega ebook-gratis
Entrega ebook-gratis
 
Servlets e JSP
Servlets e JSPServlets e JSP
Servlets e JSP
 
Clusterização de Aplicações PHP
Clusterização de Aplicações PHPClusterização de Aplicações PHP
Clusterização de Aplicações PHP
 
L'esprit de l'escalier
L'esprit de l'escalierL'esprit de l'escalier
L'esprit de l'escalier
 
Apres s3
Apres s3 Apres s3
Apres s3
 
Performance em Java
Performance em JavaPerformance em Java
Performance em Java
 
Instalação CakePHP 2.2.3
Instalação CakePHP 2.2.3Instalação CakePHP 2.2.3
Instalação CakePHP 2.2.3
 
Sistema S2DG e Tecnologias Web
Sistema S2DG e Tecnologias WebSistema S2DG e Tecnologias Web
Sistema S2DG e Tecnologias Web
 
Dicas para Turbinar o servidor de Aplicações JBoss 7
Dicas para Turbinar o servidor de Aplicações JBoss 7Dicas para Turbinar o servidor de Aplicações JBoss 7
Dicas para Turbinar o servidor de Aplicações JBoss 7
 
PORTUGUESE SquashBrochure
PORTUGUESE SquashBrochurePORTUGUESE SquashBrochure
PORTUGUESE SquashBrochure
 
Curso asp - basico
Curso   asp - basicoCurso   asp - basico
Curso asp - basico
 
Desenvolvimento web - conceitos, tecnologia e tendências.
Desenvolvimento web - conceitos, tecnologia e tendências.Desenvolvimento web - conceitos, tecnologia e tendências.
Desenvolvimento web - conceitos, tecnologia e tendências.
 
Apresentação zend framework 2 parte 1
Apresentação zend framework 2   parte 1 Apresentação zend framework 2   parte 1
Apresentação zend framework 2 parte 1
 
TDC 2017 - Borg até o Prometheus: Site Reliability Engineering
TDC 2017 - Borg até o Prometheus: Site Reliability EngineeringTDC 2017 - Borg até o Prometheus: Site Reliability Engineering
TDC 2017 - Borg até o Prometheus: Site Reliability Engineering
 
PHP FrameWARks - CakePHP
PHP FrameWARks - CakePHPPHP FrameWARks - CakePHP
PHP FrameWARks - CakePHP
 
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXF
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXFIntrodução ao JBoss Fuse 6.x: criação e implantação de um serviço CXF
Introdução ao JBoss Fuse 6.x: criação e implantação de um serviço CXF
 
Escalabilidade e alta disponibilidade no php com nginx
Escalabilidade e alta disponibilidade no php com nginxEscalabilidade e alta disponibilidade no php com nginx
Escalabilidade e alta disponibilidade no php com nginx
 

En vedette

PHP Conference 2016: Aplicações em tempo real com o Ratchet PHP
PHP Conference 2016: Aplicações em tempo real com o Ratchet PHPPHP Conference 2016: Aplicações em tempo real com o Ratchet PHP
PHP Conference 2016: Aplicações em tempo real com o Ratchet PHPAryel Tupinambá
 
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015Innomatic Platform
 
Resolvendo problemas de customização em softwares como serviço (SaaS)
Resolvendo problemas de customização em softwares como serviço (SaaS)Resolvendo problemas de customização em softwares como serviço (SaaS)
Resolvendo problemas de customização em softwares como serviço (SaaS)André Aranha
 
Desenvolvendo aplicações web com o framework cakephp
Desenvolvendo aplicações web com o framework cakephpDesenvolvendo aplicações web com o framework cakephp
Desenvolvendo aplicações web com o framework cakephpRodrigo Aramburu
 
ASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NETASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NETEduardo Pires
 
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EE
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EEJavaOne 2014 - Supporting Multi-tenancy Applications with Java EE
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EERodrigo Cândido da Silva
 
How to build customizable multitenant web applications - IPC11 Spring Edition
How to build customizable multitenant web applications - IPC11 Spring EditionHow to build customizable multitenant web applications - IPC11 Spring Edition
How to build customizable multitenant web applications - IPC11 Spring EditionStephan Hochdörfer
 
Multi-tenancy in Java
Multi-tenancy in JavaMulti-tenancy in Java
Multi-tenancy in Javaseges
 

En vedette (9)

PHP Conference 2016: Aplicações em tempo real com o Ratchet PHP
PHP Conference 2016: Aplicações em tempo real com o Ratchet PHPPHP Conference 2016: Aplicações em tempo real com o Ratchet PHP
PHP Conference 2016: Aplicações em tempo real com o Ratchet PHP
 
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
 
Resolvendo problemas de customização em softwares como serviço (SaaS)
Resolvendo problemas de customização em softwares como serviço (SaaS)Resolvendo problemas de customização em softwares como serviço (SaaS)
Resolvendo problemas de customização em softwares como serviço (SaaS)
 
Desenvolvendo aplicações web com o framework cakephp
Desenvolvendo aplicações web com o framework cakephpDesenvolvendo aplicações web com o framework cakephp
Desenvolvendo aplicações web com o framework cakephp
 
Hackeando Dados públicos com python
Hackeando Dados públicos com pythonHackeando Dados públicos com python
Hackeando Dados públicos com python
 
ASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NETASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NET
 
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EE
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EEJavaOne 2014 - Supporting Multi-tenancy Applications with Java EE
JavaOne 2014 - Supporting Multi-tenancy Applications with Java EE
 
How to build customizable multitenant web applications - IPC11 Spring Edition
How to build customizable multitenant web applications - IPC11 Spring EditionHow to build customizable multitenant web applications - IPC11 Spring Edition
How to build customizable multitenant web applications - IPC11 Spring Edition
 
Multi-tenancy in Java
Multi-tenancy in JavaMulti-tenancy in Java
Multi-tenancy in Java
 

Similaire à PHP Conference 2015: Construindo e mantendo aplicações multi-tenant (multi-cliente)

2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER
2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER
2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MERRodrigo Kiyoshi Saito
 
Replicacao Object Sistemas
Replicacao Object SistemasReplicacao Object Sistemas
Replicacao Object Sistemastaniamaciel
 
WSO2 - Portfólio de Produtos, Soluções e Suportes
WSO2 - Portfólio de Produtos, Soluções e SuportesWSO2 - Portfólio de Produtos, Soluções e Suportes
WSO2 - Portfólio de Produtos, Soluções e SuportesEdgar Silva
 
Arquitetura cliente servidor
Arquitetura cliente servidorArquitetura cliente servidor
Arquitetura cliente servidorMarcia Abrahim
 
Iniciando com serviços de bancos de dados gerenciados na AWS
Iniciando com serviços de bancos de dados gerenciados na AWSIniciando com serviços de bancos de dados gerenciados na AWS
Iniciando com serviços de bancos de dados gerenciados na AWSAmazon Web Services LATAM
 
Joana costa tp 1 – trabalho prático www
Joana costa tp 1 – trabalho prático wwwJoana costa tp 1 – trabalho prático www
Joana costa tp 1 – trabalho prático wwwJoana Costa
 
Android Dev Conference 2017 - Entrega Contínua para Mobile
Android Dev Conference 2017 - Entrega Contínua para MobileAndroid Dev Conference 2017 - Entrega Contínua para Mobile
Android Dev Conference 2017 - Entrega Contínua para MobileiMasters
 
Aplicações de tempo real com Meteor.js
Aplicações de tempo real com Meteor.jsAplicações de tempo real com Meteor.js
Aplicações de tempo real com Meteor.jsRafael Sales
 
Microserviços - Universidade Metodista - EETI 2016
Microserviços - Universidade Metodista - EETI 2016Microserviços - Universidade Metodista - EETI 2016
Microserviços - Universidade Metodista - EETI 2016Renato Groff
 
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Dirceu Resende
 
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Dirceu Resende
 
Cakephp - framework de desenvolvimento de aplicações Web em PHP
Cakephp - framework de desenvolvimento de aplicações Web em PHPCakephp - framework de desenvolvimento de aplicações Web em PHP
Cakephp - framework de desenvolvimento de aplicações Web em PHPArlindo Santos
 
Guia essencial para embarcar o MySQL em seu produto
Guia essencial para embarcar o MySQL em seu produtoGuia essencial para embarcar o MySQL em seu produto
Guia essencial para embarcar o MySQL em seu produtoMySQL Brasil
 
Introducao banco de dados
Introducao banco de dadosIntroducao banco de dados
Introducao banco de dadosvaniakenob
 
Microsoft Azure no Licenciamento Open
Microsoft Azure no Licenciamento OpenMicrosoft Azure no Licenciamento Open
Microsoft Azure no Licenciamento OpenLucas A. Romão
 
Infraestrutura como código
Infraestrutura como códigoInfraestrutura como código
Infraestrutura como códigoEduardo Rozario
 

Similaire à PHP Conference 2015: Construindo e mantendo aplicações multi-tenant (multi-cliente) (20)

2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER
2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER
2019-2 - BD I - Aula 02 - Camadas de aplicação a Banco de Dados e Introd MER
 
Replicacao Object Sistemas
Replicacao Object SistemasReplicacao Object Sistemas
Replicacao Object Sistemas
 
WSO2 - Portfólio de Produtos, Soluções e Suportes
WSO2 - Portfólio de Produtos, Soluções e SuportesWSO2 - Portfólio de Produtos, Soluções e Suportes
WSO2 - Portfólio de Produtos, Soluções e Suportes
 
Arquitetura cliente servidor
Arquitetura cliente servidorArquitetura cliente servidor
Arquitetura cliente servidor
 
Iniciando com serviços de bancos de dados gerenciados na AWS
Iniciando com serviços de bancos de dados gerenciados na AWSIniciando com serviços de bancos de dados gerenciados na AWS
Iniciando com serviços de bancos de dados gerenciados na AWS
 
Mda arq cliente_serv
Mda arq cliente_servMda arq cliente_serv
Mda arq cliente_serv
 
Front end architecture
Front end architectureFront end architecture
Front end architecture
 
Joana costa tp 1 – trabalho prático www
Joana costa tp 1 – trabalho prático wwwJoana costa tp 1 – trabalho prático www
Joana costa tp 1 – trabalho prático www
 
Android Dev Conference 2017 - Entrega Contínua para Mobile
Android Dev Conference 2017 - Entrega Contínua para MobileAndroid Dev Conference 2017 - Entrega Contínua para Mobile
Android Dev Conference 2017 - Entrega Contínua para Mobile
 
Aplicações de tempo real com Meteor.js
Aplicações de tempo real com Meteor.jsAplicações de tempo real com Meteor.js
Aplicações de tempo real com Meteor.js
 
Microserviços - Universidade Metodista - EETI 2016
Microserviços - Universidade Metodista - EETI 2016Microserviços - Universidade Metodista - EETI 2016
Microserviços - Universidade Metodista - EETI 2016
 
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
 
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
 
Cakephp - framework de desenvolvimento de aplicações Web em PHP
Cakephp - framework de desenvolvimento de aplicações Web em PHPCakephp - framework de desenvolvimento de aplicações Web em PHP
Cakephp - framework de desenvolvimento de aplicações Web em PHP
 
De 1 a 1.000.00 de usuários
De 1 a 1.000.00 de usuáriosDe 1 a 1.000.00 de usuários
De 1 a 1.000.00 de usuários
 
C # banco de dados
C # banco de dadosC # banco de dados
C # banco de dados
 
Guia essencial para embarcar o MySQL em seu produto
Guia essencial para embarcar o MySQL em seu produtoGuia essencial para embarcar o MySQL em seu produto
Guia essencial para embarcar o MySQL em seu produto
 
Introducao banco de dados
Introducao banco de dadosIntroducao banco de dados
Introducao banco de dados
 
Microsoft Azure no Licenciamento Open
Microsoft Azure no Licenciamento OpenMicrosoft Azure no Licenciamento Open
Microsoft Azure no Licenciamento Open
 
Infraestrutura como código
Infraestrutura como códigoInfraestrutura como código
Infraestrutura como código
 

PHP Conference 2015: Construindo e mantendo aplicações multi-tenant (multi-cliente)

  • 1. Construindo e mantendo aplicações multi-tenant (multi- cliente) Aryel Tupinambá PHP Conference 2015
  • 2. Sobre o palestrante Co-fundador e CTO da LQDI Digital Projetos para empresas como Porto Seguro, Nestlé, Garoto, Editora FTD, Tishman Speyer e Ambev 12 anos trabalhando com PHP Desde a época que o PHPClasses era a onda :) Aryel Tupinambá
  • 3. Single tenant - Um único "cliente" para a aplicação - Forma tradicional, instalada no servidor do cliente - Faz sentido quando a aplicação é um PROJETO
  • 4. Agora com mais um cliente… e mais outro... - Seu PROJETO se tornou um PRODUTO - Diversos clientes usando a mesma aplicação - Estruturas separadas para cada novo cliente - Nada é compartilhado; tudo é isolado
  • 5. E agora, como faço... … atualizações de segurança? … correção de bugs? … features novas para todo mundo? E o espaço que toda essa galera ocupa? E o custo que tudo isso gera?
  • 6. Arquitetura multi-tenant - Tenant = inquilino - Uma única aplicação para vários clientes - Uma estrutura comum entre os clientes - As benfeitorias servem para todos - A customização de um cliente não interfere nos demais, nem previne que ele utilize da estrutura comum
  • 7. Principais desafios DATA STORAGE CODEBASE CUSTOMIZAÇÃO Como segmentar a base de dados para cada cliente? Como segmentar os arquivos enviados? Como fica o código fonte da aplicação? Como ficam as customizações? Como lidamos com updates e novas features? Como podemos customizar as funcionalidades da aplicação? Como permitir que atualizações e novas features não sejam impedidas por customizações?
  • 8. Não existe escolha certa ou errada O que existe são escolhas que fazem mais sentido para determinados cenários.
  • 10. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Cada cliente possui uma instância do seu SGDB (MySQL, Postgres, Mongo, etc), com seus dados isolados. Mais isolado Mais compartilhado Cada cliente tem um banco de dados (ou schema) diferente, na mesma instância Todos os clientes estão na mesma base de dados; o cliente é identificado por meio de uma coluna nas tabelas (tenantID) Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 11. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Mais isolado Mais compartilhado Todos os clientes estão na mesma base de dados; o cliente é identificado por meio de uma coluna nas tabelas (tenantID) Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 12. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Mais isolado Mais compartilhado Cada cliente tem um banco de dados (ou schema) diferente, na mesma instância Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 13. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Mais isolado Mais compartilhado Cada cliente possui uma instância do seu SGDB (MySQL, Postgres, Mongo, etc), com seus dados isolados. Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 14. Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 15. Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
  • 16. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Sugestão de uso: - Aplicações com pouca ou nenhuma variabilidade / customização - Aplicações em que a principal customização é visual - Aplicações com alto número de usuários (500k+) Mais isolado Mais compartilhado
  • 17. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Sugestão de uso: - Aplicações em que deve haver maior flexibilidade para customização - Aplicações em que a infra-estrutura sempre será responsabilidade sua - Planos baseados em volume de consumo ou performance Mais isolado Mais compartilhado
  • 18. Três formatos mais comuns Data storage Instâncias separadas Bancos de dados separadas Banco de dados compartilhado Sugestão de uso: - Projetos em que a separação física do hardware se faz necessária (instalações on-premises, compliance corporativo ou governamental, decisões de performance); - Alta disparidade no volume de dados ou de acessos entre clientes (quando alguns clientes consomem demais) - Quando você precisa monitorar o consumo individual de hardware para cada cliente (e seu SGDB não faz isso por database/schema) Mais isolado Mais compartilhado
  • 19. - Em regra geral, a FLEXIBILIDADE necessária deve ser o fator decisório - Customizar funcionalidades pode ser um desafio quando você tem um modelo de dados fixo; alterar o modelo de dados de toda uma aplicação só para atender um cliente / uma feature pode gerar inconsistência e dificultar a manutenção - Use o pattern de "migrations" e "seeds" para criar e manter o database schema; muito importante criar migrations que sejam, na medida do possível, 100% reversíveis. - Você não necessariamente precisa escolhar um único modelo para todos os dados da aplicação; se sua aplicação tem interações entre os clientes mas é altamente customizável, por exemplo, faz sentido segmentar o que faz parte do core em um único database, e o que faz parte da customização em um database separado Data storage
  • 20. Relembrando: não existe escolha certa ou errada
  • 21. Data storage: na prática
  • 22. Data storage: na prática Modelo compartilhado (via tenant ID)
  • 23. Data storage: na prática Modelo isolado (instâncias diferentes)
  • 25. Codebase - Dois cenários: uma instância para todos, ou uma instância por tenant app código fonte cliente1.app.com cliente2.app.com cliente3.app.com config 1 config 2 config 3 cliente1.app.com código fonte config 1 cliente2.app.com código fonte config 2 cliente3.app.com código fonte config 3 custom code Uma instância para todos Uma instância por cliente
  • 26. Codebase - Uma instância para todos - Atualizações são sincronizadas sem custo ou esforço - Nenhum ou pouquíssimo "housekeeping" necessário - Não é muito flexível para customizações - Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante app código fonte cliente1.app.com cliente2.app.com bigcorp.app.com config 1 config 2 config 3
  • 27. Codebase - Uma instância para todos - Atualizações são sincronizadas sem custo ou esforço - Nenhum ou pouquíssimo "housekeeping" necessário - Não é muito flexível para customizações - Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante app código fonte cliente1.app.com cliente2.app.com bigcorp.app.com config 1 config 2 config 3 Nginx sitesvia DB, cachedGit repository
  • 28. Codebase - Uma instância por cliente - Atualizações não são sincronizadas, exceto se automatizadas - Necessário um trabalho de "housekeeping" para manutenção das instâncias - Bastante flexível para customizações - Qualquer cliente pode ter sua versão da aplicação "congelada" - O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em algum momento isso fizer sentido para o negócio) bigcorp.app.com código fonte config 1 cliente1.app.com código fonte config 2 cliente2.app.com código fonte config 3 custom code
  • 29. Codebase - Uma instância por cliente - Atualizações não são sincronizadas, exceto se automatizadas - Necessário um trabalho de "housekeeping" para manutenção das instâncias - Bastante flexível para customizações - Qualquer cliente pode ter sua versão da aplicação "congelada" - O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em algum momento isso fizer sentido para o negócio) bigcorp.app.com código fonte config 1 cliente1.app.com código fonte config 2 cliente2.app.com código fonte config 3 Git repo .env files custom code
  • 30. Codebase - Uma instância por cliente - Atualizações não são sincronizadas, exceto se automatizadas - Necessário um trabalho de "housekeeping" para manutenção das instâncias - Bastante flexível para customizações - Qualquer cliente pode ter sua versão da aplicação "congelada" - O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento (se em algum momento isso fizer sentido para o negócio) bigcorp.app.com código fonte config 1 cliente1.app.com código fonte config 2 cliente2.app.com código fonte config 3 Nginx sites + PHP-FPM pools v1.4.0 v1.4.1 v1.4.0 custom code
  • 31. Codebase - De novo, o maior fator decisório aqui deve ser a FLEXIBILIDADE: o quanto você espera que o código da aplicação se altere com customizações de clientes? - A escalabilidade, embora seja um desafio (e mereceria uma palestra a parte), não deve ser dificultada em nenhum dos cenários, DESDE QUE você automatize todos os processos e fique de olho na consistência - Instâncias isoladas permitem que você escale clientes mais "barulhentos" (alto volume) para hardware melhor - Você pode também trabalhar com instâncias segmentadas por tier ou plano, e "empacotar" menos clientes por instâncua em tiers mais elevados/caros.
  • 33. Variabilidade e customização - O calcanhar de aquiles da arquitetura multi-tenant - Requer bastante meditação sobre os requisitos - Aqui é um dos melhores lugares onde design patterns e uma arquitetura sã e consistente brilham de verdade - Vou falar sobre algumas técnicas e formatos interessantes
  • 34. Relembrando: não existe escolha certa ou errada
  • 35. Variabilidade e customização - Para configuração: - Para instâncias de código isoladas: um arquivo de configuração (biblioteca DotEnv) - Para instâncias unificadas: parâmetros de configuração no banco/repositório de tenant data .env
  • 36. Variabilidade e customização - Para o data storage: - Migrations: funcionam como um controle de versão do seu modelo de dados - A maioria dos frameworks/ORMs possuem suporte built-in (Laravel, CakePHP, Doctrine), e há libs standalone para outros formatos. - Sempre criar migrations "reversíveis", ou seja, que possam sofrer rollback
  • 37. Variabilidade e customização - Para o código / funcionalidade: EVENTS Transação de negócio (ex: novo pedido realizado) Gerenciador de eventos (via Framework, biblioteca ou hand-made) Envio de e- mail para o usuário Registro no log de atividade do usuário Sub-serviços do core app Módulo customizado: NF-E Geração de NF-E Módulo customizado: Tracking Registrar nova carga à entregar dispatchEvent('order_created', $order);
  • 38. - Para o código / funcionalidade: EVENTS Variabilidade e customização Transação de negócio (ex: novo pedido realizado) Gerenciador de eventos (via Framework, biblioteca ou hand-made) Envio de e- mail para o usuário Registro no log de atividade do usuário Sub-serviços do core app Módulo customizado: NF-E Geração de NF-E Módulo customizado: Tracking Registrar nova carga à entregar dispatchEvent($order); CORE APP CUSTOM CODE
  • 39. return [ ['Entregas','abc.delivery.index'], ['Configurar Frete','abc.delivery.config'] ]; - Para o código / funcionalidade: HOOKS Variabilidade e customização Renderizar menu principal Gerenciador de hookstriggerHook('render_menu'); return [['Pedidos','core.orders.index']]; return [['Estoque','core.inventory.index']]; Módulo de Pedidos Módulo de Estoque Módulos do core app Módulo de Entregas Custom code do cliente ABC return [...];
  • 40. Variabilidade e customização - Para o código / funcionalidade: DEPENDENCY INJECTION Order BillingGatewayContract PayPalBillingGateway implementa DI Container registra recebe PayPalBillingGateway pede BillingGatewayContract
  • 41. Variabilidade e customização - Para o código / funcionalidade: DEPENDENCY INJECTION Order BillingGatewayContract PayPalBillingGateway Core app Order BillingGatewayContract PayPalBillingGateway Core app Order BillingGatewayContract PayPalBillingGateway Core app TENANT 1 TENANT 2 TENANT 3
  • 42. PagSeguroBillingGateway Variabilidade e customização - Para o código / funcionalidade: DEPENDENCY INJECTION Order BillingGatewayContract PayPalBillingGateway Core app Order BillingGatewayContract PayPalBillingGateway Core app Order BillingGatewayContract PayPalBillingGateway Core app TENANT 1 TENANT 2 TENANT 3 Custom code
  • 43. Variabilidade e customização - Para o frontend / interface: - Dê preferência para usar uma engine de templates (Blade, Twig, etc);
  • 44. Variabilidade e customização - Para o frontend / interface: - Use Sass ou outro pré-compilador de CSS - Você pode gerar o config via PHP, e então rodar o compilador (automático ou manual)
  • 45. Variabilidade e customização - Para infraestrutura / deploy:
  • 46. Variabilidade e customização - Para infraestrutura / deploy:
  • 47. Variabilidade e customização - Para infraestrutura / deploy: http://forge.laravel.com http://deployhq.com http://envoyer.io Use ferramentas ou serviços de automatização de deploy (imagine atualizar manualmente a versão de 600 clientes)
  • 48. Variabilidade e customização - Para infraestrutura / deploy: Use o Composer para gerenciar core app e código customizável
  • 49. Variabilidade e customização - Para infraestrutura / deploy: Automatize (se aplicável) o processo de provisionamento para novos clientes Novo cliente cadastrado Script / microservice de PROVISIONAMENTO Criar pasta no servidor e site no Nginx Criar banco de dados Gerar .env de configuração Criar registro no DB de tenants Cadastrar no Envoyer e realizar primeiro deploy Gerar composer.json com Core + Custom code Disparar e-mail para o cliente Gerar config do Sass e compilar CSS final
  • 50. Variabilidade e customização - Para infraestrutura / deploy: Automatize (se aplicável) o processo de provisionamento para novos clientes Novo cliente cadastrado Script / microservice de PROVISIONAMENTO Criar pasta no servidor e site no Nginx Criar banco de dados Gerar .env de configuração Criar registro no DB de tenants Cadastrar no Envoyer e realizar primeiro deploy Gerar composer.json com Core + Custom code Disparar e-mail para o cliente Gerar config do Sass e compilar CSS final
  • 51. Variabilidade e customização - Para infraestrutura / deploy: - O custo e tempo para provisionamento interfere diretamente em um KPI de negócio, o CAC (Custo de Aquisição de Cliente) - Provavelmente toda sua infra-estrutura pode ser administrada via API; use isso a seu favor - Amazon EC2 e DigitalOcean tem APIs para provisionamento de servidores - Amazon S3 e Rackspace Cloud tem APIs para criação de novos "buckets" de arquivos - Amazon Route 51 e DigitalOcean tem APIs para gerenciar o DNS (domínios customizáveis)
  • 52. TL;DR - Oriente sua arquitetura principalmente pela sua necessidade de flexibilidade e customização - Mais customizável -> mais isolada - Mais uniforme -> mais compartilhada - Use as melhores práticas de SOLID, principalmente no que diz respeito a Inversão de Dependência; a arquitetura multitenant é provavelmente o melhor use- case de substituição de implementações de uma interface em runtime
  • 53. TL;DR - Automatize TUDO que diz respeito a provisionamento, deploy e housekeeping de infraestrutura: manutenção manual de instâncias é uma eterna dívida técnica que se acumula - TDD é PRIMORDIAL; lembre-se que em um ambiente sincronizado, uma atualização impacta TODOS os seus clientes
  • 55. A está contratando! Procuramos desenvolvedores front-end e back-end, de TODOS os níveis de experiência, apaixonados pelo que fazem e a fim de aprender e ensinar Ambiente de trabalho bacana, descontraído, com remuneração competitiva, horários flexíveis e bastante abertura para novas idéias. Sem melindres, sem preciosismo e puxação de saco :D Plano de carreira sólido e flexível, com espaço para crescimento em gestão e especialização, e programas de feedback contínuo entre a equipe e os gestores. Manda um e-mail pra work@lqdi.net e cite a palestra da PHP Conference Ou me chame pessoalmente agora para trocarmos uma idéia Começe 2016 de trampo novo!
  • 56. Obrigado! E-mail / Hangouts: aryel.tupinamba@lqdi.net Facebook: http://facebook.com/aryel.tupinamba Twitter: http://twitter.com/DfKimera LinkedIn: http://linkedin.com/in/aryeltupinamba Slides da palestra: http://slideshare.net/aryeltupinamba http://lqdi.net

Notes de l'éditeur

  1. Boa tarde, pessoal! Vamos começar? Primeiramente eu gostaria de agradecer a presença de todos vocês, e o pessoal da Tempo Real que está organizando esse evento. A PHPConf tá completando 10 anos, e é realmente notável a diferença que o engajamento da comunidade tem feito na qualidade e experiência dos desenvolvedores no Brasil. Como alguém que está sempre entrevistando e contratando gente, eu vi o nível da galera subir muito nos últimos anos, e atribuo muito disso ao engajamento e espírito de comunidade da galera do PHP. É isso aí, continuem vindo nos eventos, aprendam, repassem o que aprenderam, voltem como palestrantes, ajudem a disseminar o conhecimento que todos saímos ganhando. O mercado é gigantesco, nenhum dev bom fica sem emprego, então a gente tem motivo de sobra pra ajudar todo mundo.
  2. Vou falar bem rapidamente de mim. Meu nome é Aryel Tupinambá, sou fundador e CTO da Liquidi, uma agência com bastante foco em tecnologia. Esse aí na foto sou eu, fingindo ser um cara sério e normal, mas é tudo fachada! A gente aqui sabe que não existe desenvolvedor que seja normal, né? Eu trabalho com PHP a mais ou menos 12 anos, desde aquela época em que o PHPClasses era a onda :)
  3. Desde aquela época, até começar essa onda de startups e software como servico, esse aqui era o padrão de projetos web. O software tinha um único cliente, que era instalado no servidor do cliente, ou em algum servidor compartilhado, e rodava lá sozinho. Esse é um modelo que chamamos de "single tenant", ou "um único cliente". A gente compara esse modelo com uma casa, solitária e ocupando todo o terreno sozinha.
  4. Só que aí, quando tudo dava certo e sua equipe comercial começava a bombar, o mesmo projeto que você fez pra um cliente, você começa a fazer pra outro, e mais outro, e mais outro. Seu projeto virou um produto, com vários clientes diferentes, mas sua estrutura continua a mesma. Pra cada cliente você tem uma estrutura diferente, com um código que pode até ser igual, mas que está replicado integralmente em cada um dos clientes. Aqui, a gente compara o modelo com um bairro. Tem várias casas, com vários clientes, mas tá todo mundo em seu terreninho, isolado do resto, cuidando do próprio umbigo. E todo esse isolamento, toda essa independência gera uma série de problemas.
  5. Preciso fazer uma atualização de segurança, ou preciso corrigir um bug. E agora? Vou sair copiando e colando a atualização na pastinha de cada um dos clientes? Vou entrando no FTP, no SSH, cliente por cliente, e atualizando. E se eu customizei a instalação desse produto pra alguém? E se eu quiser pegar a customização de um e replicar pra outro, que tem outra customização? E esse espaço todo que essa galera tá ocupando? E o mais importante pro negócio, e o custo que tudo isso gera? Se eu tenho um custo que aumenta tão rápido conforme eu ganho novos clientes, como que o negócio vai crescer?
  6. Aí que entra a arquitetura multi-tenant. Tenant é a palavra em inglês para inquilino. O conceito primário dela é que a gente usa uma única aplicação para vários clientes, e que esses clientes compartilham de uma estrutura comum. É igual a um prédio ou um condomínio, por que tá todo mundo compartilhando do mesmo terreno, o mesmo prédio. Daí que veio o termo "multi-inquilino". As benfeitorias servem pra todos, e o produto base é igual pra todos. E, igual a um apartamento, nada impede de um inquilino fazer uma "reforminha" no apê dele; ele vai estar com o mesmo apê que os outros, mas com uma ou outra coisa diferente. Parece ótimo né? Os olhinhos até brilham, tanto pros devs quanto pra empresa.
  7. Mas naturalmente, uma arquitetura dessas traz vários desafios na hora de desenhar a aplicação. Eu separei ele em 3 pilares: data storage, que seria banco de dados e arquivos de cliente; codebase, que seria o código do aplicativo em si, back-end e front-end; e customização. E aí ficamos com algumas perguntas: no data storage, como que a gente segmenta a base de dados pra cada cliente? E os arquivos enviados? No code base, como fica o código fonte e as customizações? Como que a gente lida com updates e features novas? Na customização, como que a gente vai customizar? Como que a gente atualiza o produto base sem quebrar as customizações, ou vice versa?
  8. Primeira coisa: não existe resposta certa, nem resposta errada. Pra cada uma dessas perguntas existe uma infinidade de respostas, assim como praticamente qualquer decisão na área de engenharia. Eu vou compartilhar aqui um pouco da minha experiência com projetos desse tipo, lá na Liquidi e em outras empresas que eu trabalhei e dei consultoria. Pra algumas pessoas, pode ser que a palestra fique um pouco superficial, por que o assunto é bem extenso e eu optei por falar mais sobre a arquitetura e menos sobre a implementação. O objetivo aqui é que vocês levem esses conceitos pra casa pra estudar com mais detalhe, testar, experimentar e pesquisar mais, e ver onde e como aplicar isso nos projetos de vocês, okay?
  9. Vamos lá, data storage.
  10. A gente tem 3 formatos mais comuns de segmentar um banco de dados no modelo multi-tenant, indo de um modelo mais compartilhado e unificado, e indo para um modelo mais isolado e independente. Vamos ver de baixo pra cima.
  11. Banco de dados compartilhado, basicamente o sistema roda todo em cima de um único banco de dados, e a gente segmenta os clientes por uma coluna com o ID do cliente. Nesse caso aqui, tem a coluna TenantID que especifica qual o cliente.
  12. Banco de dados separados, a gente cria um database pra cada cliente, dentro da mesma instância. O cliente é identificado pela database que ele está usando.
  13. E por fim, instâncias completamente separadas, com seus dados isolados. Esse formato é um pouco incomum, por causa do overhead de usar uma instância única pra cada cliente, mas faz sentido quando você tem altos requisitos de segurança e compliance. Beleza, mas e agora, quando eu uso cada modelo?
  14. A gente tem duas preocupações primárias na hora de segmentar o banco: custo de desenvolvimento e manutenção, e flexibilidade de extensão. Esse gráfico aqui mostra a progressão de custo sobre tempo das duas pontas do espectro. A gente vê aqui que o modelo Compartilhado tem um custo de desenvolvimento inicial maior, mas ganha no custo de manutenção futura. O modelo isolado é mais barato, mas encarece o processo de manutenção. A gente vai ver por que um pouco mais a frente. O custo por si só não deve ser o fator decisivo de um modelo ou outro.
  15. Esse gráfico mostra a relevância de decisão entre os formatos. Ter um volume alto de clientes puxa a decisão mais próxima do modelo compartilhado, principalmente por motivos de custo. Puxando pro outro lado, a gente tem, primeiramente, o tamanho do banco por cliente e a quantidade de usuários por cliente. Isso por que escalar um banco de dados gigantesco e homogêneo vai se tornando um desafio progressivo conforme o volume por cliente vai aumentando. Quando você já sabe que esse volume vai ser alto, você já pode prever, num processo de sharding do banco por exemplo, que cada tenant ficaria em um shard. Naturalmente ficaria mais barato prever essa separação desde o início. Agora, o que eu considero o fator mais decisório é o último aqui da lista, que é o serviço agregado por cliente, ou seja, as customizações que um cliente vai ter na aplicação. Se você tá prevendo que seu produto vai ser um produto único, cujo comportamento nunca muda entre um ou outro cliente, o modelo compartilhado faz muito mais sentido. Se você está imaginando que alguns dos seus clientes vão querer acrescentar módulos ou alterar comportamentos dentro do seu produto, o modelo de isolamento é melhor, por que você fica livre pra alterar o modelo de dados, criar novas tabelas e colunas sem se preocupar em sujar os dados dos outros clientes que não tem essa mesma customização.
  16. Então, sugestões de uso pra cada formato. O modelo compartilhado é ideal para aplicações em que pouca coisa, ou nada mesmo, vai mudar entre um cliente e outro. Esse modelo é o mais comum quando se fala de SaaS "para as massas", aquele tipo de aplicação que qualquer um assina num formulário web, coloca o número de cartão e sai usando. Geralmente essas aplicações tem um ticket médio baixo, e não faz muito sentido para o seu cliente customizar a experiência além daquilo que você previu desde o início.
  17. O modelo de bancos separados é ideal pra quando você já está prevendo customizações e módulos adicionais. Aqui você fica livre para ter modelos de dados que variam entre clientes. Nesse modelo você consegue segmentar melhor também aqueles clientes que tem mais ou menos consumo, ou que tem níveis maiores ou menores. Você pode empacotar mais ou menos clientes em uma instância de banco dependendo do tier que ele contratou, ou mover clientes mais "barulhentos" para outras instâncias.
  18. O modelo mais isolado, em que cada cliente tem uma instância isolada do banco, faz sentido quando você tem isso como pré-requisito de alguns clientes, como governos ou bancos. Aqui você consegue ter um controle bem maior da performance e do consumo de cada cliente.
  19. Na regra geral, o que deve te motivar mais na decisão do modelo é a flexibilidade que você precisa para mexer no banco de dados. Fica muito difícil você customizar um software, colocar funcionalidades ou alterar fluxos quando o seu modelo de dados é praticamente intocável. Uma coisa muito importante, principalmente quando você tá indo para um modelo mais isolado, é usar o modelo de migrations e seeds para criar e manter o seu modelo de dados. As migrations funcionam como um controle de versão do banco, e é o que vai permitir que você crie customizações para clientes sem quebrar a aplicação base. Você não precisa ter um único modelo entre os 3, necessariamente. Dá pra fazer um híbrido entre um e outro, por exemplo, quando você tem interações entre clientes dentro da sua aplicação, mas em um cenário em que ela ainda é customizável. Nós tivemos esse cenário na LQDI na nossa ferramenta de gestão de projetos.
  20. Lembrando de novo, gente, não tem resposta certa ou errada. Estude bem esses 3 modelos, veja o artigo que eu citei da Microsoft, avalie bem os requisitos do seu projeto e aí você consegue escolhar a mais adequada.
  21. Na prática, como a gente poderia implementar essas divisões no código? Vou usar alguns exemplos usando Laravel, que é o framework que a gente mais usa na LQDI, e é super tranquilo de fazer. Outros frameworks e ORMs tem soluções parecidas, e você consegue usar esses componentes aqui apartados do Laravel se precisar.
  22. No modelo compartilhado, a implementação mais fácil é criar uma query scope global, que condiciona as consultas baseadas no seu tenant ID. Aí você pode criar uma trait que aplica essa query scope global nos models que são multi-tenant. Nesse exemplo aqui, o Tenant ID vem de uma variável de ambiente, mas poderia vir de qualquer lugar; do subdomínio ou do domínio, de um campo na URL, de uma variável de sessão, e por aí vai.
  23. No modelo isolado é ainda mais tranquilo: a gente cria duas conexões, sendo uma específica para os modelos multitenant, e aí usa essa conexão como padrão nos models que são multitenant. Na configuração daquele cliente, você tem tanto os dados do banco único ali em MASTER_DB, que tem os dados compartilhados, quanto os dados do cliente, ali em TENANT_DB.
  24. Falando um pouco agora do codebase, do código fonte da aplicação.
  25. A gente tem dois modelos mais comuns pra trabalhar: uma instância pra todo mundo, ou uma instância por cliente. Eu tô usando o termo instância aqui me referindo a instância do codebase, e não necessariamente uma instância de servidor. Dá pra notar que temos mais ou menos a mesma polarização que temos nos modelos de dados: uma opção mais compartilhada e uma opção mais isolada. Os pros e contras são basicamente os mesmos
  26. No modelo de instância única, a gente tem algumas boas vantagens. As atualizações são sempre sincronizadas com todo mundo, já que todo mundo acessa o mesmo codebase. Também não tem muito housekeeping, muito trabalho de manutenção ou monitoramento pra cada cliente, uma vez que tá rodando tudo junto, e é um dos motivos pelo qual esse modelo fica mais barato ao longo do tempo. Agora, naturalmente, esse modelo não é muito flexível pra customizar a experiência por cliente. Ele é um modelo legal quando você tem módulos pré-definidos que são opcionais, e aí pra cada cliente você ativa ou desativa os módulos relevantes. Uma customização mais específica para um cliente fica mais difícil. Esse modelo também é bem fácil de escalar, principalmente se o padrão de consumo dos clientes é o mesmo. Dá pra colocar ele em um serviço Platform as a Service, tipo o Azure Websites ou o Amazon Elastic Beanstalk, e escalar ele só arrastando um slider no painel.
  27. Na prática, o formato que a gente usa pra implementar esse modelo: o repositório de código é único, sincronizado via git. Cada cliente tem o seu config, que pode vir do banco mestre ou de um microservice e pode ficar cacheado na sessão, e aí a gente pode criar um site no nginx pra cada cliente, todos apontando para o mesmo lugar, que é o repositório do app. Sua aplicação fica responsável por rotear o domínio pro cliente correto, pegar os dados desse cliente e carregar a configuração dele.
  28. O outro modelo é ter uma instância por cliente. A idéia aqui é que cada cliente tem sua pastinha separada, tendo exatamente o mesmo código fonte. Aqui a configuração dele pode estar na própria pasta, e essa pasta que vai conter qualquer código de customização específica de um cliente. As atualizações de código aqui não são sincronizadas por padrão, mas você pode, e deve, automatizar isso. Você acaba tendo um certo trabalho de housekeeping, já que cada cliente tem uma pasta com arquivos separados, e qualquer problema durante o deploy, execução ou instalação de customização pode exigir uma intervenção mais manual. O legal dele é que você fica livre pra tratar cada cliente de forma excepcional: fazer customizações, colocar e tirar funcionalidades, travar um cliente em uma versão do app ou colocá-lo pra rodar uma versão beta. Se em algum momento isso fizer sentido, você pode até criar um fork da sua aplicação pra atender um único cliente, como por exemplo em um projeto customizado pra um grande cliente.
  29. Na prática, a gente pra cada pastinha um repositório git, sincronizado via um repositório central tipo Github ou Bitbucket. A configuração de cada ambiente fica mais fácil, podendo ser feita por exemplo em um arquivo DotEnv na raiz de cada cliente. E o código customizado entra, quando aplicável, individualmente na pasta do cliente
  30. Nesse modelo é o mesmo esquema, cada cliente tem um site no Nginx, e aqui a gente pode até ter um pool separado do PHP-FPM por cliente, ganhando um certo nível de controle sobre a performance e carga de cada cliente em cima do servidor da aplicação.
  31. Então, pro codebase o fator decisório principal também é a flexibilidade, até mais que no banco de dados. Você vai precisar de muita gambiarra pra ter o mesmo nível de flexibilidade do modelo isolado no modelo compartilhado, e dificilmente vai valer a pena. A escalabilidade é um desafio pra maioria dos projetos multitenant, mas merece uma palestra a parte. A escolha do modelo, desde que você automatize bem os processos e tenha uma arquitetura consistente, não deve te impedir ou dificultar de escalar a aplicação. Ter as instâncias isoladas te dá mais controle pra isolar clientes mais ou menos exigentes, e com mais ou menos volume. Igual ao caso do data storage, a gente pode segmentar as instâncias por tier ou plano do cliente, e colocar menos clientes por servidor nos tiers mais caros. Dá pra atingir o mesmo resultado com uma instância compartilhada, mas você tem um adicional de código e complexidade de ter que manter o controle de qual cliente está em qual servidor.
  32. O terceiro desafio, e o mais, digamos, difícil de resolver, é o de Variabilidade.
  33. É o real calcanhar de aquiles da arquitetura multitenant, e precisa de bastante atenção e estudo, pra não gerar uma dívida técnica desnecessária. É nesse tipo de arquitetura que a gente vê os design patterns, os princípios do SOLID, realmente brilharem e te ajudarem pra caramba. Vou falar aqui sobre algumas técnicas e formatos legais de trabalhar.
  34. Lembrando de novo, não existe solução certa, ainda mais nesse quesito.
  35. Pra configuração, nas instâncias de código isolado a gente pode ter um arquivo de configuração em cada instância. Eu sugiro aqui usar a biblioteca DotEnv, que permite você usar um arquivo tipo esse aqui, e carregar essas variáveis só chamando uma função no código. Esse arquivo fica no gitignore e você só gera ele quando for provisionar um novo cliente. Na instância única, você vai ter mais ou menos a mesma configuração, só que dentro da tabela de tenants no banco principal. É legal, nesse formato, fazer um cache dessa informação, ou usar um banco de dados in-memory como o Redis, pois você provavelmente vai precisar consultar os dados a cada requisição.
  36. Pro data storage, ressalto a importância das migrations. Elas funcionam como um controle de versão do seu banco, onde a cada alteração você roda o script que cria novas tabelas ou altera as existentes, e ao fazer uma instalação do zero, todas as migrations são rodadas na ordem certa. É importante aqui sempre criar migrations que sejam reversíveis, problemas acontecem e você vai precisar voltar versões do modelo de dados ou desfazer customizações em alguns casos. A maioria dos frameworks modernos e ORM tem alguma forma de migration, e se não tiver, você pode usar as libs separadas do Laravel, que ficam no pacote Iluminate.
  37. Pra código, pra customização de comportamento, a gente tem vários patterns legais de trabalhar. Events. Aconteceu algum evento ou transação relevante na sua aplicação base, você dispara um evento, e passa os parâmetros dessa transação junto. Com esse evento, quem estiver escutando recebe os dados e pode fazer o que for necessário. Nesse exemplo aqui: criei um pedido novo e disparei o evento. Um módulo customizado de um cliente específico, por exemplo, estava escutando e gerou uma nota fiscal eletrônica desse pedido. Pra outro cliente, esse evento pode registrar uma carga que vai ser rastreada na logística. O legal é que você pode usar esse padrão dentro da sua própria aplicação base. Você pode ter atividades que não são relacionadas necessariamente o domínio original da transação, como por exemplo mandar um e-mail de aviso pro usuário ou registrar a atividade do cara num log.
  38. Aqui é o código dividido em core app, que é o código que todos os clientes tão rodando, e o custom code. O custom code não precisou mexer em nenhum código ou arquivo do core app pra poder tomar ações quando a pedido foi criado.
  39. Hooks: são tipo eventos, só que tem um certo retorno o Wordpress usa bem esse modelo nos plugins dele um exemplo legal: na hora de construir o menu, você dispara um hook, e cada módulo ou serviço registrado responde com os ítens que quer adicionar ao menu. desse jeito, ninguém precisa mexer na view do core app pra customizar os ítens do menu
  40. Injeção de dependência, uma coisa que eu sei que tem muita gente que ainda não sacou pra que serve, acho que agora vai ficar bem claro. Aqui nesse exemplo: O model de pedido da aplicação não sabe quem é o gateway de pagamento, mas ele sabe que precisa de UM gateway de pagamento então a gente estabelece um contrato, uma interface que determina o que um gateway de pagamento deve poder fazer O model de order pede pra um container "olha, me dá uma instância de alguém que implementa esse contrato", e esse container olha na configuração da aplicação e nos serviços e módulos registrados quem é a instância mais indicada. aqui ainda estamos no core app, e temos a implementação do gateway do PayPal. Então o container retorna pro model de pedido essa implementação, e o pagamento vai rolar via paypal
  41. Aí você tem sua lojinha funcionando, e um belo dia um cliente fala pra vc que quer usar um gateway diferente. Como o model de pedido não tá lidando com a implementação do PayPal direta, e sim com o contrato, essa solicitação fica muito mais simples
  42. A gente escreve uma nova implementação desse mesmo contrato, como por exemplo o PagSeguro. Depois, a gente fala pro container que a classe mais indicada pra lidar com esse contrato é a implementação do PagSeguro, e não do PayPal Pronto, trocamos de gateway, e não colocamos um dedo dentro do core, só mexemos na customização. A gente pode atualizar livremente o core app, sem quebrar o PagSeguro pra esse cliente, e nem o PayPal para os outros. O legal é que depois a gente pode pegar essa implementação do PagSeguro, e oferecer pra qualquer um dos clientes. O cliente quer, é só colocar o componente que registra essa implementação no container, e pronto. Geralmente containers de injeção de dependência, como o do Laravel, tem uma infinidade de controles e fine tuning. Você pode ser bem específico, por exemplo, sobre qual instância vai ser retornada caso a caso. Por exemplo, quando o model Pedido pedir um gateway, retornar PayPal. Quando a classe Assinatura pedir um gateway, retornar PagSeguro. O container cuida de decidir qual implementação vai ser usada.
  43. Falando agora um pouco de frontend. Sempre que der, usem engines de template pro projeto. Dá pra facilitar bastante a customização. Esse aqui é um exemplo da engine Blade, que vem no Laravel. Olha só, no meu layout aqui eu defino algumas rotas por nome, e não por caminho absoluto, então eu posso sobrescrever essas rotas se eu quiser. Aí aqui eu uso especifico o output de algumas seções, sidebar e content. Esse aqui é o arquivo de layout. Aí eu posso criar um sublayout, que extende do layout principal, e que define algum conteúdo pra sidebar, por exemplo. Aí eu tenho uma página desse módulo, que usa o sublayout específico, e define uma outra seção. Reparem como fica limpo e fácil de visualizar e manter o HTML consistente, e de reutilizar bastante coisa, por exemplo, numa customização. Dá pra jogar uma série de layouts, componentes e sections na mão do programador front-end, e ele vai tocar muito mais tranquilamente o desenvolvimento, mexendo só no que precisa e reutilizando muita coisa.
  44. Outra coisa importante pra incorporar no projeto é o Sass. Esse cara facilita muito a customização de layout e de visual entre um cliente e outro. Você define uma série de variávels que vão ser sobreescritas pelo cliente, escreve o estilo da aplicação e pronto. No seu processo de provisionamento, você compila o Sass e o CSS já sai pronto e customizado pro cliente. Dá pra você colocar tudo isso na mão do cliente, gerar o config via PHP carregando direto do banco e compilando o Sass. Tudo isso sem precisar sujar o HTML de estilos inlines que chamam variáveis carregadas de algum lugar, e que fica um inferno de administrar e manter depois.
  45. Pra infra-estrutura e deploy, tem uma coisa que é primordial pra projetos multitenant
  46. Automatizem tudo! De verdade, gente. Infra e deploy é o maior custo de overhead que um projeto desses vai acumular com o tempo, e quanto antes você automatizar esses processos, melhor. É importante já pensar nos processos automatizados na hora de planejar e desenhar a aplicação.
  47. Pra deploy, tem várias ferramentas. Na LQDI a gente usa essas 3, e são ridiculamente fáceis de usar e configurar. O Envoyer é bem focado em deploy de PHP, o Forge é um automatizador de provisionamento, instalação, configuração, deploy de servidores feito pelo criador do Laravel, super completo. O DeployHQ é uma plataforma praticamente que universal de deploys, aceita diversos targets, faz deploy usando Git, FTP, Amazon S3, rsync e o que mais vc precisar, dá pra customizar bastante o processo, é a ferramenta mais completa de deploy que a gente já usou.
  48. O Composer é melhor solução pra gerenciar e versionar tanto o seu core app quanto as customizações e módulos diferentes, principalmente no caso das instâncias isoladas. Você consegue criar repositórios privados usando uma ferramenta chamada Satis. Aí você gera um composer.json na hora de provisionar o cliente, e já especifica qual a versão do core code que você quer e quais módulos de customização. Pronto, os módulos viram packages e ficam isolados nas pastinhas dentro do vendor, e você evita a maioria dos problemas de housekeeping. Depois que você se acostuma a trabalhar desse jeito, fica fácil criar uma feature pra um cliente que pode ser revendida pra qualquer outro cliente.
  49. Ainda na linha de automatizar tudo, o próprio processo de provisionamento é importante de ser automatizado. Provisionamento é algo que cabe bem dentro de um microservice, por exemplo, e economiza um tempo danado da equipe de desenvolvimento e dos sysadmins, e facilita a configuração e customização de alguns clientes. Aqui é um exemplo de um script de provisionamento: o cliente se cadastrou, a gente dá um trigger pro serviço de provisionamento. Esse serviço começa criando um registro do tenant no banco. Aí ele vai, cria a pastinha do cliente do servidor e já gera um arquivo de site pro Nginx. Cria o banco, gera o .env com a configuração dos bancos. Enquanto ele vai fazendo isso, ele vai atualizando o registro do tenant no banco; o usuário pode até acompanhar o processo de provisionamento em tempo real. Aí vai, gera o composer.json com os módulos selecionados, gera o config do Sass e compila o CSS, cadastra o tenant no Envoyer via API e dá o trigger no deploy. O envoyer vai clonar os arquivos do core, instalar as dependências do composer, rodar as migrations no banco e reiniciar o nginx quando terminar. No final, dispara um email pro cliente já com a URL do ambiente dele.
  50. Só nas fases de customização, imagina o tempo que você não perderia fazendo isso manualmente. Criando arquivo, editando os campos, copiando e colando. Enquanto isso, seu cliente tá lá esperando. Se ele se inscreve direto do site, então, já era.
  51. É importante essa automatização por que o processo de provisionamento interfere direto num KPI de negócio, que é o custo de aquisição de cliente. Se para cada novo cliente o negócio vai precisar que você aloque algumas horas configurando arquivos e mexendo em paineis dos serviços, esse custo sobe. É um custo que afeta diretamente a capacidade do negócio crescer, dificulta e encarece um modelo trial ou uma opção freemium, e por aí vai. Uma coisa importante pra lembrar na hora de pensar na automatização do provisionamento é que provavelmente, sua infra inteira tem APIs para serem administradas programaticamente. EC2 e DigitalOcean dá pra provisionar servidores virtuais via API. S3, Rackspace Cloud e Google Storage, dá pra criar buckets de arquivos via API. Route 51 e DigitalOcean, dá pra gerenciar o DNS pra criar domínios custom pros clientes. Tá muito mais fácil do que antigamente automatizar tudo isso.
  52. Então, pra fechar gente, os principais pontos e dicas que eu posso dar pra arquitetura multitenant. Primeiro, foca sempre na sua necessidade de flexibilidade de customização na hora de decidir o modelo de segmentação de banco e de codebase. Quanto mais customizável, mais o modelo isolado é indicado. Quanto mais uniforme, mais o modelo compartilhado performa melhor. Segundo, tente usar sempre as melhores práticas do SOLID no projeto. Se você não conhece o SOLID ou ainda não entendeu muito bem, me manda um email que eu mando alguns materiais bem legais de SOLID. Inversão de dependência é uma coisa que te ajuda muito nesse tipo de projeto; é praticamente garantido que você vai ter casos de uso de ter que trocar a implementação algum serviço.
  53. Terceiro, automatize TUDO que diz respeito a provisionamento, deploy e housekeeping. Esse trio é o responsável por acumular uma constante divida técnica no seu projeto, e é difícil você automatizar depois de ter uma gama de clientes, pq você acaba correndo um risco de ter inconsistências entre quem veio antes e quem veio depois. Pra diagnosticar isso depois é difícil. Quarto e último ponto: escreva testes pra tudo que estiver dentro do core. Lembra que qualquer problema que passar vai ser propagado por todos os clientes. É muito importante testar também por que as customizações que você for escrever no futuro dependem de um core estável; você precisa saber se a sua customização quebrou algo ou não, e os testes vão te dizer isso.
  54. É isso gente! Perguntas?
  55. Rapidinho antes de fechar gente, um recado: a gente tá contratando lá na LQDI. A gente tá procurando desenvolvedores de todos os níveis de experiência, de júnior a sênior e especialista. A LQDI é uma empresa bem legal pra trampar, descontraída, com remuneração competitiva, horários flexíveis, bastante abertura pra novas idéias e muito projeto legal pra fazer. É uma oportunidade de fazer carreira numa empresa ainda pequena que está crescendo com bastante velocidade. Se alguém se interessar, é só mandar um e-mail pra work@lqdi.net citando a indicação da palestra. Se quiser saber mais, pode vir falar comigo agora também. É a chance de começar 2016 de trampo novo, hein gente!
  56. E é isso, pessoal. Muitíssimo obrigado pela atenção de vocês, e até a próxima! Meus contatos tão aí pra quem quiser tirar dúvida ou precisar de ajuda. E quem quiser os slides, é só pegar no meu Slideshare via QRCode. Valeu!