Uma história sobre o que você precisa considerar para criar uma arquitetura de qualidade para o seu projeto. Como torná-lo inafundável e clientes satisfeitos.
Abaixo, consideraremos exemplos da vida real e tentaremos aprender com os erros dos outros. E, ao longo do caminho, elaboraremos um livro de recomendações úteis para o arquiteto da solução. Em todas as histórias - tarefas de arquitetura que começam com os requisitos primários do cliente e são acompanhadas por outras perguntas.

O artigo é baseado em um relatório de Alexey Bogachuk (arquiteto de soluções da EPAM) da conferência
HolyJS 2018 Piter . Sob a cena - vídeo e transcrição do relatório.
Abordagens para a construção de arquitetura e o papel do arquiteto de projeto
Swam - nós sabemos
Assim disseram os marinheiros do navio sueco Vasa. Eles apenas navegaram, fugindo do navio afundando, que acabara de ser jogado na água pelas rampas. O que Vasa tem a ver com isso?

Vamos começar com uma pequena história que faz você ter uma visão completamente diferente das abordagens para criar a arquitetura de aplicativos e o papel do arquiteto de projeto.
O rei sueco assinou um contrato com o arquiteto construtor de navios Henrik Hubertsson. Nos termos do contrato, Henrik teve que construir um carro-chefe - a beleza da frota sueca, o melhor navio da Europa. Como principais patrocinadores, o rei e o tesouro participaram da coordenação de todas as principais características do navio; como resultado, o pedido foi formulado da seguinte forma:
- o navio deve ser o maior da frota do Báltico: 70 metros de comprimento, 10 de largura;
- você precisa de três decks, que acomodarão 300 soldados;
- ele deve ter 64 armas a bordo em duas filas;
- 3 anos são dados para construção.

Análogos de tal navio neste momento não existiam. No entanto, ele também não durou muito, afundando no meio da celebração de sua construção.
Quando eles tentaram descobrir por que isso aconteceu, descobriu-se que não havia desvios dos requisitos. O tamanho é o mesmo, o número de armas é normal, os marinheiros no convés são exatamente a quantidade necessária. No entanto, isso foi perfeitamente combinado com o fato de que as leis da física não permitiam que esse navio se sustentasse por um período de tempo na água.
Os seguintes erros de cálculo arquitetônicos de Henryk são evidentes (que, aliás, poderiam lhe custar a vida se ele tivesse sobrevivido ao tribunal):
- Todas as restrições conflitantes não foram equilibradas.
- Não havia gerenciamento de riscos, porque ninguém havia construído navios dessa magnitude antes.
- O gerenciamento de relacionamento com o cliente também estava ausente - Henrik não teve coragem de discutir com o rei.
- Tecnologias de construção incorretas usadas.
- O arquiteto concordou com requisitos impossíveis.
Como resultado desses erros de cálculo, o navio "afundou" mesmo na fase de projeto. A história é instrutiva, porque reflete a influência do ciclo da arquitetura no aplicativo que está sendo criado. Existem partes interessadas que formulam metas e requisitos, com base nisso, a arquitetura do projeto é construída e, em seguida, o próprio projeto. Um erro em um desses estágios pode valer a pena todo o projeto e, às vezes, o chefe / trabalho, Henrik Hubertsson, não deixa você mentir.
Amigos poderosos
Quantos aplicativos com a arquitetura errada estão mortos antes de escrever a primeira linha de código?
O ciclo de influência da arquitetura no projeto é o seguinte:

