Jump to content
Douglas Motta

Gerenciamento de Aplicação Multi Instance/Tenancy em PHP

Recommended Posts

Olá, pessoal.

Desenvolvi uma aplicação em PHP para um segmento específico onde cada empresa terá essa aplicação. 

Minha dúvida é quanto ao gerencimento deste sistema, tendo em vista que cada empresa poderá personalizar a aplicação conforme suas necessidades (locais, legislação, negócio, etc.). Porém a maioria das funcionalidades será comum a todas as empresas (mas nada garante que uma funcionalidade que é comum hoje vai ser comum a todas amanhã). Por questões de segurança cada empresa terá seu banco de dados.

Estou entrando no mercado com o primeiro cliente e estou pensando no momento que tiver 30 clientes como vai ser. Utilizo o Bitbucket para controle de versão.

Qual é a melhor forma de gerenciar o codebase e o codecustom desta aplicação?  Um branch para cada cliente? Submodulos do Git? Pela própria aplicação?

Alguém que já vivenciou algo parecido que pode me ajudar?

Obrigado.

Share this post


Link to post
Share on other sites

No decorrer da minha experiência como dev, eu vi muitas decisões ruins, algumas delas eu mesmo sugeri. Mas, a que mais me impressionava era quanto ao projeto base e suas customizações.


Pensando apenas em code (sem entrar em banco de dados), eu utilizaria uma mescla entre o GIT e o composer.

 

Branch's e divisões

 

No GIT:

  • Dividir as branchs em 5 tipos (serão mais branchs): master, cutom-*, homologacao-*, dev-* e hotfix-*;
  • A branch master será única e exclusivamente para o código base não customizado;
  • A branch custom-*, será específica para o código homologado do projeto customizado para uma empresa (custom-empresa01, custom-empresa02, etc..);
  • A branch homologacao-* será específica para homologar a transição do código de dev para prod, aonde testes de alto nível são aplicados. Cada branch de produção (master/custom) terá sua respectiva branch de homologação (homologacao-master, homologacao-custom-empresa01, etc);
  • A branch dev-* é aonde é realizado o desenvolvimento, ela são livres, aonde o "desenvolvedor não conhece as leis" ou "o filho chora e mãe não vê", etc.. Você deve ter quantas forem necessárias, para cada implementação, cada GAP, cada moficação (dev-master-task-2784, dev-custom-empresa01-task-3500, etc...);
  • A branch de hotfix-* é aquela correção rápida, aquele conflito do merge entre uma entre o código base e uma customização ou que está implicando em parada geral do sistema (aquele bug ou erro de português que passou pela homologação/testes), que não necessariamente deve passar por todos os passos de desenvolvimento/homologação/produção. O que nós normalmente chamamos de "codificar em prod"... Sim, isso existe na realidade de todos já fizeram.

Essa é a definição da árvore do projeto. Os caminhos a serem seguidos:

  • dev-master-* <--> homologacao-master <--> master --> homologacao-custom-* <--> custom-(todas as empresas);
  • dev-custom-* <--> homologacao-custom-* <--> custom-*;
  • hotfix-* <--> para aonde for necessário.

Perceba que no fluxo, uma custom nunca deve levar o seu código para a master. Apenas a master pode levar códigos para a custom. Sempre utilizando a branch de homologação da custom.

 

Fork

 

Uma característica bem interessante dos serviços de controle de versionamento (bitbucket, github, etc...) é a possibilidade de criar um fork de um projeto. O seu projeto CORE será o repositório principal e, para cada cliente, você criará um novo fork. Logo, você terá o projeto master e os forks para cada cliente (master -> cliente-01 -> cliente-02, etc...).

 

A divisão entre branchs, deve ser a mesma exemplificada exclusiva para a master. Ou seja, 4 tipos: master, homologação, dev-* e hotfix-*). A nomenclatura das branchs (mster, homologacao, dev-* e hotfix-*) segue a mesma definição anteriormente explicada.

 

A parte de fluxo será o que está exemplificado abaixo:

  • dev-* <--> homologacao <--> master;
  • hotfix-* <--> para onde for necessário.

 

O cuidado, vem na hora de sincronizar os forks. O BitBucket, por exemplo, lhe sugere um fork automático entre as branchs masters de cada repositório. Entretanto, para um melhor controle e validação do novo código, a sincronização deve ocorrer entre a branch master, do projeto master, para a branch homologacao do projeto customizado. Ou seja:

 

  • Master:master --> Cliente-01:homologacao;

 

