GeoPuzzle - faites le monde morceau par morceau

image

Je veux parler d'un projet qui s'est développé au cours des deux dernières années. Il s'appelle GeoPuzzle et est un jeu de puzzle sur la carte politique du monde. Le but est de remettre des morceaux du pays à sa place. L'idée a été repérée dans l'article «Puzzle Mercator pour les experts en géographie» , qui jouait également des tetris de pays (toujours sous DOS) dans l'enfance, mais je ne me souviens pas du nom du programme. J'étais tellement inspiré par l'idée que je voulais faire un produit complet, intéressant non seulement pour les écoliers, mais aussi pour les experts en géographie. Le développement du projet peut être observé sur GitHub .

Prototype


L'article «Puzzle Mercator pour les experts en géographie» a été publié le 8 février 2013, mais après 4 mois, j'avais un prototype prêt, dans lequel les polygones de tous les pays du monde étaient assemblés. Un peu plus tard, j'ai ajouté les régions de la Russie et des États américains et j'ai fait le choix de la position initiale sur la carte pour les polygones aléatoires. J'ai décrit le processus de développement dans mon blog , publié le code source sur GitHub . Et c'est tout - coincé. J'ai eu beaucoup moins de temps libre, ma motivation avait disparu (aucune décision n'a été prise) et la complexité a augmenté de façon exponentielle. C'était un projet pour animaux de compagnie, et la tâche principale était d'apprendre quelque chose de nouveau, j'étais donc un peu perverti par la technologie. Sur le client, bien sûr, javascript (avec lequel je ne travaillais pas beaucoup à l'époque), le script ruby ​​(encore une fois un nouveau langage pour moi) était responsable de la préparation des données, mais sur le serveur il y avait erlang (je voulais essayer quelque chose de purement fonctionnel). Sortie complète de la zone de confort: il était difficile de travailler directement avec des objets PostGIS, la douleur de convertir des chaînes en erlang, de configurer YAWS était un problème tout à fait différent ... pensez pendant quelques années.

GeoPuzzle


image

Le site a fonctionné pendant tout ce temps, les gens y sont même allés, mais je voulais vraiment ajouter un petit détail: afficher au moins quelques informations sur le polygone nouvellement découvert. Ainsi, j'avais prévu de passer les vacances du Nouvel An en 2017 avec bénéfice. En raison de problèmes dans le prototype, j'ai décidé de tout réécrire et de créer le produit sur quelque chose de familier - Django. Hors de la boîte, il y a des choses qui ont grandement simplifié ma vie, par exemple, le panneau d'administration et le travail avec PostGIS via ORM. Mais pour commencer, il fallait recréer les fonctionnalités qui fonctionnaient déjà. Cela n'a pris que quelques soirées, et la plupart du temps a été pris en chargeant des données à partir de fichiers KML. Pas tant le processus d'importation lui-même que leur préparation et restauration de mes connaissances sur la façon de travailler avec eux. Au fait, j'ai pris des polygones sur gadm.org à ce moment-là. Cela fonctionnait très bien pour les pays, mais il y avait certains problèmes avec la précision des régions, j'ai donc pris un temps mort pour ce problème.

Quelques mots sur les niveaux administratifs dans les géodonnées (niveaux).
Tous les pays sont divisés en plusieurs régions, qui sont divisées en parties encore plus petites. Au total, il y a 12 couches dans une telle hiérarchie.

Par exemple, pour la Russie:

  • Russie (2) -> District fédéral du Sud (3) -> Territoire de Krasnodar (4) -> District de Vyselkovsky (6) -> Art. Villages (8)
  • Russie (2) -> District fédéral du Sud (3) -> Territoire de Krasnodar (4) -> Krasnodar (6) -> District de Prikubansky (9) -> Kopanskaya (10)
  • France (2) -> Métropole de France (3) -> Région Normandie (4) -> Département de l'Orne (6) -> canton de Donfron (7) -> commune de Donfron-en-Poiret (8) -> Donfron (9)

Les unités territoriales dans différents pays sont appelées à leur manière, mais pour moi, j'ai déduit cette division: Pays (2) -> Région (4) -> District (6). La division administrative est partie pour plus tard.

Développement de projet


A cette époque, l'application n'était qu'une collection de pages HTML avec un minimum de CSS. Je voulais vérifier rapidement l'idée et ne pas m'embêter avec le design. L'idée s'est avérée réalisable et il est temps d'en faire une belle coquille. Parce que Je n'ai aucun sens de la beauté dans l'interface utilisateur, puis Bootstrap pour m'aider. Il n'y a pas d'interface, mais il est apparu, et même adapté aux appareils mobiles. Mais ce n'était que la première étape pour mettre de l'ordre dans le frontend.

Comment vous sentez-vous d'apprendre JavaScript en 2016 ?! Lorsque le code est compilé dans un autre dialecte, il est modélisé, collé ensemble afin de pouvoir ensuite être découpé en morceaux. En tant que backend, j'avais peur, mais la complexité de la partie client était suffisamment importante, ce qui impliquait la nécessité d'utiliser un framework ou une bibliothèque. J'ai opté pour React pour deux raisons: je n'avais pas besoin de SPA, mais d'un ensemble de composants pour différentes pages, et je voulais voir rapidement le résultat. Mais avant de commencer la programmation, vous deviez configurer l'environnement. Maintenant, je comprends le front-end familier, qui a dit qu'il avait configuré Webpack pendant 2 jours. Il s'avère que ce n'était pas une blague.

A cette époque, j'ai succombé à la persuasion et mis en œuvre la logique de l'application en utilisant Redux. Ce n'était peut-être pas une erreur, car autorisé à entrer rapidement dans le sujet. Les règles formelles m'ont permis d'écrire du code et de m'assurer qu'il fonctionnait sans regarder sous le capot. Redux utilisant son middleware m'a fait abstraction de l'interaction réseau, ce qui m'a permis de vérifier les réponses au serveur. Oui, jusqu'à présent, le client a travaillé seul - une demande ajax a extrait toutes les données nécessaires et vérifié les réponses par ses propres moyens. L'utilisateur pourrait tricher en regardant les données provenant du serveur. De plus, lors du chargement, les données ont volé, nécessaires uniquement après la bonne réponse. Après avoir implémenté la vérification via des sockets Web, le processus est devenu idéologiquement plus correct - la réponse vérifie le code qui n'est pas disponible pour le client. Pour l'utilisateur, cela semblait toujours instantané: envoyer les points extrêmes du polygone au serveur, vérifier s'ils étaient entrés dans le carré avec une erreur, emballer les données de la boîte d'informations et du polygone détaillé dans json et les transférer au client - tenir en ~ 200 ms.

image

Après avoir appris toute la puissance du javascript, il est difficile de s'arrêter. Immédiatement, il y a eu des idées pour ajouter des animations, des blocs pliants, des clignotements et de nouvelles versions de jeux. L'un d'eux est le «Quiz», dans lequel vous devez deviner le pays par son nom, son drapeau, ses armoiries ou sa capitale. Certes, au cours du processus de test, il s'est avéré que certaines régions n'avaient pas de drapeaux, tandis que d'autres n'avaient pas de capitale, donc certains pays devaient être cachés de la liste des pays disponibles. Dans le même temps, un mode de jeu est apparu sur la carte physique du monde - sans les frontières des pays, pour les vrais pros.

Sources de données ouvertes


Il y a environ 50 000 polygones dans le jeu maintenant, et je tiens à dire un grand merci à des projets aussi formidables que Wikipedia et Open Street Map, sans lesquels remplir la base aurait été impossible. L'exigence fondamentale était de recevoir et de mettre à jour des données à partir de sources ouvertes, c'est-à-dire sans modification manuelle, car Je ne veux pas faire de logique de synchronisation complexe. En conséquence, j'ai obtenu 2 scripts qui peuvent mettre à jour les boîtes d'informations et les polygones.

Wikipédia et SPARQL


image

Quelle est la plus grande base de données de pays et régions? Wikipédia! Au départ, je voulais montrer aux utilisateurs l'intégralité de la boîte d'informations, mais j'ai rapidement abandonné cette idée. Oui, il y avait des choses importantes comme les noms, les drapeaux, les capitales et d'autres choses, mais il y avait aussi beaucoup de déchets (code téléphonique, forme de gouvernement, PIB ...). J'ai essayé d'analyser déjà collecté, mais a constaté qu'ils ont une structure différente. Cela s'est avéré être un désastre: les coûts de main-d'œuvre pour la mise en œuvre ont augmenté de nombreuses fois. Il était temps de s'arrêter et de réfléchir. Le lendemain, j'ai appris l'existence d'un langage de requête spécial - SPARQL. En apparence, il ressemble à SQL - également déclaratif, avec les mots-clés SELECT , WHERE , ORDER BY , mais il fonctionne d'une manière complètement différente. Un petit exemple qui renvoie une liste des États avec leurs capitales en anglais et en russe:

 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 

Ça a l'air sauvage, non?! Vérifiez ici . J'ai même écrit une petite note sur mon blog pour structurer mon expérience et aider à entrer dans le sujet, car il existe peu de documents détaillés sur Internet. Vous pouvez apprendre à lire de telles demandes assez rapidement, mais il m'a fallu tout un week-end pour écrire quelque chose de significatif. Beaucoup de "magie" de wd:Q3624078 et d'autres attributs. Vous devez savoir que wdt:P31 est une «entité» et wd:Q3624078 est un «État souverain». Les inconnus commencent par un point d'interrogation et la satisfaction de la demande consiste à rechercher de tels triplets de faits qui satisferaient aux conditions. Par exemple ?country wdt:P31 wd:Q3024240 -« rechercher tous les objets qui sont des états historiques »; puis le même objet participe à d'autres triplets ?country wdt:P36/rdfs:label ?capital - d'où vient le capital.

Environ une semaine plus tard, j'avais la première version du script prête, qui téléchargeait des informations régionales à partir de Wikipedia. Et puis un autre problème est devenu clair - cette fois avec les données. Certains svg n'ont pas commencé par <?xml version="1.0" encoding="UTF-8"?> Et n'ont pas été reconnus par le navigateur comme des images valides. Heureusement, le fichier source peut être modifié. Il n'y a rien de compliqué à s'inscrire sur wikipedia.org, mais vous vous retrouvez immédiatement dans un bain public pour une journée. Voici leur protection contre les robots. Donc, le lendemain soir, j'ai gouverné XML et j'étais content de la simplicité, et des drapeaux et des emblèmes sont apparus sur la carte.

Des polygones


image

Si pour des faits nous allons sur Wikipedia, alors pour les géodonnées - dans l'Open Street Map. Ce serait cool de récupérer une copie locale, d'apprendre la langue des demandes de contournement , mais je ne peux même pas imaginer combien de temps cela prendrait. Et vous devez également prendre la hiérarchie quelque part ... Heureusement, une personne gentille a déjà résolu ce problème pour moi . Le service fournit même une API pour récupérer des informations. J'ai réussi à télécharger à partir de là tous les polygones jusqu'au niveau 6 inclus (quartier) et à tout remplir dans Postgres, un peu plus de 2 Go sont sortis. Ce n'était pas sans aventures - certains polygones étaient si grands (par exemple, le Canada pèse plus de 100 Mo dans un GeoJSON zippé) que le serveur est tombé en panne ou n'a pas répondu. J'ai dû contourner ces moments manuellement. J'ai téléchargé tous les enfants et les ai fusionnés dans QGIS. À propos, ceci est un autre exemple d'un projet open source qui m'a beaucoup aidé.

Problèmes de Big Data


Donc, j'ai une base de données avec des données, je lance le jeu et ... et attends ... encore j'attends ... apparu! J'ai essayé de faire glisser le polygone - Il est mort, Jim! Chrome n'a pas pu gérer un tel volume de points et est tombé. La stratégie du front ne fonctionne plus, il est temps de réfléchir. Le plus évident est de réduire le détail des polygones. Empiriquement dérivé d'une formule qui dépend de la zone de la figure - elle s'est améliorée. Sur un ordinateur qui fonctionne, l'algorithme a fonctionné à la volée, tandis que le serveur est gravement limité en ressources. Connecté redis, il s'est déjà amélioré sur le serveur. Mais les polygones tronqués sont bons pour Drag'n'Drop, et lorsqu'ils sont définis au bon endroit, les bordures ne coïncident pas avec celles qui dessinent Google maps. Eh bien, cela peut être contourné en appliquant une formule moins agressive pour réduire les détails. Puisqu'il y a déjà 2 caches, pourquoi ne pas essayer de mettre en cache tout ce qui est possible?! Des infoboxes (en deux langues) ont volé vers Redis, les frontières par lesquelles la réponse est calculée, le centre du polygone, ainsi que les pages statiques du site. En conséquence, le jeu a commencé à fonctionner beaucoup plus rapidement et une grande partie de la charge de travail a été supprimée de Postgres, ce qui pourrait théoriquement être le goulot d'étranglement. Moins - l'application ne fonctionne pas du tout sans Redis.

Premier déploiement


Il est donc temps de montrer le projet à des amis pour obtenir des commentaires. Il ne restait plus que peu: générer sitemap.xml, ajouter robots.txt, connecter les métriques, ajouter des boutons sociaux. réseaux et ... déployez! J'ai choisi AWS comme hébergement, espérait s’insérer dans les ressources gratuites fournies. Et c'est une très bonne pile pour un projet débutant:

  • serveur d'applications (t2.micro: 1xCPU, 1 Go de RAM, SSD 20 Go)
  • base de données (db.t2.micro: 1xCPU, 1 Go de RAM, SSD 20 Go)
  • stockage de fichiers avec CDN (5 Go S3, 50 Go de trafic)
  • serveur de mise en cache (cache.t2.micro: 1xCPU, 0,5 Go de RAM)
  • Elasticsearch + Kibana (t2.small.elasticsearch: 1xCPU, 2 Go de RAM)

Ce n'est qu'une liste de ce que j'ai réussi à utiliser. En cours de route, j'ai décidé de dresser mon râteau sous forme d'articles , mais je suis vite décédé. Le temps passe décemment, mais il n'est pas clair si quelqu'un en a besoin.

En conséquence, pour l'année de service, j'ai payé quelque chose de l'ordre de 10 $, et même par stupidité. Mais ici, la période d'essai a pris fin, et j'ai dû déménager, car le coût de possession de toute cette économie a commencé à approcher plusieurs centaines de dollars. Tarifs comparés, et installés sur DigitalOcean. Pour l'instant, j'ai assez de machines avec 2 Go de RAM pour tout (serveur d'applications, base de données et cache), mais j'ai laissé la statique et le CDN sur AWS. Maintenant, j'ai découvert que DO avait également un CDN et un stockage pour 5 $ / mois, il est donc logique de penser à déplacer cette partie également.

Transfert vers l'Open Source


Ce soir de janvier, j'ai reçu une lettre d'une école danoise. Son essence se résume au fait qu'ils ont 100 $ et qu'ils veulent me les donner. Mais il y a une condition - le code source du projet doit être ouvert. Jusqu'à ce moment, je n'avais même pas pensé à l'Open Source. Quelques soirées ont été consacrées à la réflexion et au choix d'une licence. En conséquence, j'ai téléchargé les sources sur Github sous la licence GPLv3 et j'ai reçu les 100 $ promis. Cela a considérablement accru la motivation - mon projet a été vraiment utile! Et je me suis précipité vers le prochain objectif - l'éditeur de jeu. Pour que chacun puisse créer ses propres puzzles. Par exemple, «Pays participant à la Seconde Guerre mondiale», «Districts du territoire de Krasnodar», «Pays sans littoral»… Mais pour cela, l'enregistrement et un compte personnel primitif étaient nécessaires. En conséquence, le développement a traîné pendant 3 mois. Pendant ce temps, j'ai écrit un arbre de régions qui extraire des données via ajax, connecter la localisation, apprendre à enregistrer une carte Google en tant qu'image pour générer des aperçus et couper redux. Oui, il m'a aidé à gérer les données au tout début, mais maintenant, elles sont plus susceptibles d'interférer. Je devrais faire glisser des réducteurs pour dessiner des polygones sur la carte, ainsi que du code qui gérerait leur mouvement. Heureusement, la suppression de la liaison à l'état global n'a pris que quelques jours, et le déplacement du code vers le code local a même simplifié l'application. Et bien sûr, c'est une bonne expérience :)

Connexion au service


Il s'avère que de nombreux services payants fournissent leurs services gratuitement pour des projets open source. Je vais lister uniquement ceux que j'ai connectés aux miens.

- Sentinelle . Je pense que ce service pour détecter les erreurs est familier à tout le monde. Lorsque je viens de déployer le projet, la journalisation consistait à envoyer une trace de pile au mail. Cela ne fonctionnait que pour le backend, mais je voulais également garder une trace des bugs sur le frontend. Et pas en vain - j'ai épuisé la limite de messages gratuits en seulement 2 semaines. La plupart des erreurs se trouvaient dans les entrailles de la bibliothèque de cartes Google, ce qui à première vue est très étrange. Au cours de l'enquête, il s'est avéré que tout était de ma faute. Les corrections ont duré plus d'un mois, mais c'était une pratique très utile de gestion des erreurs javascript.

- crowdin.com - localisation. Je prévois de rendre le projet accessible à tous. Y compris que les infoboxes étaient montrées dans sa langue maternelle. Les remplir à partir de Wikipedia n'est pas un problème, mais pour des raisons de cohérence, j'aimerais également avoir une interface dans la même langue, et jusqu'à présent, elle n'a été traduite qu'en russe et en anglais.

image

- CircleCI . Aucun projet moderne ne peut se passer de CI / CD, de tests et de déploiement automatique. J'ai choisi CircleCI uniquement parce que j'avais déjà travaillé avec TravisCI lorsque j'ai écrit la bibliothèque pour travailler avec Yandex.Disk . J'ai l'impression qu'il convient mieux pour tester des bibliothèques, comme il est facile de définir la matrice des environnements dans lesquels le code doit être testé. Mais avec les tests eux-mêmes, j'ai un problème - il n'y en a pas autant que nous le souhaiterions, bien que l'infrastructure soit déjà prête.

image

- Combinaisons . Service de visualisation de la couverture du code. Capable de donner également une étiquette à insérer dans le projet README.md.

- SonarQube . Moissonneuse pour le contrôle de la qualité du code. Il vérifie le code selon diverses règles, prend en compte la complexité cyclomatique, surveille la couverture par des tests et reconnaît même la duplication de code! Un service très intéressant que je n'ai pas encore eu le temps de bien comprendre.

image

- Les robots Github. Jusqu'à présent, seul Dependabot est connecté, ce qui met à jour les dépendances.

image

Je propose dans les commentaires de partager la liste des services et des bots sur leurs projets.

Bugs


L'analyse des bogues et des problèmes mérite un article séparé. Il y en avait de drôles, complexes et difficiles à corriger (par conséquent, la Tchoukotka se tient toujours à sa place). Actuellement, il y en a un qui dérange vraiment les utilisateurs. Lorsqu'une réponse est reçue, les polygones sont supprimés et recréés (dans la bibliothèque react-google-maps), et si à ce moment l'utilisateur en a fait glisser, la carte Google continue de supposer que le processus n'est pas encore terminé. Il semble que dans le processus de glisser-déposer, le polygone disparaisse et vous ne pouvez plus en saisir d'autre. Vous pouvez, bien sûr, verrouiller le traitement des réponses dans le processus de glisser-déposer, mais cela est garanti pour tuer le jeu multijoueur, sur lequel je travaille actuellement. J'ai essayé de trouver un moyen d'interrompre le glisser-déposer par programme, mais à la fin j'ai soulevé une question sur StackOverflow et un bug sur Google Maps dans l'espoir qu'ils y prêteraient attention. Jusque-là, il a ajouté un bouton «le jeu est cassé!», Qui réinitialise toute la carte, mais ne réinitialise pas le résultat.

Et ensuite?


  1. Conception. J'avoue qu'avec ça, tout est complètement mauvais. Il est nécessaire d'embaucher un concepteur et un concepteur de mise en page, car je ne suis pas moi-même ami avec la mise en page et les mises en page.
  2. Monétisation. Au départ, je n'avais rien prévu. Le projet est dédié à l'éducation de base qui, à mon avis, devrait être accessible à tous. J'ai été très inspiré par une lettre d'une école danoise, mais près d'un an s'est écoulé et pendant cette période, il n'y a eu qu'un seul transfert de 5 $. Eh bien, je ne pensais pas que cela pouvait même payer pour le serveur. Cependant, il a quand même commencé une campagne sur Patreon . Dans le même temps, vous pouvez probablement penser à introduire des opportunités rémunérées pour les enseignants ou les organisations. Par exemple, j'ai une expérience d'intégration avec Learning Management Systems - un ensemble de plates-formes qui vous permettent de créer des cours et sont très populaires en Europe et aux États-Unis. Pour autant que je sache, même si le code source est également sous GPL sur Github, cela ne m'empêche pas, en tant qu'auteur, de développer une version commerciale parallèle.
  3. Téléphones portables. Je souhaite publier une application pour iOS / Android. À en juger par la métrique Yandex, un quart des utilisateurs essaient de jouer à partir d'un téléphone ou d'une tablette, mais il s'avère qu'ils ont des difficultés.
  4. Développement. Tout le travail est effectué sur GitHub . Je veux continuer à développer le projet, mais le faire seul est difficile. Les plans incluent l'ajout de multijoueur, la création de balises, de notes et de filtres dans l'atelier, l'ajout de polygones pour une carte physique (montagnes, mers, péninsules). Il y a encore beaucoup de choses intéressantes, donc l'un des objectifs de l'article est de trouver des personnes partageant les mêmes idées. Une autre option est d'aller à la fondation, par exemple, la Python Software Foundation et d'obtenir une subvention.

Voici ce qui est en ce moment. Merci d'avoir lu jusqu'au bout! Vous pouvez jouer ici - geopuzzle.org , et regarder le code source sur GitHub .

Minute de soins OVNI


Ce matériel peut provoquer des sentiments contradictoires, donc avant d'écrire un commentaire, rafraîchissez quelque chose d'important dans votre mémoire:

Comment écrire un commentaire et survivre
  • N'écrivez pas de commentaires offensants, ne soyez pas personnels.
  • Abstenez-vous d'un langage obscène et d'un comportement toxique (même sous une forme voilée).
  • Pour signaler des commentaires qui enfreignent les règles du site, utilisez le bouton "Signaler" (si disponible) ou le formulaire de commentaires .

Que faire si: moins de karma | compte bloqué

Code des auteurs Habr et habraetiket
Version complète des règles du site

Source: https://habr.com/ru/post/fr427209/


All Articles