Problemas de arquitetura em grandes projetos

O desenvolvimento de aplicativos para dispositivos móveis parece uma tarefa bastante simples. Parece o que fazer lá? Joguei algumas visualizações, ungi-a com alguma arquitetura, e é isso, o projeto está pronto, você pode enviar o aplicativo para a estação. Em uma série de artigos, compartilharei os recursos que encontramos ao desenvolver um aplicativo para um grande banco.


Considere 5 tópicos importantes. Obviamente, a maioria deles foi discutida mais de uma vez na comunidade, mas por trás de cada tópico há dor, lágrimas, tempo perdido e, o mais importante, a experiência que nos foi útil, e espero que seja útil para você.


imagem


No início do desenvolvimento de um aplicativo móvel, o líder ou o designer enfrenta a pergunta - qual padrão de arquitetura usar? Nosso estúdio possui um MVP de padrão arquitetural comum. O MVP puro certamente é bom em sua forma pura (veja a imagem abaixo), mas não seríamos desenvolvedores reais se não tivéssemos finalizado esse padrão. Eles não pararam em uma opção e temos dois ramos do MVP puro.


imagem


Portanto, na fase de design, fomos confrontados com a tarefa de escolher um e, com base em um padrão arquitetural geralmente aceito e compreensível, seguimos em frente. Mas, já em um estágio tão inicial, conseguimos cometer um erro, o que posteriormente nos trouxe muitos problemas.


Vejamos dois de nossos MVPs em esteróides.


SurfMVP


imagem


A imagem mostra que, comparado ao MVP usual, pouco mudou. Percebemos alguns problemas ao alternar entre telas nos aplicativos iOS. Uma grande quantidade de lógica para a criação de novas telas antes da transição se concentrar diretamente no UIViewController, pareceu-nos não muito correta, então a primeira coisa que fizemos foi destacar uma entidade de roteador separada, responsável por fazer transições entre telas no aplicativo.
Modelos no SurfMVP são os serviços que o Presenter chama para recuperar dados. Frequentemente, um serviço resolve as tarefas de todo o módulo, mas em situações difíceis você precisa interagir com vários.
A entidade Configurator é responsável por criar um módulo separado, inicializa todos os componentes necessários e é responsável por criar dependências entre eles.


imagem


A principal característica do SurfMVP é que cada camada no MVP é separada por um protocolo. A imagem mostra um diagrama das camadas e a relação dos protocolos entre elas. Protocolos são necessários para que cada camada seja separada da outra e, em teoria, seja facilmente substituída. Cada uma das camadas não deve divulgar detalhes da implementação.


Vamos considerá-los separadamente:


ViewInput - implementa o próprio Viewer , o Presenter mantém o link. Este protocolo descreve os métodos pelos quais o Presenter pode controlar a Visualização , transferir dados, alterar estados e assim por diante.


ViewOutput - implementa o Presenter , o View mantém um link para ele. O protocolo descreve um conjunto de ações que podem ocorrer nos métodos Exibir e ciclo de vida, por exemplo, eventos de interação do usuário com a tela.


RouterInput - implementa o Roteador , e o Presenter mantém um link para ele, pois é o único responsável por iniciar mais navegação no aplicativo.


ModuleTransitionable - View é implementado, o roteador mantém um link para ele. Este é o único protocolo "básico" no SurfMVP . É necessário para fornecer ao roteador um conjunto de métodos para trabalhar com a navegação do aplicativo.


ModuleInput - Implementa o Presenter . Este protocolo deve conter métodos pelos quais outro módulo que contém um link para esse protocolo pode alterar o estado do módulo atual.


ModuleOutput - implementa o Presenter do módulo de chamada, o link mantém o Presenter do módulo chamado. Se a tela de perfil puder ser exibida no módulo de notícias, o NewsPresenter deverá implementar o ProfileModuleOutput e o ProfilePresenter deverá conter um link para ele.
ModuleOutput é passado para o configurador do módulo chamado e instalado no Presenter . Contém métodos de módulo que afetam o comportamento do módulo de chamada.


Problema no SurfMVP


Com base em todos os itens acima, há um problema principal - a navegação. Embora a mensagem para destacar uma entidade separada do roteador fosse um problema de navegação, eles acabaram, mas não por muito tempo. O SurfMVP foi usado com sucesso em projetos com navegação simples e plana , sem DeepLinks e Push-Notifications complexos.


A imagem abaixo mostra esquematicamente a navegação no aplicativo com o SurfMVP. Cada módulo individual se comunica com o outro através de seu próprio roteador. Assim, a navegação de qualquer fluxo no aplicativo é construída.


imagem


Esse tipo de navegação é adequado para o caso em que o usuário passa pelo fluxo de sua escolha no aplicativo. Por exemplo, na imagem abaixo: o usuário passa pelas telas do ponto A ao ponto D, então ele próprio constrói uma pilha na qual precisa ir e retornar da mesma maneira.


imagem


Os problemas começam no momento em que é necessário transferir o usuário do ponto A para o ponto D, e isso deve ocorrer sem a participação dele. Por exemplo, se um usuário clicar em Push-Notification ou seguir um link de um aplicativo de terceiros. No caso do SurfMVP, teremos que adicionar um roteador global que controlará a navegação, independentemente de onde o usuário esteja atualmente no aplicativo. Para resolver esse problema globalmente, decidimos usar os coordenadores, vamos passar para eles.


imagem


SurfMVP Coordenado


imagem


