Arquitetura PHP pura. Como medir e controlar isso?

Prefácio


Como você já entendeu pelo nome, aqui vou falar sobre a mais pura arquitetura pura. E o ímpeto para o desenvolvimento de toda essa história foi o livro de Robert Martin, "Arquitetura pura". Se ainda não o li, ouso recomendá-lo! O autor revela muitos tópicos importantes, compartilha ativamente sua rica experiência de vida (de um campo profissional, é claro) e as conclusões feitas com base nisso ocasionalmente tecem em capítulos da história como magistralmente (e não apenas, é claro) nossos pais e avós nos anos 60, 70, 80 e até mesmo nos 90, como grãos de grãos, foram coletados os princípios favoritos de todos do SOLID e seus análogos no mundo dos componentes e o que eles aprenderam nos últimos meio século. No processo de leitura do livro, a linha de desenvolvimento da indústria de desenvolvimento de software é bem traçada, problemas típicos com os quais os garotos tiveram que lidar,e métodos para resolvê-los.

Não pense, recontar o resumo do livro não é o objetivo deste post.
Em seguida, falaremos sobre idéias que me levaram a desenvolver uma ferramenta (determinarei o grau de sua utilidade para você e aguardarei comentários, sugestões e críticas construtivas com grande interesse).

Parece-me que o artigo será útil para todos. Aqueles que já estão familiarizados com o livro poderão atualizar alguns de seus momentos em sua memória ou simplesmente pular a primeira parte e começar imediatamente a se familiarizar com a ferramenta. Quem não leu o livro antes pode talvez encontrar algo novo para si na primeira parte.

Por conveniência, o artigo está dividido em 2 partes.

No primeiro, vou falar sobre as ideias-chave que geraram na minha cabeça o desejo de automatizar tudo isso, somos programadores ou quem no final? Aqui citarei muito do autor, além de inserir ativamente trechos e ilustrações de diferentes capítulos do livro.

A segunda parte, quase inteiramente, será dedicada à descrição da ferramenta que apareceu, revelando suas capacidades e orientações passo a passo.

Se você se considera uma categoria de pessoas levando tudo muito perto do seu coração, recomendo que comece a ler o Posfácio .



Parte 1


O que é arquitetura de software?


Infelizmente, o autor do livro não dá uma definição única. Há um grande número de formulações diferentes, e todas estão corretas à sua maneira.
No entanto, podemos ir do outro lado ..

Qual é o propósito da arquitetura?


Há apenas uma resposta:

o objetivo da arquitetura de software é reduzir o trabalho humano necessário para criar e manter um sistema.

Um pouco introdutório ..

Onde muitos projetos começam?


"Poderemos restaurar a ordem mais tarde, entraríamos apenas no mercado!"
Como resultado, a ordem não foi restaurada, porque a pressão da concorrência no mercado nunca diminui.

“A maior mentira que muitos desenvolvedores acreditam é que o código sujo os ajudará a entrar rapidamente no mercado, mas, na realidade, retardará seu movimento a longo prazo. Os desenvolvedores que acreditam nessa mentira mostram a arrogância de Hare, acreditando que no futuro poderão passar da criação de desordem para a restauração da ordem, mas cometem um erro simples. O fato é que a criação de desordem é sempre mais lenta que a constante observância da limpeza, independentemente da escala de tempo escolhida ".

Dois valores de produtos de software


  1. Comportamento (algo urgente, mas nem sempre importante)
  2. Arquitetura (algo importante, mas nem sempre urgente)

Muitas vezes se afogam no primeiro e negligenciam completamente o segundo.

Tipo: “Por que perder tempo pensando profundamente na arquitetura, o principal é que ela funcione corretamente!” .

Mas eles perdem um ponto importante: “Se um programa que funcione corretamente não permitir a possibilidade de alterá-lo, ele parará de funcionar corretamente quando os requisitos forem alterados e eles não serão capazes de fazê-lo funcionar corretamente. Ou seja, o programa se tornará inútil.

Se o programa não funcionar corretamente, mas puder ser facilmente alterado, eles poderão fazê-lo funcionar corretamente e manter seu desempenho à medida que os requisitos forem alterados. Ou seja, o programa sempre será útil. ”

Gostei desta afirmação:"Se você acha que uma boa arquitetura é cara, tente uma arquitetura ruim". (Brian Foote e Joseph Yoder)

Acontece que é importante prestar a devida atenção à limpeza e arquitetura do código em geral desde as primeiras linhas. Mas, se tudo é relativamente claro com a pureza do código (cheire todos os tipos de maus cheiros no código e corrija-o, além de as ferramentas estarem cheias de IDEs inteligentes, analisadores estáticos e outros resíduos indubitavelmente importantes), então a arquitetura não é bem assim (pelo menos menos eu).

Como você pode controlar algo que é tão vago que é difícil até mesmo ser definido por uma única frase que tem uma idéia muito versátil e a cada segundo, droga, merda vê e tenta interpretá-lo de sua própria maneira, se você não é neto de Vanga, não ganhou o programa "Intuição ”E o quinto ponto não é particularmente sensível? Então o autor do livro lança alguns pensamentos valiosos para o pensamento ... Vamos resolver isso.