Da esquerda para a direita:
- Existem partes interessadas ou partes interessadas (no caso do navio, este é o rei e o tesouro).
- Eles têm seus próprios objetivos (o primeiro navio na Europa).
- Os objetivos ditam os requisitos (características específicas do futuro navio).
- Em seguida, são feitos desenhos, diagramas e desenhos.
- Construção no projeto.
Um erro em um desses estágios pode atravessar o futuro do seu projeto.
Manual do Arquiteto de Soluções
Vamos considerar exemplos da vida real e tentar aprender com os erros dos outros. Ao mesmo tempo, compilaremos um livro de recomendações úteis para o arquiteto da solução. Henrik Hubertsson ficou esgotado pelo fato de não ter um.
Se vivêssemos no tempo de nosso herói, quando os erros de arquitetura eram puníveis com a morte, este livro seria escrito em sangue.
Em todas as histórias, o kata arquitetônico (tarefas) será fornecido. Eles conterão uma solicitação simplificada com os primeiros requisitos do cliente, a essência do problema e a conclusão.
História do relógio de Jimmy
Requisitos do cliente- Substitua a solução atual da interface do usuário.
- Introduzir uma nova abordagem para o desenvolvimento e implementação desta solução.
- Precisa de uma melhor experiência do usuário.
- Ao mesmo tempo, siga todas as práticas recomendadas.
- Suporte para várias plataformas.
O que foi feitoOs requisitos são muito gerais, sem detalhes. Não está claro o que todos precisam fazer com isso. Ao mesmo tempo, a equipe de desenvolvimento está localizada em Minsk, e o cliente está em Montreal. Devido ao fato de haver sanções entre a Bielorrússia e o Canadá, o trabalho diretamente com o Canadá não pôde ser realizado. Foi decidido trabalhar com o cliente através de um escritório em Dublin. Devido a todos esses atrasos no tempo e na mediação, não foi possível entrar em contato com o cliente e, finalmente, descobrir os requisitos, fazer propostas de implementação.

Depois de algum tempo, um certo Jimmy ainda começou a responder perguntas e esclarecer requisitos, o desenvolvimento do projeto começou. Jimmy compartilhou avidamente conselhos, contatos foram tirados dele e correspondência foi conduzida diretamente com ele. Como resultado do trabalho, foi feita uma apresentação. É hora de mostrar os resultados. Foi organizada uma conferência com pessoas importantes do cliente, mas, estranhamente, Jimmy não estava entre elas e ninguém sabia quem era. Obviamente, tudo acabou sendo completamente diferente do que o cliente esperava. O fato é que a empresa não conhecia nenhum Jimmy, mas ele era um desenvolvedor comum e simplesmente compartilhou sua experiência e conselhos. Ele não tomou decisões e, em geral, não tinha nenhuma relação com o projeto.
Qual é o erro? No primeiro estágio de definição da arquitetura, as partes interessadas foram definidas incorretamente.
ConclusãoQualquer arquitetura começa com a identificação das partes interessadas. Para identificá-los, existem muitas abordagens, consideraremos uma delas - construiremos uma matriz RACI.
Raci
A abreviação significa: R - responsável, quem implementará; A - tomadores de decisão responsáveis; C - assessoria consultada (empresários); I - informado, pessoas que precisam ser informadas. Cada uma das partes interessadas deve ser atribuída a uma ou outra categoria. A matriz indica funções e tarefas.

Tendo construído essa matriz, podemos entender quem são as partes interessadas.
Além disso, percebeu-se que entre as partes interessadas há pessoas que fazem alegações falsas que afastam o projeto. Nesse caso, verificou-se que eram representantes de outros fornecedores que não estavam interessados no projeto. Mas a matriz RACI não sabe distinguir esses clientes, pois existe uma abordagem Onion.
Cebola
A abordagem da cebola é um pouco diferente das matrizes RACI.