O SurfMVP coordenado é um padrão arquitetural no qual, diferentemente do SurfMVP, removemos a entidade do roteador que estava dentro de cada módulo individual. O paradigma de construção de um aplicativo mudou um pouco. Os módulos não são mais totalmente independentes. Cada módulo, com exceção dos completamente reutilizáveis, está localizado em um UserFlow separado, que, conforme planejado, deve executar alguma ação geral que leva o usuário ao resultado desejado.


Um exemplo desse fluxo em nosso aplicativo é o fluxo de pagamentos. Os pagamentos são um conjunto de telas que permitem ao usuário fazer uma transferência ou pagamento de maneiras diferentes.


No SurfMVP Coordenado, a entidade Roteador substituiu a entidade Coordenador , que agora é responsável por navegar não apenas em um módulo separado, mas em um conjunto de módulos logicamente conectados entre si. Isso simplifica a navegação e o trabalho com o aplicativo. Esquematicamente, nosso aplicativo fica assim:


imagem


No topo está o ApplicationCoordinator, responsável pelo roteamento inicial no aplicativo. Por exemplo, um caso, quando o usuário estiver autorizado, o enviaremos imediatamente para a parte principal do aplicativo, caso contrário, o enviaremos para a tela de autorização.


Se tivermos Deeplinks ou Push-Notifications em nosso aplicativo, sempre podemos definir regras de inicialização e início para os coordenadores, de forma que eles construam a pilha diretamente no ponto D desejado, sobre o qual falamos anteriormente.


imagem


Esquematicamente, nossa navegação agora se parece com isso. Cada UserFlow individual se refere ao seu próprio coordenador, que decide o que acontecerá no futuro. A responsabilidade de transmitir dados e iniciar mais navegação agora cabe ao coordenador, ele já se comunica com outros módulos ou outros coordenadores para continuar construindo a pilha de navegação.


Prós e contras do SurfMVP coordenado


Vantagens:


  1. A principal vantagem da abordagem do coordenador é a capacidade de reutilizar blocos de navegação inteiros no aplicativo. Agora, de qualquer lugar do aplicativo, é possível ligar para esse coordenador e não pensar em outra coisa senão concluir seu trabalho.
  2. Como a lógica de navegação é isolada dentro de um coordenador separado, agora é muito mais conveniente seguir a navegação: basta abrir um arquivo e a imagem inteira diante de seus olhos. Não há mais necessidade de perfurar todos os módulos individuais para entender o que eles estão alcançando, montar o aplicativo e analisar o design.
  3. É mais conveniente projetar em equipes grandes. É suficiente, no estágio de design de um novo recurso separado, alocar tempo para construir toda a navegação e inicializar todos os módulos, após o qual delegará o desenvolvimento a um grande número de desenvolvedores, e haverá muito menos problemas com a integração dessas telas entre si.
  4. A integração de Deeplinks e Push-Notifications não é mais uma dor de cabeça.

Desvantagens:


Como em qualquer abordagem arquitetural, há desvantagens no SurfMVP coordenado.


  1. Grandes coordenadores doem. Devido à concentração de toda a lógica em um só lugar, fica muito mais difícil não se afogar em um grande número de linhas de código. Se você não seguir o princípio da responsabilidade compartilhada, é claro que o coordenador poderá se transformar em um grande monstro, e todas as vantagens da legibilidade do código evaporarão facilmente.
  2. Você precisa escrever muito para obter beleza no código. Devido ao grande número de camadas no aplicativo, cada uma das quais é responsável por uma ação separada, é necessário romper essas camadas para alcançar o coordenador desejado.
  3. Vazamentos de memória - o problema não é novo, mas você deve seguir este assunto para não entrar no buraco. O principal motivo para vazamentos de memória ao trabalhar com coordenadores é reter ciclos nos retornos de chamada do módulo. Portanto, você precisa monitorar cuidadosamente os vínculos fortes dentro dos fechamentos.

Caso típico

Um caso típico é a inicialização do novo coordenador e a implementação do encerramento finishFlow. A captura de um weak coordinator é obrigatória; caso contrário, o coordenador fará referência a si mesmo, o que levará a um vazamento na forma de AuthCoordinator.


  func runAuthFlow() { let coordinator = AuthCoordinator(router: MainRouter()) coordinator.finishFlow = { [weak self, weak coordinator] in self?.removeDependency(coordinator) } self.addDependency(coordinator) coordinator.start() } 

Conclusões


Na fase de design, subestimamos a complexidade do projeto e escolhemos a abordagem arquitetônica errada. Mas esse erro ajudou a formar um conjunto de regras e abordar com mais cuidado a escolha da arquitetura ao inicializar projetos.


Quando usar o SurfMVP Coordenado


De fato, quando você quiser, use-o, mas aderimos às seguintes condições:


  • A estrutura das telas é complexa e sujeita a alterações;
  • Existem Deeplinks e / ou Push-Notifications com navegação;
  • É necessário trabalhar em uma grande equipe;

Quando usar o SurfMVP


Não esquecemos nosso primeiro padrão arquitetural. Ainda o usamos no estúdio ao desenvolver projetos, se ele satisfizer as seguintes condições:


  • O projeto é pequeno o suficiente e não planeja se desenvolver rapidamente;
  • O projeto possui uma estrutura de tela muito simples e não está sujeita a fortes mudanças.

Materiais adicionais



Neste artigo, compartilhei um problema com a arquitetura que encontramos durante o trabalho. Obviamente, a escolha de qual arquitetura usar permanecerá com você. No próximo artigo, vou compartilhar os problemas de back-end em grandes projetos e contar como os resolvemos. Fique atento!

Source: https://habr.com/ru/post/pt485172/


All Articles