Por que você criou o SOLID e por que não basta o suficiente?


Todos nós provavelmente conhecemos os princípios do SOLID.

Seu objetivo é criar estruturas de software de nível médio que:

  • tolerante à mudança;
  • simples e compreensível;
  • formam a base para componentes que podem ser usados ​​em muitos sistemas de software.

Mas: “Assim como tijolos bons podem formar uma parede inutilizável, componentes tão bem projetados do nível médio podem criar um sistema inutilizável.”
Portanto, no mundo dos componentes, existem análogos dos princípios do SOLID, bem como princípios de alto nível para a criação de arquiteturas.

Vou abordar esses tópicos muito superficialmente, mais detalhes podem ser encontrados no livro. Vamos lá!

Conectividade dos componentes e seus princípios determinantes


“A qual componente essa ou aquela classe pertence? Essa importante decisão deve ser tomada de acordo com os princípios estabelecidos de desenvolvimento de software. Infelizmente, essas decisões são de natureza especial e são tomadas quase exclusivamente com base no contexto. ”

REP: Princípio de equivalência de reutilização / liberação - O princípio de equivalência de reutilização e liberações.

Em termos de arquitetura e design, esse princípio significa que as classes e módulos que compõem um componente devem pertencer a um grupo conectado. Um componente não pode simplesmente incluir uma mistura aleatória de classes e módulos; Deve haver algum tema ou objetivo comum a todos os módulos.

Classes e módulos combinados em um componente devem ser liberados juntos.

PCC: Princípio Comum de Fechamento - o princípio da mudança consistente.
Esse é o princípio do SRP (responsabilidade única) reformulado para os componentes.

Classes que mudam pelos mesmos motivos e ao mesmo tempo devem ser incluídas em um componente. Componentes diferentes devem incluir classes que mudam em momentos diferentes e por vários motivos.

CRP: Princípio Comum de Reutilização - O princípio da reutilização compartilhada.
Esse princípio é semelhante ao ISP (segregação de interface).

Não force os usuários a depender do que eles não precisam.

O princípio indica que as classes que não estão intimamente relacionadas não devem ser incluídas em um componente.

“Talvez você já tenha notado que os três princípios dos componentes conectados entram em conflito um com o outro. Os princípios de equivalência de reutilização (REP) e mudança consistente (CCP) são inclusivos: ambos se esforçam para tornar os componentes tão grandes quanto possível. O Princípio de Reutilização (CRP) é excepcional, buscando tornar os componentes o menor possível. A tarefa de um bom arquiteto é resolver essa contradição. ”

imagem

“No passado, vimos a conectividade mais facilmente do que sugerem os princípios de equivalência de reutilização (REP), mudança consistente (CCP) e reutilização compartilhada (CRP). Uma vez que pensamos que a conectividade é apenas um atributo, que um módulo executa uma e apenas uma função. No entanto, os três princípios da conectividade de componentes descrevem uma variedade muito mais complexa. Ao escolher classes para inclusão em componentes, você deve considerar as forças opostas associadas à facilidade de reutilização e desenvolvimento. Encontrar um equilíbrio dessas forças com base nas necessidades do aplicativo não é uma tarefa fácil. Além disso, a balança é quase sempre constantemente alterada. Ou seja, a partição considerada bem-sucedida hoje pode não ser bem-sucedida após um ano. Consequentemente,a composição dos componentes quase certamente mudará com o tempo e o foco do projeto mudará da facilidade de desenvolvimento para a facilidade de reutilização. ”

Compatibilidade de componentes


“Os três princípios a seguir definem as regras para o relacionamento entre componentes. E, novamente, somos confrontados com contradições entre facilidade de desenvolvimento e organização lógica. As forças que afetam a arquitetura da estrutura dos componentes são técnicas, políticas e voláteis. ”

ADP: Princípio das Dependências Acíclicas - o princípio da aciclicidade das dependências.
Não são permitidos loops no gráfico de dependência de componentes!

imagem

De qualquer componente exibido no gráfico, você começa a se mover ao longo das setas que indicam a direção da dependência, não será possível retornar ao ponto original. Este é um gráfico orientado acíclico (DAG - Directed Acyclic Graph).

imagem

Nesta imagem, temos uma dependência que leva ao aparecimento de um ciclo. A dependência cíclica resultante pode sempre ser interrompida.

Métodos para quebrar dependências cíclicas


1. Aplicando DIP (princípio de inversão de dependência)

imagem

2. Introdução do novo componente

imagem

“A segunda solução envolve a dependência da estrutura dos componentes em relação à mudança de requisitos. De fato, à medida que o aplicativo cresce, a estrutura das dependências de componentes cresce e muda. Portanto, ele deve ser constantemente verificado quanto a ciclos. Quando os ciclos se formam, eles precisam ser interrompidos de uma maneira ou de outra. Às vezes, para isso, é necessário criar novos componentes, o que aumenta a estrutura das dependências. ”

Design de cima para baixo, ou melhor, sua impraticabilidade


“A estrutura dos componentes não pode ser projetada de cima para baixo. Essa conclusão não é alcançada imediatamente assim que eles começam a projetar o sistema, mas isso inevitavelmente acontece com o crescimento e a mudança do sistema.