Sua essência é que as camadas são criadas em torno do sistema, dentro das quais são indicadas as faces de certos clientes. Neste exemplo, desenvolvedores, DevOps, gerenciadores de conteúdo se comunicarão com o próprio sistema. Um pouco mais alto na abstração são as pessoas de negócios. Existem também reguladores externos: mídia, leis, etc. Por exemplo, para liberar um aplicativo em alguns países, você deve passar por uma auditoria conduzida por uma empresa terceirizada, revelando acessibilidade e outras qualidades exigidas pelo projeto, requisitos de partes interessadas externas.
Então, escrevemos no manual do arquiteto que o primeiro e o estágio necessário é determinar as partes interessadas.
História: não é rápido o suficiente
A empresa tinha um cliente de negociação, neste caso a velocidade de transação é muito importante. Com base nisso, vários requisitos foram formulados.
Requisitos do cliente- Seja mais rápido que os concorrentes
- É necessário que a transação ocorra em não mais que 0,5 segundos.
O que fezO projeto foi concluído, mas falhou. Porque Novamente, os requisitos não estavam totalmente corretos. O objetivo não era fazer transações na velocidade de 0,5 segundo, mas torná-las mais rápidas que um concorrente. Como resultado, a velocidade foi reduzida para 0,5 segundos, mas o concorrente chegou a 0,4 segundos. Vemos um erro ao determinar a meta de negócios. Por que o cliente precisa de um sistema?
Uma meta de negócios é apenas a ponta do iceberg, por trás dela estão os direcionadores de negócios, os reguladores e as metas internas da empresa. Muitas vezes eles permanecem desconhecidos. Estamos mais interessados em objetivos técnicos, que incluem um objetivo de negócios. Eles são regulados por princípios de negócios, por exemplo, ninguém deseja sacrificar a qualidade do trabalho ao implementar uma meta técnica, porque esse é um erro de cálculo no longo prazo. Tudo isso você precisa saber e ter em mente ao criar arquitetura. Além do fato de que projetos sem objetivo estão mortos inicialmente.
ConclusãoMesmo que você trabalhe em startups, cujo objetivo, muitas vezes, é testar novas tecnologias, de qualquer maneira o uso de novas tecnologias no projeto não é uma meta de negócios. O problema é que, se o objetivo é usar novas tecnologias, o projeto crescerá constantemente e exigirá novos investimentos financeiros e temporários desnecessários. As metas de negócios nunca devem ser negligenciadas ao projetar uma arquitetura.
Você pode encontrar recomendações úteis no livro "Discovering Requirements", autores - Ian Alexander, Ljerka Beus-Dukic.

A história de como os pioneiros do cavalo ordenhavam
Uma empresa que vende seguros tem seu próprio site. Funciona muito bem e possui uma boa funcionalidade estabelecida. Ele já possui uma lógica de negócios complexa.
Requisitos do cliente- Além do site, você precisa criar um aplicativo móvel que os funcionários usem em seus telefones
- O aplicativo deve ter o modo offline.
O que fezCom base nos requisitos, foi decidido escrever em React Native. O desenvolvimento começou. Durante a primeira chamada, foram recebidos aprimoramentos e acréscimos aos requisitos:
- A empresa emite telefones para os funcionários e todos trabalham no Android.
- O cliente está interessado apenas no modo offline.
- Prazo - dois meses.
Obviamente, a tarefa de classificar um produto de terceiros pronto com lógica de negócios complexa e escrever um novo em dois meses não se encaixa nesse período de tempo. Foi decidido usar o PWA (Progressive Web Apps).
Eu já tinha experiência com esse trabalho. Não apenas um aplicativo PWA foi escrito, foi isomórfico. Os serviços do servidor no cliente foram reutilizados, foram criados wrappers especiais com os quais você pode se comunicar com esses serviços. Foi criado um roteador que redirecionava todas as solicitações para o banco de dados MongoDB; no cliente, através do adaptador, eles trabalhavam com o IndexedDB. Esquema abaixo.

Portanto, os problemas estavam com os requisitos, que não são tão simples. Considere um exemplo de quais são os requisitos:

Existe um formulário e precisamos gerar erros de validação. Se o URL errado for inserido, precisamos exibir a página 404. O que há de errado com os requisitos? Eles falam sobre o que o sistema deve fazer. Mas para o arquiteto, qual sistema deve ser mais importante. Se você se aprofundar no que o sistema deve fazer, poderá se aprofundar nos detalhes e seguir o caminho errado. Esses requisitos são chamados funcionais, também são chamados de requisitos do MoSCoW. Palavras frequentemente encontradas nestes requisitos:

Todos os requisitos que contêm essas palavras não lhe interessam. Se você se concentrar em tais requisitos, um sistema monolítico será construído sem nenhuma arquitetura especial.
ConclusãoO arquiteto deve se concentrar em requisitos não funcionais, em particular em restrições e atributos de qualidade. O próximo kata sobre isso.
A história do corvo branco
Requisitos do cliente- Desenvolva um serviço separado que converte e armazena em cache dados no formato xml.
- Ele deve fazer isso de um sistema legado de terceiros.
O que fezDesenvolvemos um bom serviço de trabalho, fizemos no Node.js. Foi assim que o sistema como um todo começou a parecer esquematicamente junto com o novo serviço introduzido.

