Group 21Group 22
51
Click outside or press esc to close

By Olympus Tech

04/01/2021 - 20:12

Estruturando os dados de uma aplicação de Software

Introdução

A última etapa antes de colocarmos a mão no código é definir a arquitetura da aplicação. A arquitetura consiste em como vamos fazer a divisão de responsabilidades da aplicação (inclusive a divisão dos arquivos em pastas no quesito organizacional do projeto).
Nós dividimos a etapa de arquitetura do projeto em duas:
  • Arquitetura de dados;
  • Arquitetura da aplicação (client).
Nesse artigo vamos tratar brevemente sobre como fazemos a idealização da arquitetura de dados de uma aplicação. Iremos utilizar como caso de uso para mostrar esse processo de arquitetura de dados o projeto do Memo - um projeto open-source de um aplicativo mobile de repetição espaçada focado no tema de programação. Nas próximas sessões, vamos discorrer sobre como fizemos a modelagem dos dados, como estes serão armazenados dentro da aplicação, quais tecnologias vamos utilizar para armazená-los e faremos também uma breve discussão sobre otimização na modelagem.

Tecnologias

A primeira etapa do processo de estruturação de dados da aplicação é definir quais tecnologias serão utilizadas. Essa etapa precisa preceder todas as outras porque a tecnologia afeta diretamente na modelagem dos dados da aplicação. Existem diversas possibilidades de tecnologias para utilizarmos na estruturação de um banco de dados local, sendo as mais conhecidas `SQL e NoSQL.
Para o projeto do Memo, como introduzimos brevemente no documento de requisitos técnicos, vamos utilizar a biblioteca sembast para fazer a persistência de dados local. Optamos por escolher essa biblioteca pelos seguintes fatores:
  • Está sendo mantida atualizada - na data na qual este artigo está sendo escrito, a biblioteca havia sido atualizada 14 dias atrás;
  • Possui considerável reconhecimento na comunidade: 500+ estrelas no github;
  • É mantida pelos mesmos criadores de outra biblioteca muito utilizada para persistência local no Flutter: sqflite;
  • É desenvolvida puramente utilizando Dart;
  • Possui suporte para todas as plataformas para as quais o Flutter consegue emitir binários: iOS, Android, Desktop (Mac & Windows) e até mesmo Web.
Como expresso no README do projeto, essa biblioteca utiliza um sistema de banco de dados NoSQL baseado em arquivos. Isso significa que, na hora de modelarmos os dados, devemos levar em consideração uma modelagem NoSQL.
É importante ressaltar, sempre na hora de escolher uma biblioteca externa, é conhecer não só seus benefícios, mas também seus pontos fracos. Na nossa análise sobre as funcionalidades da sembast, pontuamos uma questão que pode eventualmente impactar no futuro do projeto, inclusive em uma eventual migração para uma persistência na nuvem:
  • A biblioteca carrega todos os dados em memória na sua inicialização.
Por mais que a biblioteca utilize um arquivo local para armazenar os dados da aplicação, ela carrega todos estes dados para a memória uma vez que o banco de dados é inicializado. Isso tem um forte impacto na performance do aplicativo. Existem algumas maneiras de postergar este problema de performance caso ele se mostre um impeditivo, como por exemplo, segmentar o banco em múltiplos arquivos de banco de dados, visto que alguns dados armazenados são mais utilizados que outros, e essa segmentação faria que menos dados fossem carregados em memória. Porém é importante ter essa limitação em mente, principalmente porque com um grande número de dados isso pode acabar virando uma dor de cabeça.

Modelagem

Estruturas

Com a tecnologia do banco definida, a segunda etapa consiste na modelagem dos dados da aplicação. O Memo é uma aplicação de memorização espaçada utilizando flashcards, portanto, uma das models fundamentais da aplicação é o Deck. Vamos apresentar e discutir a model do Deck, porém foram necessárias outras definições que estão descritas em mais detalhes no Documento de Estrutura de Dados.
Um deck possui as seguintes propriedades: nome, descrição, categoria e uma lista de cartas com perguntas e respostas. Podemos formalizar a estrutura desse deck no seguinte JSON:
Deck:
Block:
Note que, conforme discutimos no último artigo, o conteúdo dos decks poderia se tornar facilmente um gargalo do projeto. Na estrutura acima mostramos como nós pensamos em resolver este problema de uma forma simples e escalável: vamos tratar as perguntas e respostas das cartas como blocos de conteúdo. Dessa maneira, não precisamos lidar com HTML utilizando WebViews - uma estratégia que havia sido introduzido no último artigo. Para quem já utilizou a ferramenta Notion, vamos seguir a mesma abordagem de blocos de conteúdos que eles utilizam.
Isso nos traz uma flexibilidade em lidar com diferentes tipos de dados, sem a necessidade de lidar com HTML, CSS e Javascript. WebViews tem grande potencial de criar muitas dores de cabeça em um projeto. Na experiência que tivemos até então, principalmente com Flutter, é sempre bom evitar quando não existe uma clara necessidade.

Stores

A biblioteca sembast expõe uma estrutura de banco de dados baseada em documentos, similar a como funcionam hoje o Firestore, MongoDB, entre outros. O conjunto de documentos, é denominado Store. Levando em consideração esse fator, dividimos a model do Deck em duas partes que serão armazenadas em duas stores diferentes:

Decks Store

Essa é a store que vai armazenar os decks da aplicação

Cards Store

Essa é a store que vai armazenar os cards da aplicação
Nós optamos em separar as cartas de um deck e armazená-las em uma store separada. Essa separação tem dois principais motivadores:
  • Contexto da aplicação (Fluxos)
  • Performance & Otimização da busca
Contexto da aplicação
Se olharmos para a interface da aplicação, podemos visualizar uma clara divisão destes dois tipos de dados. Existem fluxos, onde nós precisamos apenas informações dos decks e não precisamos de todas as cartas deles. Abaixo temos dois exemplos de telas onde as cartas do deck não precisam ser carregadas em memória para que as telas sejam construídas:
Performance & Otimização da busca
Além disso, devemos ter em mente que um deck pode ter uma grande quantidade de cartas. Se tivermos que carregar todas estas cartas em memória sempre que formos precisar das informações básicas do deck, isso gera um problema de performance na aplicação, pois ficamos carregando uma grande quantidade de dados em memória que podem nem ser utilizados.
Este mesmo problema de carregar um deck sem precisar carregar suas cartas ocorre de maneira inversa. Desejamos carregar as cartas dos decks sem precisar carregar o conteúdo dos decks em si. Na aplicação do Memo, nós possuímos fluxos onde faz sentido termos somente as informações das cartas, e não dos decks. A tela de progresso é um claro exemplo disso:
Para descobrirmos as estatísticas de uso do app, nos importa somente o conteúdo de todas as cartas de todos os decks. Não nos importa aqui, a relação das cartas com seus respectivos decks, tampouco as informações dos decks.
Por isso, nesse caso, termos as cartas separadas em uma store dedicada, nos facilitaria o acesso à todas as cartas de todos os decks de uma forma otimizada, sem termos que passar pelos decks. Se as cartas fossem uma subestrutura do deck, precisaríamos buscar todos os decks no banco e juntar todas as cartas destes respectivos decks. Com a store dedicada para as cartas, precisamos apenas buscar as cartas diretamente, pouco importando os decks as quais elas pertencem.
Ao final de todo o processo, é gerado o documento de estrutura de dados do projeto.

Conclusão & Próximos Passos

Esse documento inicia a etapa de desenvolvimento da aplicação. Com os dados estruturados, passamos para a arquitetura da aplicação. Como vamos separar as responsabilidades dentro de aplicação, organização dos arquivos em pastas e outras definições importantes que precedem o código.
Vale ressaltar que neste artigo discutimos apenas das duas principais estruturas da aplicação: os decks e suas cartas. Convidamos vocês a lerem o documento de estrutura de dados para verem um pouco mais de detalhes técnicos sobre as modelagens e algumas outras estruturas que foram criadas, como por exemplo a estrutura dos materiais de apoio.

Tem alguma dúvida?

Caso tenha alguma pergunta, feedback ou proposta envie um e-mail para hi@olmps.co.