Considerando um grande diagrama de blocos, como a estrutura das dependências de componentes, acreditamos que os componentes devem, de alguma forma, representar as funções do sistema. Mas, na realidade, esse não é um atributo indispensável dos diagramas de dependência de componentes.

De fato, os diagramas de dependência dos componentes refletem fracamente as funções do aplicativo. Em maior medida, são um reflexo da conveniência de montagem e manutenção do aplicativo. Esta é a principal razão pela qual eles não são projetados no início do desenvolvimento do projeto. Durante esse período, não há software que precise ser coletado e mantido; portanto, não há necessidade de elaborar um mapa de construção e manutenção. Mas com o advento de um número crescente de módulos nos estágios iniciais de implementação e design, a necessidade de gerenciar dependências aumenta ... Além disso, há um desejo de limitar o impacto das mudanças o máximo possível, então começamos a prestar atenção aos princípios de responsabilidade única (SRP) e mudança coordenada (CCP) e combinamos as classes, o que provavelmente mudará juntos.

Uma das principais tarefas dessa estrutura de dependência é o isolamento da variabilidade. Não precisamos de componentes que geralmente mudam pelos menores motivos e afetam outros componentes que seriam completamente estáveis. Por exemplo, alterações cosméticas na GUI não devem afetar as regras de negócios. Adicionar e modificar relatórios não deve afetar políticas de alto nível. Consequentemente, um gráfico de dependência de componentes é criado e criado pelos arquitetos para proteger componentes estáveis ​​e valiosos da influência de componentes voláteis.

À medida que o aplicativo se desenvolve, começamos a nos preocupar com a criação de itens reutilizáveis. Nesta fase, o princípio da reutilização compartilhada (CRP) começa a influenciar a composição dos componentes. Finalmente, com o advento dos loops, começamos a aplicar o princípio da aciclicidade de dependência (ADP), como resultado, o gráfico de dependência dos componentes começa a mudar e crescer.

Uma tentativa de projetar a estrutura de dependência dos componentes antes de qualquer classe provavelmente falhará. Nesse estágio, não sabemos quase nada sobre a reconciliação de mudanças, não imaginamos quais elementos podem ser usados ​​repetidamente e quase certamente criaremos componentes que formam dependências cíclicas. Portanto, a estrutura das dependências de componentes deve crescer e se desenvolver juntamente com o design lógico do sistema ”

Ei, você ainda está aqui? Cara, isso é importante, você precisa dizer olá para isso, pelo menos, para inserir o significado da próxima parte, haverá um tutorial bruto sobre o uso do tulza.

SDP: princípio das dependências estáveis ​​- o princípio das dependências estáveis.
As dependências devem ser direcionadas para a estabilidade!

“O que se entende por“ sustentabilidade ”? Imagine uma moeda em uma borda. A posição dela é estável? Muito provavelmente você responderá "não". No entanto, se você o proteger de vibrações e sopros de vento, ele poderá permanecer nessa posição por um período arbitrariamente longo. Ou seja, a sustentabilidade não está diretamente relacionada à frequência das mudanças. A moeda não muda, mas dificilmente alguém dirá que, de pé na borda, está em uma posição estável.

O dicionário explicativo diz que sustentabilidade é "a capacidade de manter a condição de alguém sob influências externas". A sustentabilidade está relacionada à quantidade de trabalho que precisa ser feito para mudar de estado. Por um lado, uma moeda que está em uma borda está em um estado instável porque é preciso um pequeno esforço para derrubá-la. Por outro lado, a mesa está em uma condição muito estável, porque requer um esforço muito mais substancial para derrubá-la.

O que tudo isso tem a ver com software? Existem muitos fatores que complicam a alteração de um componente, como tamanho, complexidade e clareza. Mas deixaremos de lado todos esses fatores e focaremos em outra coisa. Há uma maneira infalível de dificultar a alteração de um componente de software, criando muitos outros componentes que dependem dele. Um componente com muitas dependências recebidas é muito estável, porque reconciliar alterações com todos os componentes dependentes exige um esforço considerável ".

imagem

imagem

Como avaliar a estabilidade do componente? O autor sugere calcular o número de suas dependências recebidas e enviadas e, com base nas mesmas, calcular a medida de sua estabilidade.

  • Fan-in ( ): . , .
  • Fan-out ( ): . , .
  • I: : I = Fan-out ÷ (Fan-in + Fan-out). [0, 1]. I = 0 , I = 1 – .

Portanto, esse princípio diz que a métrica do componente I deve ser maior que a métrica dos componentes I que dependem dele. Ou seja, as métricas que devo diminuir na direção da dependência.

É importante observar que, se todos os componentes do sistema forem o mais estáveis ​​possível, esse sistema não poderá ser alterado. Portanto, nem todos os componentes devem ser estáveis.

Cara, não adormeça, eu estou perto. Só falta um pouco!

SAP: princípio das abstrações estáveis ​​- o princípio da estabilidade das abstrações. A estabilidade de um componente é proporcional à sua abstração.

