
Eu quero falar sobre um projeto que vem sendo desenvolvido nos últimos dois anos. É chamado
GeoPuzzle e é um jogo de quebra-cabeça no mapa político do mundo. O objetivo é colocar pedaços do país em seu lugar. A ideia foi identificada no artigo
"Quebra-cabeça Mercator para especialistas em geografia" , que também tocava tetris de países (ainda no DOS) na infância, mas não me lembro do nome do programa. Fiquei tão inspirado com a ideia que queria criar um produto completo, interessante não apenas para crianças em idade escolar, mas também para especialistas em geografia. O desenvolvimento do projeto pode ser observado no
GitHub .
Protótipo
O artigo “Puzzle Mercator para especialistas em geografia” foi publicado em 8 de fevereiro de 2013, mas após 4 meses eu tinha um protótipo pronto, no qual os polígonos de todos os países do mundo estavam reunidos. Um pouco mais tarde, adicionei as regiões da Rússia e dos Estados Unidos e fiz a escolha da posição inicial no mapa para polígonos aleatoriamente. Descrevi o processo de desenvolvimento
no meu blog , publiquei o código-fonte no
GitHub . E é isso - preso. Eu tenho muito menos tempo livre, minha motivação se foi (nenhuma decisão foi tomada) e a complexidade aumentou exponencialmente. Era um projeto de estimação, e a tarefa principal era aprender algo novo, então fiquei um pouco pervertido com a tecnologia. No cliente, é claro, javascript (com o qual eu não trabalhei muito), o script ruby (novamente, uma nova linguagem para mim) foi responsável pela preparação dos dados, mas no servidor houve erro (eu queria tentar algo puramente funcional). Saída completa da zona de conforto: era difícil trabalhar diretamente com objetos PostGIS, a dor de converter seqüências para erlang, configurar o YAWS era uma questão completamente diferente ... No estágio seguinte, percebi que não conseguia lidar com todo esse zoológico para criar um produto completo e saí pense por alguns anos.
GeoPuzzle

O site funcionou todo esse tempo, as pessoas chegaram até lá, mas eu realmente queria adicionar mais um pequeno detalhe: exibir pelo menos algumas informações sobre o polígono recém-descoberto. Assim, planejei passar as férias de Ano Novo em 2017 com benefícios. Devido a problemas no protótipo, decidi reescrever tudo e tornar o produto em algo familiar - Django. Fora da caixa, existem coisas que simplificaram bastante minha vida, por exemplo, o painel de administração e o trabalho com o PostGIS através do ORM. Mas para iniciantes, era necessário recriar a funcionalidade que já funcionava. Levou apenas algumas noites e a maior parte do tempo foi gasta carregando dados de arquivos KML. Não tanto o processo de importação em si, como a preparação e restauração de meus conhecimentos sobre como trabalhar com eles. A propósito, peguei
polígonos do
gadm.org na época. Isso funcionou muito bem para os países, mas havia alguns problemas com a precisão das regiões, por isso tirei um tempo para esse problema.
Algumas palavras sobre níveis administrativos em dados geográficos (níveis).Todos os países estão divididos em várias regiões, que são divididas em partes ainda menores. No total, existem 12 camadas nessa hierarquia.
Por exemplo, para a Rússia:
- Rússia (2) -> Distrito Federal do Sul (3) -> Território de Krasnodar (4) -> Distrito de Vyselkovsky (6) -> art. Aldeias (8)
- Rússia (2) -> Distrito Federal do Sul (3) -> Território de Krasnodar (4) -> Krasnodar (6) -> Distrito de Prikubansky (9) -> Kopanskaya (10)
- França (2) -> Metrópole de França (3) -> Região da Normandia (4) -> Departamento de Orne (6) -> cantão de Donfron (7) -> município de Donfron-en-Poiret (8) -> Donfron (9)
As unidades territoriais em diferentes países são chamadas à sua maneira, mas deduzi para mim esta divisão: País (2) -> Região (4) -> Distrito (6). Divisão administrativa adicional deixada para mais tarde.
Desenvolvimento do projeto
Naquela época, o aplicativo era apenas uma coleção de páginas HTML com um mínimo de CSS. Queria verificar rapidamente a ideia e não me preocupar com o design. A ideia acabou sendo realizável, e é hora de criar uma bela concha para ela. Porque Não tenho nenhum senso de beleza na interface do usuário e, em seguida, no Bootstrap para me ajudar. Não há interface, mas ela apareceu e até adaptada para dispositivos móveis. Mas esse foi apenas o primeiro passo para colocar a interface em ordem.
Como é aprender o JavaScript em 2016 ?! Quando o código é compilado em outro dialeto, ele é modelado, colado para que depois possa ser cortado em pedaços. Eu, como back-end, fiquei assustado, mas a complexidade da parte do cliente foi planejada o suficiente, o que exigiu o uso de uma estrutura ou biblioteca. Decidi sobre o React por dois motivos: não precisava do SPA, mas de um conjunto de componentes para páginas diferentes, e queria ver rapidamente o resultado. Mas antes de começar a programar, você tinha que configurar o ambiente. Agora eu entendo o front-end familiar, que disse que configurou o Webpack por 2 dias. Acontece que não era uma piada.
Naquele momento, sucumbi à persuasão e implementei a lógica do aplicativo usando o Redux. Talvez isso não tenha sido um erro, porque permissão para entrar rapidamente no tópico. Regras formais me permitiram escrever um código e garantir que ele funcionasse sem olhar sob o capô. O Redux usando seu middleware me abstraiu da interação de rede, o que me permitiu verificar as respostas ao servidor. Sim, até o momento, o cliente trabalhava por conta própria - uma solicitação do ajax retirava todos os dados necessários e verificava as respostas por conta própria. O usuário pode trapacear olhando os dados que vêm do servidor. Além disso, ao carregar, os dados chegaram, necessários somente após a resposta correta. Após a implementação da verificação via soquetes da Web, o processo se tornou ideologicamente mais correto - a resposta verifica o código que não está disponível para o cliente. Para o usuário, isso ainda parecia instantâneo: enviar os pontos extremos do polígono para o servidor, verificar se eles entraram no quadrado com um erro, compactar os dados para a caixa de informações e o polígono detalhado em json e transferi-lo para o cliente - caber em ~ 200ms.

