Neste artigo, quero considerar uma abordagem para dividir tarefas em subtarefas ao usar o Clean Architecture.
O problema de decomposição foi encontrado pela equipe de desenvolvimento móvel do NullGravity e, abaixo, como resolvemos o problema e o que aconteceu no final.

Antecedentes
No outono de 2018, estávamos desenvolvendo o próximo aplicativo para uma operadora de telecomunicações. Mas desta vez foi diferente. Os termos eram bastante rígidos e vinculados à campanha de marketing do cliente. A equipe do Android cresceu de 3 para 6 a 7 desenvolvedores. Várias tarefas foram realizadas no sprint e a questão era como decompô-las efetivamente.
O que queremos dizer quando falamos efetivamente:
- O número máximo de tarefas paralelas.
Isso torna possível ocupar todos os recursos disponíveis. - Reduzindo o tamanho das solicitações de mesclagem.
Eles não serão assistidos no programa e você ainda poderá detectar possíveis problemas no estágio de revisão do código. - Reduza o número de conflitos de mesclagem.
As tarefas fluirão mais rapidamente e não há necessidade de mudar o desenvolvedor para a resolução de conflitos. - Uma oportunidade para coletar estatísticas de despesas de tempo.
- Automatize a criação de tarefas no Jira.
Como resolvemos o problema?
Dividimos todas as subtarefas nos seguintes tipos:
- Dados
- Domínio
- Vazio
- UI
- Item
- Custom
- Integração
Dados e Domínio correspondem a camadas na Arquitetura Limpa.
Vazio, interface do usuário, item e personalizado referem-se à camada de apresentação.
A integração se aplica às camadas de domínio e apresentação.
Figura 1. Localização das tarefas relativas às camadas da Arquitetura LimpaVamos olhar para cada tipo individualmente.
Dados
Descrição do DTO, API, trabalho com banco de dados, fonte de dados, etc.
Domínio
Interface do repositório, descrição dos modelos de negócios, interatores.
A interface do repositório na camada de dados também é implementada.
Uma separação tão ilógica, à primeira vista, tornou possível isolar o máximo possível as tarefas dos tipos de dados e domínio.
UI
Criando um layout de tela básico e estados adicionais, se houver.
Item
Se a tela for uma lista de elementos, para cada tipo você precisará criar um modelo - Item. Para mapear o item para o layout, você precisa de AdapterDelegate. Usamos o conceito de
adaptador de delegação , mas com algumas
modificações .
Em seguida, crie um exemplo de trabalho com um item de lista no PresentationModel.
Vazio
Classes básicas necessárias para tarefas como interface do usuário ou item: PresentationModel, Framgent, layout, módulo DI, factory AdapterDelagate. Interfaces e implementações de ligação. Crie um ponto de entrada na tela.
O resultado da tarefa é a tela do aplicativo. Ele contém a barra de ferramentas, RecyclerView, ProgressView, etc. isto é, elementos comuns da interface, cuja adição poderia ser duplicada por diferentes desenvolvedores e levaria a inevitáveis conflitos de mesclagem.
Custom
Implementação de um componente de interface do usuário não padrão.
Um tipo adicional é necessário para separar o desenvolvimento de um novo componente de uma tarefa do tipo UI.
Integração
Integração de camadas de domínio e apresentação.
Como regra, essa é uma das tarefas que consomem mais tempo. É necessário reduzir as duas camadas e refinar os pontos que poderiam ter sido perdidos nas etapas anteriores.
Ordem das tarefas
Tarefas como dados vazios e personalizados podem ser iniciadas imediatamente após o início do sprint. Eles são independentes de outras tarefas.
A tarefa de domínio é executada após a tarefa de dados.
As tarefas da interface do usuário e do item após a tarefa vazia.
A tarefa de integração é a última a ser concluída, pois requer a conclusão de todas as tarefas anteriores.
Figura 2. Execução da tarefa TimelineApesar de algumas tarefas serem bloqueadas por outras, elas podem ser iniciadas ao mesmo tempo ou com um pequeno atraso. Essas tarefas incluem domínio, interface do usuário e item. Assim, o processo de desenvolvimento é acelerado.
Figura 3. Linha do tempo de execução de tarefas com bloqueiosPara cada funcionalidade específica, o conjunto de tarefas pode variar.
Pode haver um número diferente de tarefas vazias, interface do usuário, item e integração, e alguns tipos podem simplesmente estar ausentes.
Automação de processos e coleta de estatísticas
Para coletar estatísticas ao criar uma tarefa, um rótulo é atribuído a ela. Esse mecanismo no futuro permitirá analisar o tempo gasto em cada tipo e formar os custos médios. As informações coletadas podem ser aplicadas ao avaliar um novo projeto.
Para automação, também conseguimos encontrar uma solução. Como as tarefas são típicas, por que sua descrição em Jira deve ser diferente. Desenvolvemos modelos para resumo e descrição. No início, era apenas um arquivo json, o analisador Python desse arquivo e a API REST do Jira foi conectada para gerar tarefas.
Nesta forma, o script durou quase um ano. Hoje, ele se transformou em um aplicativo de desktop completo, escrito em Python, usando a arquitetura PyQt e MVP.
Talvez o MVP estivesse sobrecarregado, mas quando a primeira versão do Tkinter travou a versão 10.14.6 do MacOS e nem todas as equipes puderam usar o aplicativo, reescrevemos facilmente a exibição do PyQt em meio dia e funcionou. Mais uma vez, estávamos convencidos de que o uso de abordagens arquitetônicas, mesmo para tarefas simples, tem suas vantagens. Uma captura de tela do JiraSubTaskCreator é mostrada na Figura 4.
Figura 4. A tela principal do JiraSubTaskCreatorConclusões
- Desenvolvemos uma abordagem para decompor tarefas em subtarefas minimamente dependentes uma da outra;
- Modelos gerados para descrever tarefas;
- Recebemos pequenas solicitações de mesclagem, o que possibilita revisar e alterar cuidadosamente o código isoladamente
- Reduzido o número de conflitos com solicitações de mesclagem;
- Tivemos a oportunidade de avaliar e analisar com mais precisão o tempo gasto em cada tipo de tarefa;
- Parte automatizada do trabalho de rotina.