“Algumas partes dos sistemas de software devem mudar muito raramente. Essas peças representam decisões arquitetônicas de alto nível e outras decisões importantes. Ninguém quer que essas decisões sejam voláteis. Portanto, o software que encapsula regras de alto nível deve residir em componentes estáveis ​​(I = 0). Volátil (I = 1) deve conter apenas código mutável - um código que pode ser alterado fácil e rapidamente.

Mas se você colocar regras de alto nível em componentes estáveis, isso complicará a alteração no código-fonte que as implementa. Isso pode tornar toda a arquitetura inflexível. Como tornar um componente com estabilidade máxima (I = 0) tão flexível que permaneça estável durante as mudanças? A resposta está no princípio de abertura / fechamento (OCP). Este princípio diz que é possível e necessário criar classes suficientemente flexíveis para que possam ser herdadas (estendidas) sem alterações. Quais classes cumprem esse princípio? Resumo.

O SAP (o princípio da estabilidade das abstrações) estabelece uma conexão entre estabilidade e abstração. Por um lado, ele diz que um componente estável também deve ser abstrato para que sua estabilidade não impeça a expansão e, por outro lado, ele diz que um componente instável deve ser concreto, porque a instabilidade facilita a alteração de seu código.

Ou seja, um componente estável deve consistir em interfaces e classes abstratas para que possa ser facilmente estendido. Os componentes resilientes disponíveis para expansão são flexíveis o suficiente para não restringir excessivamente a arquitetura.

Os princípios de estabilidade de abstrações (SAP) e dependências estáveis ​​(SDP) juntos correspondem ao princípio de inversão de dependência (DIP) para componentes. Isso é verdade porque o princípio do SDP exige que as dependências sejam direcionadas à sustentabilidade, e o princípio do SAP declara que a sustentabilidade implica abstração. Ou seja, as dependências devem ser direcionadas à abstração.

No entanto, o princípio DIP é formulado para classes e, no caso de classes, não há meios-tons. A classe é abstrata ou não. Os princípios do SDP e do SAP se aplicam aos componentes e permitem uma situação em que um componente é parcialmente abstrato ou parcialmente estável. ”

Como medir a abstração de um componente? Aqui também tudo é muito simples.
O valor da medida do componente abstrato é determinado pela razão entre o número de suas interfaces e classes abstratas e o número total de classes.

  • Nc: o número de classes no componente.
  • Na: o número de classes abstratas e interfaces no componente.
  • A: resumo. A = Na ÷ Nc .

O valor da métrica A varia no intervalo de 0 a 1. 0 significa a ausência completa de elementos abstratos no componente e 1 significa que o componente contém apenas classes e interfaces abstratas.

Dependência entre I e A

Se você plotar no gráfico (Y - abstração, X - instabilidade) componentes “bons” de ambos os tipos: abstrato estável e concreto instável, obtemos o seguinte:

imagem

Mas, porque os componentes têm diferentes graus de abstração e estabilidade, longe de cair nesses 2 pontos (0, 1) ou (1, 0), e como é impossível exigir que todos os componentes estejam neles, devemos assumir que no gráfico A / Existem alguns pontos que determinam as posições ideais para os componentes.

Esse conjunto pode ser derivado pela definição de áreas onde os componentes não devem estar localizados - em outras palavras, a definição de zonas de exclusão.

imagem

Zona de dor

Considere os componentes localizados perto do ponto (0, 0).

Eles são muito estáveis ​​e específicos. Tais componentes são indesejáveis, pois são muito difíceis. Eles não podem ser expandidos, porque não são abstratos e é muito difícil mudar devido à sua grande estabilidade. Quanto mais mudamos o componente que entra na zona de dor, mais ela traz. Isto é devido à complexidade de sua mudança.

Normalmente, os componentes projetados corretamente não devem estar próximos do ponto (0, 0).
No entanto, na realidade, existem entidades de software que se enquadram nessa zona. Por exemplo, o esquema do banco de dados, é o mais específico possível e muitas dependências se estendem para ele. Esse é um dos motivos pelos quais as alterações no esquema do banco de dados geralmente estão associadas a grandes problemas.

Zona inútil

Considere os componentes localizados perto do ponto (1, 1).

Tais componentes também são indesejáveis, porque eles são tão abstratos quanto possível e não têm dependências. Eles são simplesmente inúteis. Freqüentemente, essas são classes abstratas que nunca foram implementadas.

Como evitar entrar em zonas de exclusão?

Coloque os componentes próximos ou na sequência principal. Tais componentes não são "abstratos demais" por sua estabilidade e "instáveis ​​demais" por sua abstração. Eles não são inúteis e não causam muita dor. Outros componentes dependem deles na extensão de sua abstração, e eles mesmos dependem dos outros na extensão da especificidade.
As posições mais desejáveis ​​para os componentes são os pontos finais da sequência principal. No entanto, em sistemas grandes, sempre haverá vários componentes que não são suficientemente abstratos e não são estáveis ​​o suficiente. Tais componentes têm excelentes características quando localizados na sequência principal ou nas proximidades.

A distância para a sequência principal

Como é desejável que o componente esteja localizado na sequência principal ou próximo a ela, é possível determinar uma métrica que expresse a distância do componente ao ideal.

  • D: distância. D = | A + I - 1 | . Essa métrica usa valores do intervalo [0, 1]. Um valor 0 indica que o componente está diretamente na sequência principal. Um valor 1 indica que o componente está localizado na distância máxima da sequência principal.

