Como fazer aplicativos que mostram coisas perto de você funcionar de verdade
A maioria dos desenvolvedores subestima a parte difícil quando decide construir algo baseado em proximidade. Não é só chamar uma API de mapas e colocar marcadores num mapa. Tem problemas reais que aparecem só quando o app vai pro mundo e começa a escalar. Vou explicar como isso funciona na prática, com os detalhes que os tutoriais não costumam mencionar.
coisas perto de mim — como funciona por baixo do capô
O conceito é simples na superfície: você pega as coordenadas do usuário, calcula a distância até cada ponto de interesse no banco de dados, ordena por proximidade e retorna os resultados. O problema é que calcular distância euclidiana ingênua em milhares de registros mata seu banco de dados em questão de segundos. Geografia real exige algo como a fórmula de Haversine, mas mesmo ela tem custo se você não indexar direito. O que funciona na prática é usar Google S2 cells ou PostGIS com índices SP-GiST. Se você está rodando PostgreSQL, o PostGIS é praticamente obrigatório. A cláusula ST_DWithin com um índice espacial evita que você tenha que varrer toda a tabela. Sem índice espacial, cada query de proximidade vai escanear todas as linhas. Com índice, essa mesma query roda em milissegundos na maioria dos casos razoáveis.
Se você não usa PostGIS e está num ambiente mais restrito, o Google S2 permite dividir o planeta em células hierárquicas. Você converte coordenadas para um identificador S2 e usa isso como filtro prévio antes do cálculo de distância final. É um passo de pré-filtragem que corta drasticamente o número de linhas que precisam de cálculo pesado.
O problema que ninguém conta
Montei um sistema de recomendação de restaurantes baseado em proximidade para um projeto interno. Os primeiros testes passaram tranquilo. Quando coloquei com tráfego real, comecei a ver requests que levavam 800ms para retornar. O gargalo era óbvio: o filtro de distância estava rodando em toda a tabela de estabelecimentos, que tinha cerca de 45 mil linhas. Nada que um índice simples resolvesse, porque a consulta precisava verificar múltiplas condições. A solução foi adicionar uma camada de cell S2 no nível 8 antes do cálculo de distância. Isso reduziu de 45 mil linhas para cerca de 600 a 800 linhas por query, dependendo da região do usuário. O tempo de resposta caiu para algo entre 20ms e 40ms. A mudança foi pequena —basicamente uma coluna adicional e um JOIN a mais— mas fez toda a diferença.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Privacidade e permissões: a parte chata
Não adianta construir algo se você não souber pedir permissão de localização corretamente. iOS e Android têm políticas diferentes e ambas mudaram nos últimos anos. No iOS, o uso de NSLocationWhenInUseUsageDescription ou NSLocationAlwaysUsageDescription depende exatamente de quando você precisa dos dados. Se for só enquanto o app está aberto, use WhenInUse. Pedir Always sem justificativa forte resulta em rejeição na review da App Store. No Android, a partir da versão 13 (API 33), você precisa de permissão explícita em tempo de execução para localização em primeiro plano. A permissão ACCESS_FINE_LOCATION não é suficiente sozinha se o app precisar de acesso rápido sem interação constante do usuário. Documente bem o motivo no manifesto, senão os usuários rejeitam na instalação.
Um detalhe importante: muitos desenvolvedores esquecem que a localização do GPS pode ter erro de dezenas de metros em áreas urbanas com muitos prédios altos. Isso significa que um estabelecimento que aparece "perto" pode estar realmente longe ou vice-versa. A solução é combinar dados de WiFi e torres de celular como fallback, e aplicar uma margem de tolerância nos resultados.
Quando não usar geolocalização em tempo real
Se o seu objetivo é mostrar coisas em um raio de alguns quilômetros para um usuário que já está se deslocando, consultas em tempo real podem funcionar. Mas se você precisa servir milhões de solicitações por dia com latência baixa, o melhor é fazer pré-agregação por célula S2 e servir resultados cacheados. Atualize o cache periodicamente, tipo a cada 5 minutos para lugares estáticos como restaurantes, ou a cada 30 segundos para coisas mais dinâmicas como transporte público. Também considere que nem todo mundo quer compartilhar localização. Bons apps de proximidade permitem busca por CEP ou endereço manualmente, sem obrigar o rastreamento. Isso não é só educação — em várias jurisdições, isso é requisito legal sob regulamentações como a LGPD no Brasil e o GDPR na Europa.
Ferramentas úteis para começar
Para prototipagem rápida, o Mapbox GL JS com seus exemplos de clustering de marcadores resolve em poucas horas. Para produção com PostgreSQL, PostGIS é o caminho mais direto. Se você estiver no ecossistema Google e quiser algo já integrado, a API Places Near Me do Google Maps funciona, mas tem custo que escala linearmente com requisições — e você perde controle sobre o caching e a lógica de filtro. Uma alternativa open source que vale a pena testar é o Nominatim do OpenStreetMap para geocodificação reversa, combinado com queries PostGIS no seu próprio banco. Isso elimina dependência de APIs pagas para a parte de consulta de endereços e nomes de lugares.
O que quebrar mais fácil
O erro mais comum que vejo é calcular distância no lado do cliente após buscar todos os registros. Funciona bem com 100 itens. Com 100 mil, seu servidor vai sofrer. Sempre filtre no banco com alguma forma de spatial index antes de trazer os dados para a aplicação. Outro erro frequente é não considerar fusos horários e zonas de cobertura ao fazer projeções de distância em áreas rurais onde a rede celular é esparsa. A parte mais irritante na prática é a manutenção dos dados. Estabelecimentos fecham, mudam de endereço, atualizam horários. Um sistema de coisas perto de mim que não tem um pipeline de atualização de dados acaba retornando informações desatualizadas em semanas. Planeje isso desde o início, senão seu app se torna inútil sem ninguém perceber imediatamente.