Obviamente, o Node.js é uma ovelha negra aqui, apesar de tudo ter funcionado bem.
O erro foi descoberto durante a transferência do serviço para clientes que não estavam familiarizados com o Node.js. Essa situação mostra perfeitamente o papel de identificar restrições para o projeto. Quais são as limitações?
- Técnico
- Tempo e orçamento
- Pilha de desenvolvedor do cliente
ConclusãoO arquiteto é obrigado a descobrir todas as restrições existentes que podem afetar o produto final. Limitações são decisões arquiteturais que foram tomadas antes e para você.
Em seguida, nos voltamos para os atributos de qualidade, temos um interesse especial neles.
Atributos de qualidade
Biblioteca muito segura
Existem muitos atributos de qualidade, basta ver a lista que a Wikipedia nos fornece.

A história é baseada no atributo "segurança". Quando você visita a biblioteca, dificilmente espera, usando um computador lá, que precisará passar por uma autorização de dois fatores digitando email, telefone e um código de verificação do telefone. No entanto, isso acontece. Vemos que a aplicação cega de atributos de qualidade também pode ser complicada.
Telefone na floresta
E o desempenho? É claro que não há pessoas que não se importam com o desempenho. Aqui está o script. Suponha que uma pessoa queira usar um aplicativo móvel do telefone enquanto estiver na floresta. Assim, afeta nosso sistema, mas não o todo, mas a interface da web. Por exemplo, ele precisa obter alguns dados em três segundos. Este é o cenário de desempenho que devemos obter.

São esses casos de uso que um arquiteto deve coletar para criar um sistema de alta qualidade na saída. Quando temos uma lista de requisitos de negócios, atributos de qualidade, restrições, reconhecemos todas as partes interessadas, começamos a abordá-las nos diagramas de gráficos. Esse endereçamento de atributos nos diagramas é chamado de tática arquitetônica. Quais táticas arquiteturais podem ser aplicadas a um sistema telefônico na floresta com base nos cenários existentes?
- Melhore o UX para que pareça a uma pessoa que a produtividade é maior.
- Otimize recursos (JS, CSS, imagens, fontes, etc.).
- Execute o cache.
- Adicione trabalhadores de serviço, caminho crítico.
- Aplique compactação.
- HTTP / 2.
No entanto, no caso de um telefone na floresta, o UX e o caminho crítico não nos convêm imediatamente. E, novamente, as táticas devem ser ditadas por scripts. Este é o trabalho do arquiteto, para escolher entre todas as táticas necessárias em um caso particular. Mas um aplicativo não é apenas um front-end. O desempenho também é afetado pelo DNS, back-end, bancos de dados e tudo isso também pode ser otimizado. Existem muitas táticas sobre como fazer isso, mas, novamente, a aplicação de uma ou outra depende do cenário de uso.
Vamos tentar usar o padrão CQRS (segregação de responsabilidade de consulta de comando). O uso desse padrão como tática afeta até várias camadas do aplicativo: o back-end e o front-end.

Digamos que exista um banco de dados legado muito lento, enviamos uma solicitação para lá e, após dez segundos, obtemos uma resposta. Além disso, ele é replicado e você precisa fazer entradas nas duas cópias. Nós na floresta com um telefone queremos ler rapidamente nossos dados desse banco de dados. O padrão diz que devemos separar os pedidos de leitura e gravação. Adicione um banco de dados de leitura rápida. Estamos adicionando todos os meios para sincronizar este banco de dados com um existente.