Ao adotar essa métrica, você pode explorar todo o design próximo à sequência principal. A métrica D pode ser calculada para qualquer componente. Qualquer componente com um valor métrico D longe de zero requer revisão e reestruturação.

imagem

Conclusão do autor (Robert Martin)


“As métricas de gerenciamento de dependência descritas neste capítulo ajudam a quantificar a consistência da estrutura de dependência e abstração do design com o que eu chamo de design“ bom ”. A experiência mostra que existem boas dependências, existem más. Essa classificação reflete essa experiência. No entanto, as métricas não são a verdade última; estas são apenas medidas baseadas em um padrão arbitrário. Essas métricas são imperfeitas - na melhor das hipóteses, mas espero que você as ache úteis. ”

Cara, fico feliz se você ainda estiver comigo. Isso é tudo com a primeira parte. Embora ainda haja muitos tópicos, os pensamentos detalhados do autor não foram afetados. Ainda assim, o principal objetivo do meu artigo não é recontar o livro; caso contrário, você ficaria mais satisfeito em ler o original. Eu, subi e já fui especificamente longe demais com a quantidade de conteúdo, mas serei bastardo, tentei não inflar o máximo que pude. Volta!

Segundo dia. Umm, ou seja, Parte 2


Introdução


O que eu tenho passado por tanto tempo? "Ah, sim ... Somos como arquitetos, ou realmente queremos ser eles, certo?"

O que nós temos? - Algum tipo de projeção miserável, ou talvez um sistema monstruoso, PROJECT, sua mãe, bem, ou finalmente ainda não há nada, mas apenas esfregamos as mãos, olhamos o calendário e descobrimos o quão bem teremos que conversar.

Não existem nós, eu trabalho sozinho! Ou talvez nós, com um ajudante, na garagem, estivéssemos preenchendo uma nova Apple, por que não? Bem, ou somos o exército e todos fazemos parte de uma empresa robusta, estamos trabalhando duro, como os negros dos pobres em casa (ou seja, os afro-americanos, é claro, você entende), ou talvez estejamos chutando em silêncio para não sermos demitidos. Por um salário alto, com bônus, biscoitos e uma vista da cidade de Moscou ou por puro entusiasmo, por uma idéia e uma participação em uma startup que naturalmente fica um inferno quando decola.

Na verdade, isso não importa. O que é importante é isso: todos nós, no final, simplesmente queremos que nossa ideia não se dobre prematuramente, bem, pelo menos antes de nossa partida, e há todas as chances disso. Sim, sim ...

E o que fazer agora, você pergunta? Então, se você não tem um irmão mais velho no escritório, o irmão não pode ficar sem um terceiro olho.

Resumo da primeira parte


Na última parte do artigo, falamos um pouco sobre métricas que permitem aos arquitetos medir seus números em números para refletir o grau de qualidade da arquitetura de seu sistema.

A - abstração do componente
I - instabilidade do componente
D - distância da sequência principal no gráfico A / I Foram

reveladas zonas erógenas das zonas de dor e futilidade .

Chegamos à conclusão de que, idealmente, A deve aumentar e diminuir proporcionalmente a uma diminuição e, consequentemente, um aumento em I. Componentes bem projetados devem estar na ou pelo menos perto da sequência principal, ou seja, D deve estar o mais próximo possível de zero e as dependências entre os componentes devem ser acíclicas e direcionadas à estabilidade.

Eu também espero que todos entendam que alguns componentes podem conhecer muitos outros, enquanto outros não devem saber nada. Assim como nos estados escravistas antes da chegada do bom tio Abraão, pelo contrário, os negros (no sentido de afro-americanos) não eram permitidos nichrome (em termos de conhecimento e não apenas); no nosso caso, os componentes mais importantes do sistema deveriam ter um mínimo de conhecimento, eles deve ser auto-suficiente e abstrato a partir de diferentes detalhes.

E o terceiro olho? Arquitetura Limpa PHP- uma ferramenta que surgiu como resultado da leitura de um livro, graças ao tio Bob (Robert Martin) por pensamentos valiosos e desejo louco de visualizar tudo, pela conveniência da análise e automatizar, pela possibilidade de incluir várias verificações no CI / CD (semelhante ao PHPStan, Phan e outros, apenas para identificar exatamente problemas arquitetônicos).

Ferramenta e projeto de teste. Introdução ao tópico


Fuf, tudo parece ser uma teoria ... Agora você pode até sujar as mãos para obter detalhes.
E então para mim agora não tenho cavalos abstratos no vácuo para esfregar, e você tem o fim da leitura menos motivo para me chamar de mudiloy, por causa do qual você fodeu gastou tanto tempo, eu tinha que prosrat gastar um pouco dele e preparar uma demonstração projeto, que, sobstna, agora vamos fazer hara-kiri. Para os caras “superdotados” que, sem dúvida, serão e querem sair nos comentários, sobre seus detalhes, enfatizo - este é um projeto DEMO .
Piquei em cerca de meio dia, grosso modo, no joelho da minha namorada. Afinal, não posso levar e escoar para o público em geral os detalhes dos projetos de combate com os quais tenho que trabalhar ... Os caras dos feridos não vão entender, eles vão me mostrar, mas eu preciso disso? Bem, se você é um rapaz simples, não um dos "particularmente destacados", sou péssimo por uma introdução tão longa, só tive que correr os riscos e reduzir a ameaça potencial de procriação nos comentários dos bazares sobre nada.

