Arquitetura limpa para o front-end



A web moderna é complicada. O número de estruturas e o ritmo de seu desenvolvimento fazem o desenvolvedor galopar. Alguém usa novos, alguém lê livros de moda. Às vezes, porém, a leitura e a energia são aprofundadas em arquitetura, OOP, TDD, DDD, etc. não corresponda às expectativas. E às vezes os livros são confusos! E, pior ainda, eles incrivelmente aumentam o FAC!

Atrevo-me a expor de maneira simples a idéia principal da Arquitetura Pura em relação ao frontend. Espero que isso seja útil para pessoas que desejam ler este livro e para quem já leu, mas não usa o conhecimento adquirido na vida real. E para aqueles que estão interessados ​​em como eu arrastei o front end aqui.

Motivação


A primeira vez que li o FAQ foi cerca de um ano e meio antes de escrever um artigo sobre o conselho de um dos desenvolvedores seniores. Antes disso, fiquei muito impressionado com os pequenos trechos do Pure Code adaptados para JavaScript ( https://github.com/ryanmcdermott/clean-code-javascript ). Eu mantive essa guia aberta por seis meses para aplicar as melhores práticas em meu trabalho. Além disso, minhas primeiras tentativas de ler o código limpo original falharam. Talvez porque seja muito aderente às características dos projetos front-end ou porque a leitura deva ser reforçada pela prática de longo prazo. No entanto, o Cheka é um guia prático que você pode seguir e aplicar imediatamente à função escrita (eu recomendo fortemente que você a leia primeiro se não estiver familiarizado).

Mas com a AT, é cada vez mais complicado - eis aqui conjuntos de princípios, leis e dicas para a construção do programa como um todo. Não há detalhes específicos que você possa tirar imediatamente e zayuzat no componente. Este livro foi desenvolvido para alterar a maneira como você escreve software e fornecer ferramentas e métricas mentais. É um erro considerar que o ChA é útil apenas para arquitetos, e tentarei transmitir isso usando um exemplo adaptado ao front-end.

Lógica de negócios e front-end




Quando se trata de ChA, muitas pessoas desenham círculos em sua imaginação (veja a figura abaixo), projetos de tamanho gigantesco, lógica de negócios incrivelmente complexa e várias perguntas - que tipo de pai colocar YuzKeysy? A idéia da aplicabilidade dos princípios de ChA à criação de um componente de acordeão é desconcertante. Mas os problemas que surgem ao desenvolver interfaces modernas exigem uma atitude séria. Interfaces modernas são complexas e frequentemente dolorosas. Primeiro de tudo, vamos descobrir o que é mais importante no front-end.

Todos sabem há muito tempo que você precisa separar a lógica comercial de uma apresentação e observar os princípios do SOLID. O tio Bob no CHA falará sobre isso em detalhes. Mas o que é lógica de negócios? R. Martin oferece várias definições e subcategorias, uma delas soa aproximadamente Assim:
Lógica de negócios (regras de negócios) são regras que trazem dinheiro para as organizações, mesmo sem automação.
Em geral, a lógica de negócios é algo muito importante. (Ouço os backenders rirem quando ouvem sobre a lógica de negócios pelas frentes). Mas sugiro que os candidatos à frente relaxem um pouco e se lembrem do que pode ser muito importante em nossa frente. E, por mais estranho que pareça, a coisa mais importante na frente é a interface do usuário. O primeiro passo para entender o AA para mim foi a percepção de que a lógica da interface deveria estar no centro do círculo da frente! (fig. sob o cabeçalho).

Entendo que esta é uma afirmação infundada, e pode-se argumentar fortemente com ela. Mas vamos lembrar que o que está mudando na frente frequentemente e dolorosamente? Não conheço você, mas muitas vezes me pedem para alterar o comportamento de elementos interativos - acordeões, moldes, botões. Vale ressaltar que o layout (design) muda com muito menos frequência do que o comportamento da interface. Mudanças e atores ( iniciadores de mudanças ) são especialmente discutidos na AP , observe.

Molde desagradável


Não vamos nos preocupar muito com terminologia. Damos um exemplo e esclarecemos um pouco o que chamo de lógica da interface.

Existem algumas entradas com validação e mapeamento condicional. Você pode preencher apenas um campo e o formulário é válido, mas entradas opcionais serão exibidas. (Preste atenção, não nos importamos com o tipo de dados. O principal é a interatividade)





Espero que a lógica seja clara. E, a princípio, a implementação não levanta questões. Você coloca essa coisa em um componente da sua estrutura e reutiliza-a com ousadia de outras formas como parte integrante e independente. Em algum lugar, é necessário passar sinalizadores para alterar ligeiramente a validação, em algum lugar com um pouco de layout, em algum lugar nos recursos de conexão com o formulário pai. Em geral, codifique em gelo fino. E uma vez, você obtém uma tarefa desta forma (e a utiliza) e congela por alguns dias, embora pareça levar 15 minutos. Maldito seja o gerente, moldes e tarefas chatas e chatas.

Onde está o erro? Parece que você está trabalhando há mais de um dia, pensou muito bem na composição dos componentes, tentou diferentes hóquei, transmitiu modelos através de adereços, conjurou com a estrutura para a construção de formulários, até tentou seguir o SOLID ao escrever esses componentes.

Nota: componentes em ChA! == componentes em react / angular e co.

Mas o fato é que você esqueceu de destacar a lógica. Acalme-se um pouco, volte para a tarefa e jogue a simulação.

Tarefa muito simples


A NA enfatiza que a arquitetura é crítica para grandes projetos. Mas isso não nega a utilidade das abordagens de AC para pequenas tarefas. Parece-nos que a tarefa é simples demais para falar sobre a arquitetura de alguma forma. E como designar uma maneira de fazer alterações, se não através da arquitetura? Se você não definir os limites e os componentes da interface interativa, será ainda mais fácil ficar confuso. Lembre-se com que pensamentos você assume a tarefa de alterar a forma no seu trabalho.

Mas vamos ao que interessa. O que é esse formulário? Estamos tentando modelar, expressando pensamentos com pseudo-código.

ContactFormGroup
  +getValue()
  +isValid()

Na minha opinião, toda a nossa tarefa para o mundo exterior é criar um objeto com dois métodos. Parece fácil - do jeito que está. Continuamos a descrever o que vemos e o que nos interessa.

ContactFormGroup
  emailFormGroup
  phoneFormGroup
  getValue()
    => [emailFormGroup.getValue(), phoneFormGroup.getValue()]
  isValid()
    => emailFormGroup.isValid() || phoneFormGroup.isValid()

Provavelmente, vale a pena indicar explicitamente a aparência de entradas menores. Quando um gerente pede que você faça rapidamente a 10ª edição do formulário, tudo parece simples em sua cabeça - exatamente como esse pseudocódigo.

EmailFormGroup
  getValue()
  isValid()
  isSecondaryEmailVisible()
    => isValid() && !!getValue()

Podemos identificar um lugar para demandas estranhas ...

PhoneFormGroup
  getValue()
  isValid()
  isSecondaryPhoneVisible()
    => isValid() && today !== ‘sunday’

Uma das implementações de nosso formulário no Angular pode ser assim.

Implementação do ContactFormGroup (Angular)
export class ContactFormGroup {
    emailFormGroup = new EmailFormGroup();
    phoneFormGroup = new PhoneFormGroup();

    changes: Observable<unknown> = merge(this.emailFormGroup.changes, this.phoneFormGroup.changes);

    constructor() {}

    isValid(): boolean {
        return this.emailFormGroup.isValid() || this.phoneFormGroup.isValid();
    }

    getValue() {
        return {
            emails: this.emailFormGroup.getValue(),
            phones: this.phoneFormGroup.getValue(),
        };
    }
}

export class EmailFormGroup {
    emailControl = new FormControl();
    secondaryEmailControl = new FormControl();

    changes: Observable<unknown> = merge(
        this.emailControl.valueChanges,
        this.secondaryEmailControl.valueChanges,
    );

    isValid(): boolean {
        return this.emailControl.valid && !!this.emailControl.value;
    }

    getValue() {
        return {
            primary: this.emailControl.value,
            secondary: this.secondaryEmailControl.value,
        };
    }

    isSecondaryEmailVisible(): boolean {
        return this.isValid();
    }
}


Assim, obtemos três interfaces (ou classes, não importantes). Você deve colocar essas classes em um arquivo separado em um local de destaque para poder entender as partes móveis da interface, simplesmente olhando para ela. Nós identificamos, puxados e enfatizou a lógica problemática, e agora nós controlar o comportamento do formulário, combinando a aplicação de partes individuais de ContactFormGroup. E os requisitos para diferentes casos de uso podem ser facilmente representados como objetos separados.

Essa parece ser uma implementação padrão do padrão MVC e nada mais. Mas não descartaria coisas elementares que, na prática, não são respeitadas. A questão não é que tiramos um pedaço de código da visualização. O ponto é que destacamos a parte importante que está sujeita a alterações e descrevemos seu comportamento para que ele se torne simples.

Total


ChA nos fala sobre as leis de criação de software. Ele fornece métricas pelas quais podemos distinguir partes importantes das menores e direcionar corretamente as dependências entre essas partes. Descreve os benefícios do POO e abordagens para resolver problemas através da modelagem.

Se você deseja melhorar a qualidade de seus programas, flexibilizá-los, usar OOP em seu trabalho, aprender a gerenciar as dependências em seu projeto, falar no código sobre a solução do problema e não sobre os detalhes de sua biblioteca, recomendo ler Arquitetura Limpa. As dicas e princípios deste livro são relevantes para qualquer pilha e paradigma. Não tenha medo de experimentos em suas tarefas. Boa sorte

PS Sobre gerenciamento de estado


Um grande obstáculo para entender NA pode ser um compromisso com uma biblioteca de gerenciamento de estado. De fato, bibliotecas como redux / mobx resolvem simultaneamente a tarefa de notificar componentes sobre alterações. E para alguns desenvolvedores, uma frente sem um gerente de estado é algo impensável. Acredito que os princípios de ChA possam ser aplicados com e sem o uso de um gerente de estado. Mas, ao focar na biblioteca de gerenciamento de estado, você inevitavelmente perderá parte da flexibilidade. Se você pensa em termos de ChA e OOP, o conceito de gerenciamento de estado geralmente desaparece. A implementação mais simples sem gerenciamento de estado é aqui habr.com/en/post/491684

PPS


Sinceramente, mostrei a solução para uma tarefa de interface semelhante ao meu amigo - ele não gostou e reescreveu tudo para obter ganchos de reação. Parece-me que, em maior medida, a rejeição se deve ao fato de que o POO praticamente não é usado em projetos reais, e a maioria dos jovens desenvolvedores de front-end não tem a menor experiência com soluções de POO. Nas entrevistas, às vezes perguntam sobre o SOLID, mas geralmente apenas para eliminar os candidatos. Além disso, algumas rajadas de desenvolvimento no campo da OLP podem ser suprimidas por uma revisão. E muitas vezes é mais fácil para as pessoas organizar uma nova biblioteca do que ler um livro chato ou defender seu direito de tirar a lógica de um componente. Por favor, apoiem ativistas do OOP :)

All Articles