O uso desse tipo de tática complicada deve ser claramente ditado pelos requisitos.
Então, usamos algumas das táticas. Iniciamos o aplicativo e vemos que ele não ajudou, pois não há conexão com a Internet. Portanto, chegamos à tolerância a falhas que o arquiteto da solução deve cuidar.
Soldado de estanho firme
Ninguém quer que o aplicativo caia estavelmente várias vezes ao dia, todos querem tolerância a falhas.
Para que o aplicativo funcione de maneira estável, o princípio de falha rápida pode ser aplicado:
- Sempre verifique os pontos de integração com antecedência.
- Evite conexões lentas.
- Verifique suas entradas.
Por que usar isso, vejamos o exemplo da Conexão por mentiras. Esta é uma conexão que talvez algo pinga, mas na verdade não funciona. Isso pode acontecer entre o cliente e o servidor, o banco de dados e o servidor, entre os serviços. Aplique o padrão do disjuntor a ele.

Enquanto tudo está indo bem, não estamos fazendo nada. Assim que o tempo limite for excedido, ficaremos offline e, após algum tempo, faremos uma nova solicitação. Se a solicitação ocorrer novamente com um erro, novamente permaneceremos no modo offline com um tempo limite aumentado. E se a solicitação foi bem, voltamos ao modo online. Portanto, esse padrão permite que os pontos de integração sejam verificados e que conexões lentas sejam evitadas.
Submarino
Existem muitas abordagens para fornecer tolerância a falhas. Uma delas é a antepara (antepara, por exemplo, em um submarino). Seu significado é que o aplicativo é escrito de tal maneira que continua a funcionar, mesmo quando um erro aparece em um de seus componentes.
Temos uma lógica de negócios na qual enviamos dados e recebemos uma resposta. Começamos a enquadrá-lo com nossas táticas, adicionar validação, escala. Ocorreu um erro na lógica de negócios. Nós registramos. Como informações de erro, precisamos do contexto em que ocorreu. O problema é que, com esse quadro lógico, é improvável que o contexto persista, portanto, precisamos fazer um despejo de memória. Um despejo de memória é algo bastante volumoso e os erros de JavaScript ocorrem não tão raramente, portanto, é uma estratégia bastante cara para os recursos de computação. Precisamos dividir os erros em críticos e não, e fazer o dump apenas para os primeiros.
Balde com vazamento
Uma estratégia semelhante à descrita acima é usada no padrão Leaky Bucket.

Temos contadores para diferentes tipos de erros. Quando ocorre um erro, um contador de erros desse tipo é incrementado. Com o tempo limite, esse contador diminui. Mas se o número de erros começar a cair da balança, o contador não terá tempo para diminuir e, figurativamente falando, transborda o balde, após o que fazemos um despejo de memória. Em seguida, trabalhamos no erro que causou o estouro do contador.
Observe que o serviço que implementa esse padrão também será envolvido em táticas, validações e será escalado. Então a arquitetura é construída.