Portanto, o próprio projeto está aqui github.com/Chetkov/php-clean-architecture-example-project .

No futuro, ele poderá se tornar uma loja on-line completa. Eu sou certamente um perfeccionista feroz, mas você precisa ser um absurdo completocomedor de sol e fígado longo, além de sofrer de insônia, a fim de gastar tanto tempo no “coelho experimental” e na moda doces dele. Como você entende, este projeto nunca será levado à sua conclusão lógica , no entanto, como todos os outros, até projetos de combate.

Embora não seja tão ruim. No momento, possui: usuário, produto e pedido , bem como cenários: registro do usuário, alteração de senha, adição de um produto e reserva de um pedido .

O projeto está mais ou menos funcionando, você pode cloná-lo e executar scripts a partir da pasta sandbox, embora, na verdade, eu nem conseguisse fazer isso, porque para a análise da arquitetura, o projeto não requer operacionalidade.

No futuro, lançarei links para confirmações específicas para corrigir imediatamente os pontos técnicos descritos no artigo.

Estado inicial

: suponho que você já tenha se familiarizado com a estrutura. Para que possamos seguir em frente.

Nós incluímos a arquitetura limpa do PHP :
composer require v.chetkov/php-clean-architecture:0.0.3


Criamos e configuramos o arquivo de configuração

Visualização para análise


Executamos no console (na raiz do projeto):

vendor/bin/phpca-build-reports
ou
vendor/bin/phpca-build-reports /path/to/phpca-config.php

E em resposta, obtemos:

Report: /path/to/reports-dir/index.html

O relatório consiste em 3 telas:

1. Informações gerais sobre o sistema

imagem

Essa tela exibe:

O mesmo gráfico A / I mostrando a dispersão dos componentes:

imagem

Gráfico mostrando a distância dos componentes da sequência principal:

imagem

E um gráfico mostrando os relacionamentos entre os componentes: As

imagem

setas indicam a direção das dependências e os números nelas indicam a força da conexão.

Porque Os IDEs modernos fornecem uma maneira fácil de refatorar (eles mesmos encontram e corrigem todas as áreas em que o método ou a classe é explicitamente chamado, por exemplo, ao renomear ou transferir para outro espaço de nome), peguei o número de elementos do módulo de dependência usado pelo módulo dependente para melhorar a comunicação.

Por exemplo: os elementos do módulo de serviços conhecem 12 elementos do módulo de modelo e os elementos de infraestrutura conhecem 1 elemento de serviços . Etc.

A propósito, o que é * indefinido *? Bro, a pergunta esperada. Este é um módulo criado automaticamente para todos os elementos que, durante a análise do sistema, não puderam ser atribuídos a nenhum dos conhecidos (ou seja, aqueles listados no arquivo de configuração).

Se você corrigir a configuração desta maneira:

imagem

No processo de análise do sistema, os pacotes conectados via compositor também serão levados em consideração (eles mesmos não serão digitalizados, mas a imagem ficará muito mais completa).

A propósito, em vendor_path, você precisa especificar o caminho para o diretório do fornecedor e em caminhos excluídos para os diretórios dos pacotes que queremos excluir (por exemplo, se descrevermos algum pacote na principal configuração dos módulos para verificação).

Depois de ativar vendor_based_modules o gráfico mudou, embora não tenhamos alterado a configuração dos próprios módulos

imagem

2. Informações detalhadas sobre o componente

imagem

Aqui também vemos:

  • Gráfico de interconexões , mas não de todo o sistema, mas apenas dos componentes envolvidos
  • Gráfico A / I mostrando apenas o componente atual
  • Principais recursos do módulo

    imagem

e
  • Gráfico de dependência de saída mostrando o número e a lista de arquivos no módulo atual, dependendo dos arquivos de outros módulos.
  • imagem

  • E um gráfico das dependências recebidas , mostrando o número e a lista de arquivos em outros módulos, dependendo do módulo atual.

    imagem

Os últimos 2 gráficos, na minha opinião, são especialmente interessantes, porque é fácil encontrar dependências indesejadas sobre eles, mas mais sobre isso mais tarde.

3. Informações detalhadas sobre o elemento componente

imagem

Aqui você pode ver:

  • Principais características do elemento, como abstração de tipo, instabilidade, primitivo e a qual componente pertence e o modificador de acesso .

"Che, um modificador de acesso à classe em PHP?" - você diz, perfurando um buraco na área do templo com o dedo, certo? Não se apresse, eu sei que não há aulas particulares no calor, mas seria legal se elas fossem? Em geral, mais sobre isso mais tarde.

  • Gráfico de dependência , que reflete a interação do elemento em consideração com outros elementos do sistema

  • E tablets com dependências de saída e entrada

    imagem

Com a descrição das telas finalizadas, vá para as configurações para escolher como ele pode ser configurado.

