VirusMapBR o app para rastrear o COVID-19 que não foi.
Logo no começo da pandemia do Coronavírus resolvi desenvolver um aplicativo para rastrear os casos de COVID-19 no Brasil. O app ficou…
Logo no começo da pandemia do Coronavírus resolvi desenvolver um aplicativo para rastrear os casos de COVID-19 no Brasil. O app ficou pronto, mas não tive como publicá-lo nas app stores para que as pessoas pudessem utilizá-lo. É uma pena, pois já cruzamos a marca dos 4.5 milhões de casos confirmados e, infelizmente, dos 136 mil mortos e ainda não vi nenhuma ação de rastreamento de casos e contatos tracionando decentemente aqui no Brasil.
A idéia era simples: um aplicativo fácil de usar que coletasse informações de saúde e geolocalização de seus usuários e, com elas, montasse um mapa dinâmico para o acompanhamento da situação da doença no Brasil. As motivações eram nobres: "entender onde estão os focos de Covid-19 na comunidade e usar esta informação para conscientizar as pessoas sobre como evitar a propagação da doença, ajudá-las a se locomover com mais tranquilidade, entender a evolução da doença de maneira mais granular, ajudar a coordenar os esforços de suporte para as regiões mais críticas e até permitir uma retomada das atividades com mais segurança."
Para quem se interessar, num artigo anterior escrevi sobre como nasceu a idéia do aplicativo, minhas motivações para desenvolvê-lo e um pouco mais sobre como ele foi pensado e como funciona.
Agora, minha idéia é compartilhar os aprendizados desta aventura e o código como open-source. Assim, outros desenvolvedores poderão se beneficiar dos aprendizados, quem tiver curiosidade sobre como ele foi desenvolvido poderá olhar o código e quem desejar desenvolver algo parecido não precisará começar do zero.
Por que parou? Parou por que?
Como falei no começo do artigo, não consegui publicar o aplicativo nas apps stores do Google e do Apple para que ele pudesse ser utilizado. 😔 A razão é que as app stores deram uma atenção especial para aplicativos relacionados ao Coronavírus e à COVID-19 por se tratar de um tema sensível e para resguardar seus usuários de apps que pudessem usar a pandemia para se aproveitar deles.
Isto faz bastante sentido, mas não deixa de ser algo para pensarmos melhor a respeito. Até onde este tipo de preocupação é válido? Não poderíamos estar impedindo que apps autênticos e bem intencionados chegassem até as mãos de usuários que poderiam se beneficiar deles?
Em ambos os casos, Google Play Store e Apple App Store, a rejeição do app foi devidamente justificada e a comunicação continha mais detalhes sobre como estava sendo feita a aprovação de apps ligadas à pandemia do Coronavírus. Veja:
Resposta da Apple App Store:
Resposta da Google Play Store:
Uma coisa interessante é que, em ambos os casos, ficou claro que apenas apps associadas a orgãos governamentais e organizações de saúde poderiam ser publicadas. De novo, entendo a preocupação, mas me pergunto se isto não limita muitos usos autênticos de um app desta natureza. E mais, desta maneira iniciativas independentes acabam ficando impedidas de usarem importantes canais de distribuição de aplicações.
Este é, com certeza, um assunto que daria pano pra manga: quais os limites das mega-plataformas de distribuição de informações e aplicações? Quais os riscos de depender delas? O que estamos ganhando e perdendo com elas? Mas isto é assunto pra outro dia. 😉
No final, cheguei a considerar me associar a alguma instituição de saúde para tentar viabilizar a publicação do VirusMapBR, mas acabei não progredindo nesta frente. Shame on me!
Vale notar que outras iniciativas, como por exemplo o Desviralize.org do pessoal da Blockforce, usaram um caminho alternativo para distribuição de sua solução e que não tinha este tipo de restrições: a WEB! No caso deles o app é uma aplicação web que pode ser usada a partir de qualquer browser e em qualquer dipositivo. Basta clicar no link (http://desviralize.org) e seguir as instruções. Lindo! Claro, o fato do app rodar no navegador traz alguns inconvenientes e restrições, mas é uma solução simples e poderosa.
É hora de fazer limonada!
Bom, agora que já fiz as pazes com o fato de que o resultado das longas horas* de código e estudos não irá para as mãos dos usuários, é hora de tirar algum proveito desta jornada. E a limonada que faremos tem três partes:
O que aprendi escrevendo meu primeiro app com Flutter e Firebase
O que aprendi sobre LGPD e privacidade de dados
Abrir o código fonte do VirusMapBR para a comunidade
(*) A título de curiosidade, usei um plugin para o Visual Studio Code chamado Code Time que mostra várias estatísticas do projeto. Segundo ele foram 257 horas de programação no App e umas outras 10 horas de código em alguns pequenos projetos paralelos para depurar bugs que encontrei pelo caminho. Foi divertido ver um pouco de atividade colorindo meu perfil no Github. ;-)
Vamos vamos à limonada! 🍋🍋🍋
O que aprendi escrevendo um app em Flutter e Firebase?
Já fazia um tempo que eu estava com planos de criar um mobile app. A última vez que escrevi um mobile app inteiro foi há mais de 15 anos. Os smartphones ainda não existiam e a diversão era criar apps em JAVA J2ME para rodar em celulares da Nokia.
Quando ouvi falar de Flutter achei interessante a idéia e resolvi estudar mais. Mais uma vez, meu amigo Georges Bennati Jr., teve um papel importante em me mostrar as vantagens desta plataforma, desconstruir alguns preconceitos e me guiar pelo caminho. Sem ele eu teria levado o dobro de tempo para criar o app. Thanks Bro!
Achei desenvolver em Flutter uma experiência bem satisfatória. Foi legal ver, aos poucos, o app nascer e ficar com um cara profissional (mas isto só foi possível com a ajuda do Josias Cunha que transformou meus rabiscos em uma UI de verdade). E foi mais legal ainda rodar o app em iOS e Android sem grandes dificuldades. Fora detalhes de configurações e alguns perrengues para "buildar" (sic) o app para iOS, praticamente não precisei escrever código específico para as diferentes plataformas.
Gostei muito de ver o "Hot Reload" do Flutter em ação. Fazia ajustes no código e ao gravar o arquivo as modificações eram imediatamente refletidas no emulador ou até mesmo no device (quando conectado via cabo). Minha percepção foi de um aumento de produtividade enorme quando comparado com minhas experiências anteriores de desenvolvimento móvel e também quando comparado com soluções mais modernas sem este tipo de funcionalidade.
A curva de aprendizado foi bem tranquila. No começo tive que me familiarizar com a sintaxe do Dart e com o funcionamento do Flutter. Depois fui me entendendo com os Widgets do Flutter, com o gerenciamento de estados, com os providers e com como refinar a interface. Não houve nada que eu quisesse fazer que não foi possível (o que nem sempre é verdade ao se experimentar um novo framework ou uma nova linguagem de programação).
Outra experiência bem positiva foi a de usar o Firebase pela primeira vez. Foi durante o Google I/O de 2016 que o Firebase me chamou a atenção. O Google já hávia adquirido esta solução a alguns anos e tinha feito várias melhorias nela. A idéia é bastante poderosa: um conjunto abrangente de serviços de "backend" que você pode usar sem ter que implementar e manter estes serviços. São serviços que quase toda aplicação necessita e que estão prontos para você consumir a partir de API e SDKs disponíveis para várias plataformas, inclusive Flutter.
No caso do VirusMapBR os serviços que utilizei foram: Authentication, Analytics, Crashlytics, Cloud Firestore, Storage e Functions. Tudo funcionou perfeitamente depois de sofrer um pouco com as configurações e com a integração dos serviços ao app.
Fiquei particularmente feliz com o serviço de autenticação, que me poupou muito tempo de desenvolvimento. Implementei a autenticação via Google Accounts e também via Número de Telefone e SMS. E poderia ter escolhido vários outros mecanismos suportados pelo Firebase Authentication.
Mas o que mais me impressionou foi o serviço de armazenamento de dados Cloud Firestore. Um banco de dados NoSQL para armazenar e sincronizar dados entre a nuvem e o App. A velocidade de sincronismo é surpreendente e, até onde vi, a escalabilidade também é (apesar de que não experimentei questões de escalabilidade na prática).
Apesar de ter sido apenas a minha primeira experiência com estas duas tecnologias, posso dizer que fiquei bastante satsifeito com ela e que certamente usarei Flutter e Firebase em outros projetos.
O que aprendi sobre LGPD e privacidade dados?
Desde o começo do projeto, tive uma grande preocupação com a questão da privacidade e proteção dos dados dos usuários do app. Além de serem dados pessoais, são dados sensíveis por se tratarem da saúde dos usuário. Eu não gostaria de ver os dados gerados pelo VirusMapBR sendo usados para fins escusos ou para prejudicar os usuários de qualquer maneira.
Para isto tomei vários cuidados tentando fazer algo que fosse bastante respeitoso com os usuários e que levasse sempre a privicidade e proteção dados em consideração. Minha idéia era fazer um app que pudesser ser um exemplo a ser seguido nestas questões. Mas o resultado não foi bem este, e isto foi um dos grandes apredizados desta jornada.
Tentei coletar e usar o mínimo de dados possível, tentei deixar bem explícito quais dados seriam coletados e como eles seriam utilizados, criei políticas de privacidade e termos de uso com a ajuda de profissionais da área e criei um mecanismo para evitar que os dados de saúde pudessem ser associados a um usuário (preservando a privacidade dos usuários).
Se quiser saber mais detalhes sobre como o VirusMapBR usa os dados dos usuários, veja este artigo onde tento explicar isto com uma linguagem bem acessível e alguns diagramas (como este abaixo).
Durante o desenvolvimento do VirusMapBR troquei muitas idéias com várias pessoas que me ajudaram em diferentes áreas relacionadas ao app. Uma destas pessoas foi um primo meu, o Ronaldo Lemos, que é uma das maiores autoridades em direito digital do mundo e, dentre outras coisas, advogado e cientista chefe do ITSRio, um think-tank que estuda o impacto da tecnologia na sociedade. Com a ajuda do Ronaldo preparei os documentos dos Termos de Uso e da Política de Privacidade do VirusMapBR.
Depois escrevi, como parte da documentação do app, o documento que citei anteriormente e que explica como os dados dos usuários são utilizados e protegidos pelo VirusMapBR. E também uma série de pequenos artigos que aparecem na seção de ajuda do aplicativo respondendo a perguntas relacionadas ao uso dos dados e a privacidade.
Imaginei que com todos estes cuidados, eu tiraria um 10 nas questões relacionadas a privacidade e proteção de dados, mas tive uma supresa.
Para validar tudo que estava sendo feito, contei com a ajuda do ITSRio que tem feito uma super cobertura de como a tecnologia tem sido usada no combate ao Coronavírus. Pedi para que eles fizessem uma análise do VirusMapBR do ponto de vista de privacidade e proteção de dados e adequação à LGPD semelhante às que foram feitas para os aplicativos Ecuador’s SaludEC e Mexico's Covid Radar.
O resultado é um longo documento — Riscos e Recomendações de Princípios, Técnicas e Práticas — VirusMapBR! — que analisa todo o app e também os documentos de termos de uso, política de privacidade e a documentação que escrevi sobre o VirusMapBR. Nele pude ver que, apesar de ter me preocupado genuinamente com os dados do usuários, o trabalho não foi perfeito e deixei vários pontos em aberto.
Os aprendizados aqui foram:
O VirusMapBR poderia utilizar menos dados dos usuários
A começar pelos mecanismos de autenticação que usavam os dados do Google Account (email e nome do usuário) ou o número do celular do usuário(quando usando autenticação via SMS). Estes dados são pessoais e podem ser usados para identificar unicamente o usuário.
Um dos pontos aqui é que, neste caso, o app poderia oferecer praticamente as mesmas funcionalidades sem coletar estas informações. Uma opção seria criar um modo de uso anônimo do app. Criando, na largada, um hash criptográfico baseado no identificador do dispositivo e a posição inicial do usuário.
Uma das razões para usar os mecanimos de autenticação (Google Account e Número do Celular) era para desambiguar os dados dos usuários e para ter o email e o número de celular caso fosse necessário enviar comunicações para eles (emails ou mensagens de texto). A desambiguação poderia ser conseguida com o hash anônimo que citei no parágrafo anteiror. Para a comunicação, uma alternativa seria usar notificações dentro do próprio app.
Os questionamentos são válidos: Até onde autenticar o usuários, para segregar os dados e evitar fraudes, era fundamental para o VirusMapBR? E a questão da comunicação com os usuários?
Outro aspecto com relação a minimizar os dados utilizados foi o fato de que os serviços de terceiros que eu estava utilizando também coletam, armazenam e usam dados do usuários. Alguns exemplos são os serviços do próprio Firebase que armazenam o endereço IP da conexão do usuário e outros dados do dispositivo (por exemplo o Analytics) e o WordPress que usei para armazenar as notícias que aparecem no dashbord do app e as entradas da área de ajuda. As chamadas à API do WordPress acabam gerando registros (log) com mais informações do usuário.
Por fim, eu tinha a idéia de integrar o VirusMapBR com o Desviralize, para que eles pudessem trocar os registros com estado de saúde e geo-localização dos usuários (sempre sem identificar o usuário). Apesar de não termos implementado esta integração, não estava claro nos Termos de Uso e na Política de Privacidade como seriam trocadas as informações entre os dois sistemas.
O mecanismo de anonimização do VirusMapBR não é perfeito
Apesar de ter me preocupado em criar um mecanismo para impedir que os dados de saúde pudessem ser associados a um determinado usuário, o mecanismo não garantia que fosse impossível identificar um usuário.
Resumidamente o mecanismo funciona assim: Quando um usuário se autentica no app (via Google Account ou via Número de Celular e SMS) ele ganha um número único de identificação, USER ID. Porém, este USER ID não poderia ser usado como chave para gravar os dados de saúde do usuário sem que o usuário pudesse ser identificado. Para isto, quando o usuário se autentica, o app calcula um novo número único de identificação, USER HASH, que é construído através de uma função criptografica aplicada sobre o USER ID e o identificador único do dispositivo do usuário, DEVICE ID. Assim, os dados de saúde são associados ao USER HASH e não ao USER ID.
De fato, não é possível chegar ao ID do usuário a partir do USER HASH. Isto é parte da natureza da fução de hash utilizada. E também, de posse do ID do usuário, não é possível calcular o USER HASH sem o DEVICE ID. Ou seja, este pedaço do mecanismo de anonimização é relativamente robusto. O diagrama abaixo mostra — nos blocos da esquerda — como isto funciona.
Porém, como os dados de saúde contém os dados de geo-localização de um determinado usuário, e seu histórico de localizações também é armazenado nos servidores do VirusMapBR (no Firebase), estes dados poderiam ser utilizados para se identificar um usuário a partir do seu padrão de localização. Esta idéia é reforçada pelo fato de o VirusMapBR usar dados de geo-localização com alta precisão, deixando esta abordagem ainda mais eficiente.
Claro, para isto alguém precisaria ter acesso a estes dados da maneira mais ampla ou ter acesso ao banco de dados do Firebase. Não é simples, mas não é impossível.
Para estes casos poderíamos ter pensando em algumas maneiras para mitigar estas brenchas. Uma idéia seria usar os dados de geo-localização com menor precisão ou adicionar algum tipo de rúido aleatório nas medições. Outra possibilidade seria a de não se disponibilizar os dados de geo-localização de cada usuário e sim um mapa de risco por regiões sem discriminar os pontos individuais. Também poderíamos não armazenar os dados de geo-localização de cada usuário e só armazenar o resultado da computação (cálculo) do risco de cada região numa espécie de mapa de calor. E, obviamente, também seria importante manter estes dados criptografados no Firebase.
A lição aqui foi a de que assegurar a privacidade no mundo digital é uma tarefa bem mais complexa do que parece. Mesmo apps minimalistas e desenhados com a privacidade de seus usuários em mente podem estar deixando brechas que permitem a identificação de seus usuários. E quando falamos de dados sensíveis, como os de saúde, os cuidados devem ser ainda maiores.
Agora é hora de abrir o código-fonte do VirusMapBR!
Bom, já vou avisando que não é o código mais bonito ou bem escrito do pedaço. Pelo contrário, haha!
A idéia de abrir o código-fonte do VirusMapBR é para que ele possa ser utilizado como referência para outros desenvolvedores que queiram conhecer os detalhes da implementação ou criar aplicativos semelhantes modificando o código-fonte original.
Apesar de ser um aplicativo relativamente simples, ele possui um conjunto de funcionalidades que são comuns a vários outros aplicativos e, por isto, pode ser uma boa referência para quem quiser fazer coisas parecidas. Dentre elas podemos destacar:
Autenticação via Google Account com Firebase
Autenticação via Número do Telefone e SMS com Firebase
Integração com o Firebase Cloud Firestore
Integração com Google Maps
Integração com Wordpress API
Uso de geolocalização no smartphone
Queries baseadas em geolocaliação no Firestore com GeoFlutterFire
Captura de foto com a câmera do smartphone
Gerenciamento de permissões para o uso da geolocalização
Se alguém olhar o código com atenção poderá perceber como fui mudando a maneira de trabalhar com o Flutter ao longo da jornada. As principais mudanças foram com relação ao gerenciamento de estados na aplicação e à organização do código — principalmente dos Widgets — para facilitar o re-uso e deixar o código mais legível.
Já no lado ruim, o código está pouco documentado, tem uma implementação pouco consistente em suas diferentes partes (devido a minha curva de aprendizado e falta de refactoring) e não tem qualquer cobertura de testes. Ouch! 😳
Para quem se interessar, o código do VirusMapBR está publicado no GitHub e contém instruções de como fazê-lo rodar em sua máquina de desenvolvimento.
E antes de encerrar… quero deixar mais uma vez o meu MUITO OBRIGADO para as pessoas que em ajudaram durante esta jornada: André Barrence, André Salem, Celina Botinno, Georges Benatti, Josias Cunha, Luciano Tavares e Ronaldo Lemos.
HeyHo!