Tendo aprendido todo o poder do javascript, é difícil parar. Imediatamente houve idéias para adicionar animações, dobrar blocos, piscar e novas versões de jogos. Um deles é o "Quiz", no qual você deve adivinhar o país por nome, bandeira, brasão ou capital. É verdade que, durante o processo de teste, algumas regiões não tinham bandeiras, enquanto outras não tinham capital; portanto, alguns países tiveram que ficar ocultos da lista de regiões disponíveis. Ao mesmo tempo, um modo de jogo apareceu no mapa físico do mundo - sem as fronteiras dos países, para profissionais reais.
Fontes de dados abertas
Há ~ 50.000 polígonos no jogo agora, e quero agradecer muito a grandes projetos como Wikipedia e Open Street Map, sem os quais seria impossível encher a base. O requisito fundamental era receber e atualizar dados de fontes abertas, ou seja, sem edição manual, porque Eu não quero fazer lógica de sincronização complexa. Como resultado, obtive 2 scripts que podem atualizar caixas de informações e polígonos.
Wikipedia e SPARQL

Qual é o maior banco de dados de países e regiões? Wikipedia! Inicialmente, eu queria mostrar aos usuários toda a caixa de informações, mas logo abandonei essa ideia. Sim, havia coisas importantes como nomes, bandeiras, capitais e outras coisas, mas também havia muito lixo (código telefônico, forma de governo, PIB ...). Tentei analisar já coletados, mas descobri que eles têm uma estrutura diferente. Isso acabou sendo um desastre: os custos de mão-de-obra para implementação aumentaram muitas vezes. Era hora de parar e pensar. No dia seguinte, aprendi sobre a existência de uma linguagem de consulta especial - SPARQL. Na aparência, ele se assemelha ao SQL - também declarativo, com as palavras-chave
SELECT
,
WHERE
,
ORDER BY
, mas funciona de uma maneira completamente diferente. Um pequeno exemplo que retorna uma lista de estados com maiúsculas em inglês e russo:
SELECT DISTINCT ?country ?capital ?row WHERE { ?country wdt:P31 wd:Q3624078 . FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240} OPTIONAL { ?country wdt:P36/rdfs:label ?capital } . BIND(lang(?capital) as ?row) filter (?row = 'ru' || ?row = 'en') } ORDER BY ?capital
Parece selvagem, não é ?! Confira
aqui . Até escrevi uma pequena
nota no meu blog para estruturar minha experiência e ajudar a entrar no tópico, porque Existem poucos materiais detalhados na Internet. Você pode aprender a ler esses pedidos rapidamente, mas levei um fim de semana inteiro para escrever algo significativo. Muita "mágica" da
wd:Q3624078
e outros atributos. Você precisa saber que
wdt:P31
é uma "entidade" e
wd:Q3624078
é um "estado soberano". Pessoas desconhecidas começam com um ponto de interrogação e o atendimento da solicitação consiste na busca de triplos fatos que satisfizessem as condições. Por exemplo
?country wdt:P31 wd:Q3024240
- “encontre todos os objetos que são estados históricos”; e então o mesmo objeto participa de outros triplos
?country wdt:P36/rdfs:label ?capital
- de onde vem o capital.
Cerca de uma semana depois, eu tinha a primeira versão do script pronta, que baixava informações regionais da Wikipedia. E então outro problema ficou claro - desta vez com dados. Alguns svg não começaram com
<?xml version="1.0" encoding="UTF-8"?>
E não foram reconhecidos pelo navegador como imagens válidas. Felizmente, o arquivo de origem pode ser editado. Não há nada complicado em se registrar no wikipedia.org, mas você se encontra imediatamente em uma casa de banhos por um dia. Aqui está a proteção deles contra robôs. Então, na noite seguinte, eu governei o XML e fiquei feliz com a simplicidade, e bandeiras e emblemas apareceram no mapa.
Polígonos