Opções de configuração


Limitando a distância máxima permitida à sequência principal (para todos os componentes)

Primeiro, vamos tentar definir todos os componentes para a distância máxima permitida para a sequência principal. Seria tolice pensar que todos eles estarão na diagonal principal, porque o mundo não é perfeito, então sejamos realistas. Eu faço 0,3

imagem

Reiniciar o comando de geração de relatório e ver imediatamente a violação na página principal. O componente do modelo excede a distância permitida em 0,192

imagem

Limitando a distância máxima permitida para a sequência principal (para um componente específico)

É ótimo, mas vamos assumir que é o componente do modelo que pode violar essa restrição. Coisas diferentes acontecem ... Afinal, muitas vezes já não temos sistemas ideais com os quais temos que trabalhar, apoiá-los e melhorar. Alguém entende que ninguém será capaz de reduzir rapidamente essa distância, mesmo provavelmente com um deus (espero que ele me perdoe).

Na minha opinião, o principal é corrigir o estado atual, trabalhar em direção a melhorias e controlar a situação para não agravar.

Novamente, vá para a configuração e defina max_allowable_distance , apenas para um módulo específico. Eu fixo em seu valor atual 0,492

imagem

ZBS, agora tudo está normal novamente.

imagem

Mas se, com alguns ** ka Vasya, ele fumar algo de novo e piorar - corte as mãos! Um CI / CD que inclui a execução do comando phpca-check (falaremos sobre isso mais tarde) o repreende, talvez até uma linguagem suja, e é claro que destacará erros.

Controle de dependência de componentes

O que mais seria bom ter em nosso arsenal para lidar com uma arquitetura ruim? Claro, controle de dependência. Quem pode saber sobre quem, ou vice-versa, não deve saber.

O que você acha que pode a parte mais central do sistema, digamos, o domínio , para que seja completamente possível ao DDDowski saber algo sobre alguma infraestrutura fedorenta ?
Claro que sim, para alguns, é diretamente um atributo de sucesso (bem, estou falando daqueles que tornam o HTML misturado à lógica de negócios). Mas finalmente, como seja, eu não deveria ... eu certamente xs, mas todos os tipos de tipos inteligentes de livros dizem que isso não é patsansky.

Então vamos mexer assim ... Tudo está no mesmo lugar, na configuração de restrições para o modelo .

imagem

Hmm ... Até agora, todas as regras, porquemodelo sobre infraestrutura realmente não sabe de nada ...

Bem, então vamos nos divertir ... A estupidez é certamente rara, mas não achei nada melhor. Krch, no momento da criação do usuário, enviaremos o SMS e, no momento da criação do pedido, enviaremos os emails. E fazer isso através de implementações específicas de notificadores que estão na infraestrutura .

github.com/Chetkov/php-clean-architecture-example-project/commit/6bad365176b30999035967319a9c07fae69fabf9

Agora, examinamos o relatório ... Como podemos ver, os gráficos nas diferentes páginas do relatório destacam essa conexão como ilegítima.

Casa.

imagem

Relatório de componentes.

imagem

Nos gráficos do modelo "dependências de saída" e "dependências de entrada"infra-estrutura , vemos imediatamente elementos que violam a regra introduzida

imagem

Nas tabelas de "dependências de saída" de elementos de modelo e "dependências de entrada" de elementos de infraestrutura , da mesma forma.

PHPCAEP \ Modelo \ Usuário \ Usuário

imagem

PHPCAEP \ Infraestrutura \ Notificação \ Sms \ SmsNotifier

imagem

Assim como no gráfico de relacionamentos de elementos. Eu acho que no futuro me livrar completamente disso, porque não é muito informativo (especialmente para classes usadas ativamente, devido ao tamanho do nome dos nós + seu grande número)

imagem

Ações semelhantes podem ser executadas com a configuração allowed_dependencies .

imagem

O resultado será completamente oposto.

É possível compor uma configuração indicando para o módulo e proibido, e permitido (se houver um desejo, discutiremos mais detalhadamente nos comentários). Ainda não é possível especificar um componente, tanto em proibido quanto permitido ... Pensou-se em introduzir uma configuração para indicar prioridade, mas até agora não fiz isso e não tenho certeza do que farei. Tudo depende do seu feedback. Talvez tudo isso seja desperdiçado?

Classe pública / privada em PHP

Aprendemos como restringir e controlar a gama de conhecimentos dos componentes. Já não é ruim. Qual é o próximo?

E depois outro problema. O inimigo não dorme, embora na maioria dos casos esse inimigo, nós mesmos somos, ou nossos companheiros no escritório.

Afinal, você conheceu uma garota, conversou, descobriu algo sobre ela, talvez até cortejou, mas caramba, isso não funciona para você. Somos amigos e tudo mais ... Ela pode beijar você quando o conhecer, pode ouvir e apoiá-lo com uma palavra gentil, mas não lhe dá nada para matar . Então, do que estou falando ... Ah, aqui ... É tudo sobre acessibilidade.

Mas no código, constantemente ... Conecte um novo pacote, não passou um dia, mas ele já está sendo usado, mas direto para todos os lugaresde todos os lados. Metade da sua base de código já está vinculada a suas várias classes. Em suma, ele tem uma conexão muito íntima com o resto. Talvez em algumas situações essa seja a norma, mas não em todas, certo?