Dessa forma, você pode homologar, corrigir e enviar para a produção (master) da customização de clientes.

 

No BitBucket, para realizar tal feito, você pode ir no menu compare, escolha  a branch da qual está o código (parte de baixo) e a branch na qual você quer enviar o novo código (branch de cima). Compare as diferenças e, no canto direito superior, o BitBucket lhe exibirá o botão merge. Feito o merge, o processo é exatamente o mesmo que utilizando branchs.

 

Módulos

 

Aqui é que entra a questão de módulos. Caso você implemente partes do sistema como módulos, você pode usar tanto o git-submodule ou o composer. Com ambos você poderá utilizar repositórios privados para baixar as suas dependências. Para cada módulo, você deverá ter o repositório separado e, caso o repositório separado seja customizado, poderá seguir a estruturação acima mencionada.

 

Entretanto, no caso de módulos personalizados, acredito que com o git submodule não seja possível separar entre versões (branch/tags) específicas para cada projeto/branch. No caso do composer é possível, pois, cada branch/projeto, terá seu próprio composer que pode ser personalizado.

 

Banco de dados

 

Nesse caso, vai depender muito do que você irá utilizar para gerenciar o SGBD. Eu utilizei por muito tempo o MySQL WorkBench. Ele funciona perfeitamente quando o assunto é modelagem e sincronização. Entretanto, o formato de arquivo gerado por ele não é aberto e, em consequência, não pode ser versionado. Logo, quando uma tabela precisar ser diferente em algum projeto, você terá dois arquivos distintos.

 

Há, também, a possibilidade de tratar tudo na forma de SQL scripts. Mas ficaria sem uma ferramenta de apoio. Talvez alguém conheça alguma ferramenta melhor para a situação.

 

A contra-partida

 

Quando você separa pequenas partes de um projeto em módulos e os adiciona como dependências do seu projeto, você pode encontrar uma situação denominada  Dependency Hell. Esse termo também pode ser utilizado para a manutenção do código entre as branchs, pois, todas as suas customizações necessitam estarem atualizadas com a branch master. E se você almeja 30 empresas, pense que uma mudança no CORE precisa ser homologada para as 30 empresas.

 

Considerações

 

Sendo dicas como elas são, apenas dicas, você pode considerar demasiada estrutura e simplista ou exagerada demais e partir para uma abordagem meio termo ou mais robusta. Tudo dependerá de onde você está e para onde gostaria de chegar.

 

Existem outras ferramentas e abordagens que pode lhe ajudar. Uma delas seria a integração contínua, o qual incluí N outras ferramentas de auxílio.

 

Update

 

Um sistema que gerencia suas próprias customizações acaba sendo limitado a campos e novas informações. Eu, particularmente, não gosto muito da prática. Entretanto, para evitar o problema com o SGBD, pode-se utilizar tabelas de cadastros par atributo-valor para cruzar informações dinâmicas e reduzir a necessidade de criar novas colunas e tabelas. Mas, é uma questão bem limitada.

 

Update 2

 

Com a nova parte de forks (que eu não havia me lembrado anteriormente), seria a sugestão mais indicada. Pois, se você possuir uma equipe de desenvolvimento específica para cada cliente, poderá gerenciar muito melhor as permissões e acessos. O controle é bem superior a de um repositório apenas.

Edited by Gabriel Heming
explicação sobre fork e novo posicionamento
  • +1 4

Share this post


Link to post
Share on other sites

Olá Gabriel. Muito obrigado pela resposta.

 

Você detalhou bastante e tirou as dúvidas que eu tinha em minha cabeça com relação à esse gerenciamento. Poderia tirar uma útlima dúvida? Com relação ao projeto, a estrutura de pastas, etc. Eu uso Symfony e gostaria de saber se para cada novo cliente eu crio um projeto novo no PhpStorm e clono o Core ou eu consigo gerenciar tudo isso com apenas um projeto no PhpStorm? Tem uma estrutura de pastas para esta arquitetura?

 

Valeu mesmo.

Share this post


Link to post
Share on other sites

Apesar de, estruturalmente, tudo estar em um mesmo projeto. Seria necessário instalar as dependências, pelo composer, para cada projeto. Isso seria necessário sempre que mudar de uma branch de um projeto para outro.

 

Então, sim, é melhor ter um projeto separado para cada cliente.

 

Outro detalhe, que eu não comentei anteriormente é sobre o fork. Para cada cliente pode ser criado um fork do projeto (vou atualizar a resposta anterior).

  • +1 1

Share this post


Link to post
Share on other sites

Atualizei o post principal. E, nesse momento, acredito que a solução entre forks do projeto seja a mais indicada.

  • +1 1

Share this post


Link to post
Share on other sites
1 hora atrás, Douglas Motta disse:

Tem uma estrutura de pastas para esta arquitetura?

 

Não, apenas que exista uma estrutura definida e com coerência (e não seja uma bagunça).

 

A que um framework, como Symfony, lhe oferece estará de bom tamanho.

  • +1 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By djwagnersp
      Bom dia amigos, tudo bem? estou com uma duvida se alguém puder me ajudar agradeço desde já.
       
      tenha a seguinte condição:
      //array dos produtos $prod = 'agua'; $prod = 'refri'; $prod = 'cerveja'; //array das quantidades $qtd = '3'; $qtd = '2'; $qtd = '6'; Gostaria de fazer um loop o for ou foreach que imprimisse o $prod a quantidade de vezes do $qtd
      como seria possível realizar isso?
    • By dutopfave
      Galera tenho um cadastro de cliente que preenche nome e login, ai quando digita o nome, automaticamente ele preenche o login, pra agiliza, ta assim: $("#inputdonome").blur(function(){ $("#login").val($(this).val()); }); só que to com problema de nome repetido, então vou muda ao invés de preenche automático com nome, preenche com EMAIL, porém tem como preenche automático o login só q para antes de chega no '@'   ai ficaria assim:

      E-mail: contato2019@site.com.br
      Login: contato2019
    • By JenneferBarbosa
      <label>Data Inicio</label> <input type="date" name="data_inicio-incluir" id="data_inicio-incluir"> <label>Data Fim</label> <input type="date" name="data_fim-incluir" id="data_fim-incluir"> Boa tarde pessoal, estou iniciando em JS e não sei como fazer a validação de datas. Estou fazendo um sistema de aluguel de livros, então,  como consigo verificar se a data_fim não é menor que a data inicio e que a data_fim seja de 1 até 7 dias depois da data_inicio, não podendo ultrapassar. Se alguém tiver como me ajudar, ficarei muito grata.  
    • By WitchMad
      Ooi gente!
      Seguinte, estou desenvolvendo uma plataforma para advogados. Nela será consultado processos a partir do web service do PJE.
      No site do PJE me recomendou utilizar o NuSoap para consultar o web service e foi o que eu fiz.
      Segue o código da consulta
      <?php require_once 'nusoap/lib/nusoap.php'; /* Parâmetros Requisitados */ // idConsultante // senhaConsultante // numeroProcesso /* Objetos de Resposta sucesso bollean Indica se houve sucesso na consulta do processo. mensagem string Mensagem informando que o processo foi consultado com sucesso. recibo xs:base64Binary Comprovante do protocolo do processo, que contém os dados básicos do processo. */ $wsdl = "https://www.tjpe.jus.br/pje/intercomunicacao?wsdl"; $client = new nusoap_client($wsdl, 'wsdl'); if($client->getError()){ echo "Erro no construtor" . $client->getError(); exit(); } $result = $client->call('consultarProcesso', array('idConsultante'=>'CPF do Consultante', 'senhaConsultante'=>'Senha do Consultante', 'numeroProcesso'=>'Número do Processo')); echo $result['sucesso']; ?> Acontece que a página fica em branco, sem nenhum tipo de mensagem.
      Se possível gostaria de dicas se há algum erro no código, ou alguma outra ferramenta para consultar web service
    • By Alvaro Pacífico Serpa
      Olá pessoal, eu estava copiando um trecho de um código fonte usando o file_gets_contents
      $log=file_get_contents($url); $trechoInicial = "VideoUrl('"; $trechoFinal = "')"; $posicao1 = strpos($log, $trechoInicial); $posicao2 = strpos( $log, $trechoFinal, $posicao1 ); $trechoCopiado = substr( $log, $posicao1 + strlen( $trechoInicial ), $posicao2 - $posicao1 - strlen( $trechoInicial ) ); echo $trechoCopiado; Estava funcionando perfeitamente e do nada parou de funcionar, tem alguma outra forma de fazer isto que estou fazendo?
×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.