Se, por fatos, formos à Wikipedia, depois aos dados geográficos - no Open Street Map. Seria legal pegar uma cópia local, aprender o idioma dos pedidos de
passagem superior , mas não consigo nem imaginar quanto tempo levaria. E você também precisa tirar a hierarquia de algum lugar ... Felizmente, uma pessoa amável já
resolveu esse problema para mim . O serviço ainda fornece uma API para recuperar informações. Consegui fazer o download de todos os polígonos até o nível 6, inclusive (distrito), e preencher tudo no Postgres, um pouco mais de 2 Gb. Não foi sem aventuras - alguns polígonos eram tão grandes (por exemplo, o Canadá pesa mais de 100 Mb em um GeoJSON compactado) que o servidor travou ou não respondeu. Eu tive que ignorar esses momentos manualmente. Baixei todas as crianças e as fundei no QGIS. A propósito, este é outro exemplo de um projeto de código aberto que me ajudou muito.
Problemas de Big Data
Então, eu tenho um banco de dados com dados, inicio o jogo e ... e espero ... novamente eu espero ... apareceu! Tentei arrastar o polígono - ele está morto, Jim! O Chrome não conseguiu lidar com esse volume de pontos e caiu. A estratégia da testa não funciona mais, é hora de pensar. O mais óbvio é reduzir os detalhes dos polígonos. Derivou empiricamente uma fórmula que depende da área da figura - ela melhorou. Em um computador em funcionamento, o algoritmo funcionou em tempo real, enquanto o servidor é severamente limitado em recursos. Redis conectados, ficou melhor já no servidor. Mas os polígonos truncados são bons para o Drag'n'Drop e, quando definidos no lugar certo, as bordas não coincidem com as que desenham mapas do Google. Bem, isso pode ser contornado através da aplicação de uma fórmula não tão agressiva para reduzir os detalhes. Como já existem 2 caches, por que não tentar armazenar em cache tudo o que é possível ?! As caixas de informações (em dois idiomas) voaram para Redis, as bordas pelas quais a resposta é calculada, o centro do polígono e as páginas estáticas do site. Como resultado, o jogo começou a funcionar muito mais rápido e muita carga de trabalho foi removida do Postgres, que teoricamente poderia ser o gargalo. Menos - o aplicativo não funciona sem o Redis.
Primeira implantação
Portanto, é hora de mostrar o projeto aos amigos para obter feedback. Restou apenas um pouco: gerar sitemap.xml, adicionar robots.txt, conectar métricas, adicionar botões sociais. redes e ... implantar! Escolhi a AWS como hospedagem, pois esperava caber nos recursos livres fornecidos. E esta é uma pilha muito boa para um projeto iniciante:
- servidor de aplicativos (t2.micro: 1xCPU, 1 Gb de RAM, 20 Gb SSD)
- banco de dados (db.t2.micro: 1xCPU, 1 Gb de RAM, 20 Gb SSD)
- armazenamento de arquivos com CDN (5 Gb S3, 50 Gb de tráfego)
- servidor de armazenamento em cache (cache.t2.micro: 1xCPU, 0,5 Gb de RAM)
- Elasticsearch + Kibana (t2.small.elasticsearch: 1xCPU, 2 Gb de RAM)
Esta é apenas uma lista do que eu consegui usar. Ao longo do caminho, decidi elaborar meu rake
na forma de artigos , mas rapidamente morri. O tempo passa decentemente, mas não está claro se alguém precisa dele.
Como resultado, paguei pelo ano de serviço algo da ordem de US $ 10, e até mesmo por estupidez. Mas aqui o período de teste chegou ao fim e eu tive que me mudar, porque o custo de possuir toda essa economia começou a se aproximar de várias centenas de dólares. Tarifas comparadas e liquidadas na DigitalOcean. Por enquanto, tenho máquinas suficientes com 2 GB de RAM para tudo (servidor de aplicativos, banco de dados e cache), mas deixei as estatísticas e CDN na AWS. Agora descobri que o DO também recebeu um CDN e armazenamento por US $ 5 / mês, por isso faz sentido pensar em mudar essa parte também.
Transferir para código aberto
Na noite de janeiro, recebi uma carta de uma escola dinamarquesa. Sua essência se resume ao fato de que eles têm US $ 100 e querem dar para mim. Mas há uma condição - o código fonte do projeto deve estar aberto. Até aquele momento, eu nem tinha pensado em código aberto. Algumas noites foram pensando e escolhendo uma licença. Como resultado,
carreguei as fontes no Github sob a licença GPLv3 e recebi os US $ 100 prometidos. Isso aumentou muito a motivação - meu projeto foi realmente útil! E corri para o próximo objetivo - o editor do jogo. Para que todos possam criar seus próprios quebra-cabeças. Por exemplo, “Países participantes da Segunda Guerra Mundial”, “Distritos do território de Krasnodar”, “Países sem litoral” ... Mas, para isso, eram necessários o registro e uma conta pessoal primitiva. Como resultado, o desenvolvimento se arrastou por longos 3 meses. Durante esse período, escrevi uma árvore de regiões que puxavam dados pelo ajax, conectavam a localização, aprendiam a salvar um mapa do Google como uma imagem para gerar visualizações e reduzir o redux. Sim, ele me ajudou a lidar com os dados desde o início, mas agora é mais provável que interfira. Eu teria que arrastar redutores para desenhar polígonos no mapa, junto com o código que trataria do movimento deles. Felizmente, remover a ligação ao estado global levou apenas alguns dias e mover o código para o local até simplificou o aplicativo. E, claro, esta é uma boa experiência :)
Conexão de Serviço
Acontece que muitos serviços pagos fornecem seus serviços gratuitamente para projetos de código aberto. Vou listar apenas aqueles que eu conectei aos meus.
Sentinela . Penso que este serviço para detectar erros é familiar a todos. Quando acabei de implantar o projeto, o registro consistia no envio de um rastreamento de pilha para o correio. Isso funcionou apenas para o back-end, mas eu também queria acompanhar os bugs no front-end. E não em vão - acabei o limite de mensagens grátis em apenas duas semanas. A maioria dos erros ocorreu nas entranhas da biblioteca de mapas do Google, o que, à primeira vista, é muito estranho. Durante a investigação, tudo foi culpa minha. As correções duraram mais de um mês, mas foi uma prática muito útil de manipulação de erros javascript.
-
crowdin.com - localização. Eu pretendo tornar o projeto acessível a todos. Incluindo que as infoboxes foram mostradas em sua língua nativa. Preenchê-los da Wikipedia não é um problema, mas por consistência, eu também gostaria de ter uma interface no mesmo idioma e, até agora, ela foi traduzida apenas para russo e inglês.