Você: “Tudo é bom, é tímido. Como resolver o problema? "
Eu: "Deixe apenas classes permitidas para interação e restrinja o acesso ao restante."
Você: "Mas no PHP não há modificadores de acesso para classes."
Eu: "Eu concordo, mas existe uma arquitetura limpa do PHP ".

Um exemplo agora será novamente de viciados em drogas, mas o que fazer.

Em projetos reais, é claro, os casos estão cheios de casos, mas eles podem trazer uma garrafa para drenar as informações e pedir que eles se sentem. É por isso que você tem que compor.

Vamos supor que no modelo , por algum motivo, haja apenas duas classes que outras pessoas possam conhecer ... Usuário e Ordem, todo o resto deve estar oculto.

imagem

O que nós temos agora?

Conte com o principal.

imagem

Você pode ver imediatamente quais componentes precisam ser revisados.

Subimos para ver o que há de errado com a infraestrutura .

imagem

No gráfico de “dependências de saída”, vemos elementos que violam a regra:

imagem

Na página de informações do elemento, da mesma forma.

imagem

Obteremos exatamente o resultado oposto se especificarmos private_elements na configuração .

imagem

Por exemplo, proibimos que todos saibam sobre o Fio.

Agora na

imagem

página principal: Na página de informações do componente de serviços :

imagem

E na página de informações do elemento PHPCAEP \ Model \ User \ Fio :

imagem

Monitorando violações dos princípios do ADP e SDP

Ainda assim, talvez seja necessário destacar a possibilidade de incluir verificações:

  • por violações do princípio ADP, ou seja, para a existência de dependências cíclicas no gráfico ( check_acyclic_dependencies_principle )
  • e por violações do princípio do SDP, ou seja, para dependências direcionadas de módulos mais estáveis ​​para menos estáveis ​​( check_stable_dependencies_principle )

imagem

Mas isso só funciona no phpca-check até agora e não é exibido no relatório. No futuro, acho que vou corrigi-lo.

Controle automático em CI / CD


Todo esse tempo eu falei sobre a primeira parte - visualização. E a análise que pode ser realizada em sua base. Chegou

a hora de fazer com que nossos amigos govnokodera colegas respeitáveis ​​sofram.

Lançamos no console (na raiz do projeto):

vendor/bin/phpca-check

ou

vendor/bin/phpca-check /path/to/phpca-config.php

Supõe-se que a execução desse comando seja adicionada ao processo de CI / CD do seu projeto. Nesse caso, o erro bloqueará a montagem adicional.

O script termina com um erro e lança algo como isto:

imagem

Eu dou o dente, a lista será muito mais longa em um projeto real.

Interrogatório

  1. Violação do princípio de aciclicidade de dependências (ADP)
  2. Da mesma forma, mas o ciclo é um pouco mais curto
  3. 2 elementos de modelo (listados) dependem da infraestrutura , o que não é permitido pela configuração
  4. Violação ADP novamente
  5. Outro loop e violação de ADP
  6. Violação do SDP porque um modelo mais sustentável depende de uma infraestrutura menos sustentável
  7. Mais uma vez dependência cíclica, seja errado
  8. 1 elemento de serviços (listado) depende de fio não público

Aproximadamente esse resultado, temos graças aos nossos esforços e diligência em governar .

Agora vamos virar tudo na bunda. Bem, isto é, nem tudo, deixo as configurações naturalmente. Eu governo apenas o código.

Para iniciantes, faz sentido corrigir arquivos que violam as regras para as seguintes dependências. Neste projeto, a maioria dos ciclos provavelmente desaparecerá por si só, mas, em reais, definitivamente precisará mexer por mais tempo (embora isso dependa do grau de negligência do sistema e das configurações da configuração).

Solução de problemas

Eu removi um vício anteriormente inventado.

github.com/Chetkov/php-clean-architecture-example-project/commit/f6bbbff1313bb4a22dfb6061f347ef007ba3b422f

Reinicie o fornecedor / bin / phpca-check

imagem

Bem, há apenas uma configuração para editar, porque um exemplo foi realmente inventado por um viciado em drogas.

imagem

Novamente vendor / bin / phpca-check

imagem

E o CI / CD continuou!

Isso é tudo.

Posfácio


Pegue um quinto se você o ler até o fim; se não, cheire o pé na estrada (de qualquer maneira, você não viu isso).

Mas, falando sério, obrigado pelo seu tempo, não importa se você mesclou no meio ou leu, mergulhou em cada linha e analisou cada tela ou folheou as duas partes na diagonal. Obrigado mesmo assim.

Peço desculpas novamente se algo estava errado.

Talvez, meu modo de apresentação possa parecer a alguém muito imponente ou desrespeitoso, eu só queria diluir um pouco o artigo e de forma alguma queria ofender alguém. Acho que sem isso, seria muito seco e difícil de ler.

Estou realmente interessado em saber sua opinião e, se você tiver quaisquer pensamentos, idéias, sugestões ou objeções, vamos discutir nos comentários.

Código limpo e arquitetura flexível para você!

All Articles