O que significam setas verdes? Diferentes serviços interagem entre si por meio de vários protocolos, bancos de dados e outros serviços.
Para aqueles que desejam aprender mais sobre os padrões de tolerância a falhas, o livro Padrões para software tolerante a falhas, de Robert S. Hanmer, será útil.
Também recomendamos o livro “Arquitetura de Software na Prática”, de Len Bass, Paul Clements, Rick Kazman. Nele, você aprenderá sobre outros atributos de qualidade e táticas para segui-los.
Exemplo de sobremesa
Case- Queremos oferecer aos clientes existentes melhorias para a plataforma atual.
- Cerca de 400 sites estáticos já foram escritos nesta plataforma.
- O problema é que é caro e longo.
- O gerenciamento de conteúdo também é caro e longo.
- A plataforma está escrita em Drupal.
Suponha que você possa usar as seguintes estruturas para resolver esses problemas:
Já encontramos partes interessadas. Precisa definir objetivos.O objetivo mais global é satisfazer o cliente.O objetivo do negócio é otimizar os custos do cliente (esse já é um objetivo interessante para o cliente).Os objetivos a seguir são mais particulares: reduzir o tempo necessário para trazer um produto ao mercado, reduzir o tempo de gerenciamento de conteúdo.Em seguida, as seguintes restrições são descobertas:- Você precisa escrever no Drupal, pois o cliente adquiriu uma licença e suporte por algum tempo.
- O projeto usa ReactJS e VueJS e o cliente deseja que continue, a empresa não está pronta para considerar outra estrutura.
Tendo definido atributos de qualidade, descobrimos:- É importante deixar a capacidade de oferecer suporte a todos os 400 sites (capacidade de manutenção).
- , (testability).
- (re-usability).
- (performance).
- (accessibility).
Quando construímos a arquitetura, precisamos seguir um determinado modelo. Considere o modelo C4. Vários diagramas são construídos.Diagrama de contexto:
Defina os papéis das pessoas que trabalharão com a plataforma. Neste exemplo, são visitantes, desenvolvedores e gerenciadores de conteúdo.Passamos ao diagrama de contêineres: com
base no contexto comercial, existe um site que os usuários visitam. Os desenvolvedores trabalham com o gerador de sites, os gerenciadores de conteúdo trabalham no hub de conteúdo. Fazemos integração com sistemas de terceiros no processo de atualização da plataforma.Um diagrama de componentes é assim:
Vemos que os desenvolvedores criam temas e componentes; o Serviço de modelos também funciona para eles, agregando esses desenvolvimentos. Há um ponto de integração entre o hub de conteúdo e o gerador de sites. Há também um serviço de modelo que pega temas, componentes e os conecta aos dados transmitidos do hub de conteúdo.Como acelerar o fluxo de trabalho de gerenciamento de conteúdo? É necessário fornecer a oportunidade para os gerenciadores de conteúdo trabalharem diretamente com o módulo de geração de sites. Lembrando todas as práticas anteriores, adicionamos as abordagens necessárias ao módulo Serviço de Modelo. Observe que o Drupal é usado exclusivamente no hub de conteúdo. Concluímos que, para geração estática, as estruturas NuxtJS ou Next.js, escritas em Vue.js e React.js, respectivamente, são adequadas. Como um substituto para os pontos de integração, é benéfico usar o GitHub e as ramificações, portanto, chegamos à abordagem JAM. Descriptografado como JavaScript, API, Markdown.
Pode-se ver que a pilha que foi decidida usar é diferente da original. Por um lado, usamos o Node.js e algum tipo de estrutura moderna. Vamos deixar o Drupal para o gerenciamento de conteúdo, mas, organizando-o a partir de nosso sistema, poderemos integrar o novo CMS no futuro, o que pode ser mais conveniente e mais rápido. Assim, chegou-se a um entendimento da abordagem de Javascript, API e Markdown.ConclusãoVocê precisa escolher cuidadosamente a pilha de tecnologia final. É isso que escrevemos em nosso livro do arquiteto.História final
OArquiteto de Casos identificou todas as partes interessadas, requisitos, metas, limitações. Então, um certo projeto foi feito. O desenvolvimento do aplicativo foi normal, mas no final o projeto falhou.Por que isso aconteceu?O fato é que os desenvolvedores do projeto não estavam cientes dos requisitos, partes interessadas, limitações e atributos de qualidade. O desenvolvimento foi realizado exclusivamente na forma de tarefas no rastreador de tarefas, o que levou ao colapso de todo o projeto.ConclusãoO arquiteto deve acompanhar o desenvolvimento do projeto na fase inicial, a fim de garantir que o desenvolvimento seja realizado de acordo com a arquitetura projetada por ele.
Sumário
Para resumir, escreveremos uma lista de coisas importantes para a arquitetura. Imprima e pendure em um local bem visível. Para que os navios que você construiu fiquem na água e, melhor ainda, naveguem na direção certa:- Qualquer arquitetura começa com a identificação das partes interessadas.
- Você precisa considerar as metas de negócios ao projetar a arquitetura.
- O arquiteto deve se concentrar em requisitos não funcionais, em particular em restrições e atributos de qualidade. Ele deve entender qual deve ser o aplicativo que ele está projetando.
- As táticas arquitetônicas devem ser ditadas pelos cenários de uso.
- Você precisa escolher cuidadosamente a pilha de tecnologia final.
- É necessário acompanhar o desenvolvimento do projeto na fase inicial, para que seja realizado de acordo com a arquitetura projetada.
, : 24-25 HolyJS , . — , .