-
CircleCI . Nenhum projeto moderno pode ficar sem CI / CD, testes e implantação automática. Escolhi o CircleCI apenas porque já trabalhei com o TravisCI quando escrevi a
biblioteca para trabalhar com o Yandex.Disk . Tive a impressão de que é mais adequado para testar bibliotecas, pois é fácil definir a matriz de ambientes em que o código deve ser testado. Mas com os testes em si, tenho um problema - não há tantos quantos gostaríamos, embora a infraestrutura já esteja pronta.

-
Macacão . Serviço de visualização de cobertura de código. Capaz de também fornecer um rótulo para inserção no projeto README.md.
-
SonarQube . Colheitadeira para controle de qualidade do código. Ele verifica o código de acordo com uma variedade de regras, considera a complexidade ciclomática, monitora a cobertura por testes e até reconhece a duplicação de código! Um serviço muito interessante, que ainda não tive tempo de entender completamente.

- robôs do Github. Até o momento, apenas o
Dependabot está conectado, o que atualiza as dependências.

Sugiro nos comentários que compartilhem a lista de serviços e bots em seus projetos.
Bugs
A análise de bugs e problemas merece um artigo separado. Havia engraçado, complexo e difícil de consertar (portanto, Chukotka sempre fica em seu lugar). Atualmente, existe um que realmente incomoda os usuários. Quando uma resposta é recebida, os polígonos são excluídos e recriados (na biblioteca react-google-maps) e, se nesse momento o usuário arrastou alguns, o mapa do Google continua assumindo que o processo ainda não foi concluído. Parece que, no processo de arrastar e soltar, o polígono desaparece e você não pode mais pegar nenhum outro. É claro que você pode bloquear o processamento da resposta no processo de arrastar e soltar, mas isso garante a morte do jogo multiplayer, cuja implementação eu estou trabalhando atualmente. Tentei encontrar uma maneira de interromper o arrastar e soltar programaticamente, mas, no final,
levantei uma pergunta no StackOverflow e um
bug no Google Maps, na esperança de que eles prestassem atenção. Até então, ele adicionou um botão "o jogo está quebrado!", Que reinicializa o mapa inteiro, mas não redefine o resultado.
O que vem a seguir?
- Design. Admito que, com isso, tudo está completamente ruim. É necessário contratar um designer e um designer de layout, porque eu próprio não sou amigo de layouts e layouts.
- Monetização. Inicialmente, não planejei nada. O projeto é dedicado à educação básica, que na minha opinião deve ser acessível a todos. Fiquei muito inspirado por uma carta de uma escola dinamarquesa, mas quase um ano se passou e, durante esse período, houve apenas uma transferência de US $ 5. Bem, eu não acreditava que pudesse pagar pelo servidor. No entanto, ele começou uma campanha no Patreon de qualquer maneira. Ao mesmo tempo, você provavelmente pode pensar em introduzir oportunidades pagas para professores ou organizações. Por exemplo, tenho experiência na integração com o Learning Management Systems - um conjunto de plataformas que permitem a criação de cursos e são muito populares na Europa e nos EUA. Pelo que entendi, mesmo que o código-fonte também esteja sob a GPL no Github, isso não me impede, como autor, de desenvolver uma versão comercial paralela.
- Telefones celulares. Quero liberar um aplicativo para iOS / Android. A julgar pela métrica Yandex, um quarto dos usuários tenta tocar em um telefone ou tablet, mas acontece que eles têm dificuldade.
- Desenvolvimento. Todo o trabalho é feito no GitHub . Quero continuar desenvolvendo o projeto, mas fazê-lo sozinho é difícil. Os planos incluem adicionar multijogador, fazer tags, classificações e filtros no Workshop, adicionar polígonos para um mapa físico (montanhas, mares, penínsulas). Ainda há muitas coisas interessantes, então um dos objetivos do artigo é encontrar pessoas com a mesma opinião. Outra opção é ir à fundação, por exemplo, a Python Software Foundation e obter uma concessão.
Aqui está o que está no momento. Obrigado por ler até o fim! Você pode jogar aqui -
geopuzzle.org e ver o código fonte no
GitHub .

Minuto de cuidados UFO
Esse material pode causar sentimentos conflitantes; portanto, antes de escrever um comentário, atualize algo importante em sua memória: