GeoPuzzle: crea el mundo pieza por pieza

imagen

Quiero hablar sobre un proyecto que se ha desarrollado en los últimos años. Se llama GeoPuzzle y es un juego de rompecabezas en el mapa político del mundo. El objetivo es poner piezas del país en su lugar. La idea se vio en el artículo "Rompecabezas de Mercator para expertos en geografía" , también jugó tetris de países (aún bajo DOS) en la infancia, pero no recuerdo el nombre del programa. La idea me inspiró tanto que quería hacer un producto completo, interesante no solo para los escolares, sino también para los expertos en geografía. El desarrollo del proyecto se puede observar en GitHub .

Prototipo


El 8 de febrero de 2013 se publicó el artículo "Puzzle Mercator para expertos en geografía", pero después de 4 meses tenía listo un prototipo en el que se ensamblaban los polígonos de todos los países del mundo. Un poco más tarde, agregué las regiones de Rusia y los Estados Unidos e hice la elección de la posición inicial en el mapa para polígonos al azar. Describí el proceso de desarrollo en mi blog , publiqué el código fuente en GitHub . Y eso es todo, atascado. Obtuve mucho menos tiempo libre, mi motivación desapareció (no se tomó ninguna decisión) y la complejidad aumentó exponencialmente. Era un proyecto favorito, y la tarea principal era aprender algo nuevo, así que estaba un poco pervertido con la tecnología. En el cliente, por supuesto, javascript (con el que no trabajé mucho entonces), el script ruby ​​(nuevamente, un nuevo lenguaje para mí) fue responsable de la preparación de los datos, pero en el servidor había erlang (quería probar algo puramente funcional). Salida completa de la zona de confort: fue difícil trabajar directamente con objetos PostGIS, el dolor de convertir cadenas a erlang, configurar YAWS fue un problema completamente diferente ... En la siguiente etapa, me di cuenta de que no podía hacer frente a todo este zoológico para hacer un producto completo, y me fui piensa por un par de años.

GeoPuzzle


imagen

El sitio ha estado funcionando todo este tiempo, la gente incluso fue allí, pero realmente quería agregar un pequeño detalle más: mostrar al menos algo de información sobre el polígono recién descubierto. Por lo tanto, planeé pasar las vacaciones de Año Nuevo en 2017 con beneficio. Debido a problemas en el prototipo, decidí reescribir todo y hacer que el producto sea algo familiar: Django. Fuera de la caja hay cosas que han simplificado enormemente mi vida, por ejemplo, el panel de administración y trabajar con PostGIS a través de ORM. Pero para empezar, era necesario recrear la funcionalidad que ya funcionaba. Solo tomó un par de tardes, y la mayoría del tiempo se tomó cargando datos de archivos KML. No tanto el proceso de importación en sí como la preparación y restauración de mi conocimiento sobre cómo trabajar con ellos. Por cierto, tomé polígonos de gadm.org en ese momento. Esto funcionó muy bien para los países, pero hubo ciertos problemas con la precisión de las regiones, así que tomé un tiempo de espera para este problema.

Algunas palabras sobre niveles administrativos en geodatos (niveles).
Todos los países se dividen en muchas regiones, que se dividen en partes aún más pequeñas. En total, hay 12 capas en dicha jerarquía.

Por ejemplo, para Rusia:

  • Rusia (2) -> Distrito Federal del Sur (3) -> Territorio de Krasnodar (4) -> Distrito de Vyselkovsky (6) -> Art. Pueblos (8)
  • Rusia (2) -> Distrito Federal del Sur (3) -> Territorio de Krasnodar (4) -> Krasnodar (6) -> Distrito de Prikubansky (9) -> Kopanskaya (10)
  • Francia (2) -> Metrópolis de Francia (3) -> Región de Normandía (4) -> Departamento de Orne (6) -> cantón de Donfron (7) -> municipio de Donfron-en-Poiret (8) -> Donfron (9)

Las unidades territoriales en diferentes países se llaman a su manera, pero para mí deduje esta división: País (2) -> Región (4) -> Distrito (6). Más división administrativa se fue para más tarde.

Desarrollo del proyecto


En ese momento, la aplicación era solo una colección de páginas HTML con un mínimo de CSS. Quería comprobar rápidamente la idea y no molestarme con el diseño. La idea resultó ser realizable, y es hora de hacer una hermosa concha para ella. Porque No tengo sentido de la belleza en la interfaz de usuario, luego Bootstrap para ayudarme. No hay interfaz, pero apareció, e incluso se adaptó para dispositivos móviles. Pero este fue solo el primer paso para poner la interfaz en orden.

¿Qué se siente al aprender JavaScript en 2016 ? Cuando el código se compila en otro dialecto, se crea una plantilla, se pega para que luego se pueda cortar en pedazos. Yo, como backend, tenía miedo, pero la complejidad de la parte del cliente se planificó lo suficientemente grande, lo que implicaba la necesidad de usar un marco o biblioteca. Me decidí por React por dos razones: no necesitaba SPA, sino un conjunto de componentes para diferentes páginas, y quería ver rápidamente el resultado. Pero antes de comenzar a programar, tenía que configurar el entorno. Ahora entiendo el front-end familiar, que dijo que configuró Webpack durante 2 días. Resulta que no fue una broma.

En ese momento, sucumbí a la persuasión e implementé la lógica de la aplicación usando Redux. Quizás esto no fue un error, porque permitido ingresar rápidamente al tema. Las reglas formales me permitieron escribir código y asegurarme de que funcionara sin mirar bajo el capó. El uso de Redux con su middleware me abstrajo de la interacción de la red, lo que me permitió verificar las respuestas al servidor. Sí, hasta este punto, el cliente trabajó por su cuenta: una solicitud de ajax extrajo todos los datos necesarios y verificó las respuestas por su cuenta. El usuario podría hacer trampa mirando los datos que provienen del servidor. Además, al cargar, los datos volaron, necesarios solo después de la respuesta correcta. Después de implementar la verificación a través de sockets web, el proceso se ha vuelto ideológicamente más correcto: la respuesta verifica el código que no está disponible para el cliente. Para el usuario, esto todavía parecía instantáneo: enviar los puntos extremos del polígono al servidor, verificar si ingresaron al cuadrado con un error, empaquetar los datos para el cuadro de información y el polígono detallado en json y transferirlo al cliente, encajar en ~ 200 ms.

imagen

Habiendo aprendido todo el poder de javascript, es difícil de detener. Inmediatamente surgieron ideas sobre dónde agregar animaciones, bloques plegables, parpadeos y nuevas versiones de juegos. Uno de ellos es "Quiz", en el que debes adivinar el país por su nombre, bandera, escudo de armas o capital. Es cierto que durante el proceso de prueba resultó que algunas regiones no tenían banderas, mientras que otras no tenían una capital, por lo que algunos países tuvieron que ocultarse de la lista de los disponibles. Al mismo tiempo, apareció un modo de juego en el mapa físico del mundo, sin fronteras de países, para verdaderos profesionales.

Abrir fuentes de datos


Hay ~ 50,000 polígonos en el juego en este momento, y quiero agradecer enormemente a proyectos tan grandes como Wikipedia y Open Street Map, sin los cuales habría sido imposible llenar la base. El requisito fundamental era recibir y actualizar datos de fuentes abiertas, es decir, sin edición manual, porque No quiero hacer una lógica de sincronización compleja. Como resultado, obtuve 2 scripts que pueden actualizar cuadros de información y polígonos.

Wikipedia y SPARQL


imagen

¿Cuál es la base de datos más grande de países y regiones? Wikipedia! Inicialmente, quería mostrar a los usuarios el cuadro de información completo, pero pronto abandoné esta idea. Sí, había cosas importantes como nombres, banderas, capitales y otras cosas, pero también había mucha basura (código de teléfono, forma de gobierno, PIB ...). Traté de analizar ya recopilados, pero descubrí que tienen una estructura diferente. Esto resultó ser un desastre: los costos laborales para la implementación aumentaron muchas veces. Era hora de detenerse y pensar. Al día siguiente aprendí sobre la existencia de un lenguaje de consulta especial: SPARQL. En apariencia, se parece a SQL, también declarativo, con las palabras clave SELECT , WHERE , ORDER BY , pero funciona de una manera completamente diferente. Un pequeño ejemplo que devuelve una lista de estados con sus capitales en inglés y ruso:

 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 salvaje, ¿no? Mira aquí . Incluso escribí una pequeña nota en mi blog para estructurar de alguna manera mi experiencia y ayudar a entrar en el tema, porque Hay pocos materiales detallados en Internet. Puede aprender a leer tales solicitudes con bastante rapidez, pero me tomó todo un fin de semana escribir algo significativo. Mucha "magia" de wd:Q3624078 y otros atributos. wdt:P31 saber que wdt:P31 es una "entidad", y wd:Q3624078 es un "estado soberano". Las personas desconocidas comienzan con un signo de interrogación, y el cumplimiento de la solicitud consiste en la búsqueda de tales triples de hechos que satisfagan las condiciones. Por ejemplo ?country wdt:P31 wd:Q3024240 - "encontrar todos los objetos que son estados históricos"; y luego el mismo objeto participa en otros triples ?country wdt:P36/rdfs:label ?capital - de dónde ?country wdt:P36/rdfs:label ?capital el capital.

Aproximadamente una semana después, tenía lista la primera versión del guión, que descargaba información regional de Wikipedia. Y luego quedó claro otro problema, esta vez con los datos. Algunos svg no comenzaron con <?xml version="1.0" encoding="UTF-8"?> Y el navegador no los reconoció como imágenes válidas. Afortunadamente, el archivo fuente se puede editar. Registrarse en wikipedia.org no tiene nada de complicado, pero inmediatamente te encuentras en una casa de baños por un día. Aquí está su protección contra los robots. Así que a la noche siguiente goberné XML y me alegré de lo simple que resultó, y aparecieron banderas y emblemas en el mapa.

Polígonos


imagen

Si por hechos vamos a Wikipedia, entonces por geodatos, en el Open Street Map. Sería genial recoger una copia local, aprender el idioma de las solicitudes de paso elevado , pero ni siquiera puedo imaginar cuánto tiempo tomaría. Y también necesita tomar la jerarquía de algún lugar ... Afortunadamente, una persona amable ya ha resuelto este problema por mí . El servicio incluso proporciona una API para recuperar información. Logré descargar desde allí todos los polígonos hasta el nivel 6 inclusive (distrito) y llenar todo en Postgres, salieron un poco más de 2 Gb. No fue sin aventuras: algunos polígonos eran tan grandes (por ejemplo, Canadá pesa más de 100 Mb en un GeoJSON comprimido) que el servidor se bloqueó o no respondió. Tuve que pasar por alto esos momentos manualmente. Descargué a todos los niños y los fusioné en QGIS. Por cierto, este es otro ejemplo de un proyecto de código abierto que me ha ayudado mucho.

Problemas de Big Data


Entonces, tengo una base de datos con datos, inicio el juego y ... y espero ... otra vez espero ... ¡apareció! Traté de arrastrar el polígono. ¡Está muerto, Jim! Chrome no pudo manejar tal volumen de puntos y se cayó. La estrategia de la frente ya no funciona, es hora de pensar. Lo más obvio es reducir el detalle de los polígonos. Derivó empíricamente una fórmula que depende del área de la figura: mejoró. En una computadora que funciona, el algoritmo funcionó sobre la marcha, mientras que el servidor está severamente limitado en recursos. Redis conectado, mejoró ya en el servidor. Pero los polígonos truncados son buenos para Drag'n'Drop, y cuando se configuran en el lugar correcto, los bordes no coinciden con los que dibujan los mapas de Google. Bueno, esto se puede evitar aplicando una fórmula no tan agresiva para reducir los detalles. Como ya hay 2 cachés, ¿por qué no tratar de almacenar todo lo que es posible? Los cuadros de información (en dos idiomas) volaron a Redis, los bordes por los cuales se calcula la respuesta, el centro del polígono, así como las páginas estáticas del sitio. Como resultado, el juego comenzó a funcionar mucho más rápido y se eliminó mucha carga de trabajo de Postgres, lo que en teoría podría ser el cuello de botella. Menos: la aplicación no funciona sin Redis en absoluto.

Primer despliegue


Por lo tanto, es hora de mostrar el proyecto a los amigos para recibir comentarios. Solo quedaba un poco: generar sitemap.xml, agregar robots.txt, conectar métricas, agregar botones sociales. redes y ... desplegar! Elegí AWS como hosting, como esperaba encajar en los recursos gratuitos proporcionados. Y esta es una muy buena pila para un proyecto de principiante:

  • servidor de aplicaciones (t2.micro: 1xCPU, 1 Gb RAM, 20 Gb SSD)
  • base de datos (db.t2.micro: 1xCPU, 1 Gb RAM, 20 Gb SSD)
  • almacenamiento de archivos con CDN (5 Gb S3, 50 Gb de tráfico)
  • servidor de almacenamiento en caché (cache.t2.micro: 1xCPU, 0.5 Gb RAM)
  • Elasticsearch + Kibana (t2.small.elasticsearch: 1xCPU, 2 Gb RAM)

Esta es solo una lista de lo que logré usar. En el camino, decidí elaborar mi rastrillo en forma de artículos , pero morí rápidamente. El tiempo pasa decentemente, pero no está claro si alguien lo necesita.

Como resultado, por el año de servicio pagué algo del orden de $ 10, e incluso eso por estupidez. Pero aquí el período de prueba llegó a su fin y tuve que mudarme porque El costo de poseer toda esta economía comenzó a acercarse a varios cientos de dólares. Tarifas comparadas y liquidadas en DigitalOcean. Por ahora, tengo suficientes máquinas con 2 Gb de RAM para todo (servidor de aplicaciones, base de datos y caché), sin embargo, dejé las estadísticas y CDN en AWS. Ahora descubrí que DO también obtuvo un CDN y almacenamiento por $ 5 / mes, por lo que tiene sentido pensar en mover esta parte también.

Transferencia a código abierto


Esta tarde de enero recibí una carta de una escuela danesa. Su esencia se redujo al hecho de que tienen $ 100 y quieren dármelos. Pero hay una condición: el código fuente del proyecto debe estar abierto. Hasta ese momento, ni siquiera había pensado en Open Source. Un par de noches fue a pensar y elegir una licencia. Como resultado, cargué las fuentes en Github bajo la licencia GPLv3 y recibí los $ 100 prometidos. Esto aumentó enormemente la motivación: ¡mi proyecto fue realmente útil! Y me apresuré al siguiente objetivo: el editor del juego. Para que todos puedan crear sus propios rompecabezas. Por ejemplo, "Países que participan en la Segunda Guerra Mundial", "Distritos del territorio de Krasnodar", "Países sin litoral" ... Pero para esto, se necesitaba el registro y una cuenta personal primitiva. Como resultado, el desarrollo se prolongó durante 3 largos meses. Durante este tiempo, escribí un árbol de regiones que extraería datos a través de ajax, conectaría la localización, aprendería cómo guardar un mapa de Google como una imagen para generar vistas previas y cortar redux. Sí, me ayudó a lidiar con los datos desde el principio, pero ahora es más probable que interfieran. Tendría que arrastrar reductores para dibujar polígonos en el mapa, junto con el código que manejaría su movimiento. Afortunadamente, eliminar el enlace al estado global tomó solo un par de días, y mover el código al estado local incluso simplificó la aplicación. Y, por supuesto, esta es una buena experiencia :)

Conexión de servicio


Resulta que muchos servicios pagos brindan sus servicios de forma gratuita para proyectos de código abierto. Enumeraré solo aquellos que conecté con los míos.

- Centinela . Creo que este servicio para detectar errores es familiar para todos. Cuando acabo de implementar el proyecto, el registro consistió en enviar un seguimiento de la pila al correo. Esto funcionó solo para el backend, pero también quería hacer un seguimiento de los errores en la interfaz. Y no en vano: he agotado el límite de mensajes gratuitos en solo 2 semanas. La mayoría de los errores estaban en las entrañas de la biblioteca de mapas de Google, lo que a primera vista es muy extraño. Durante la investigación, resultó que todo fue mi culpa. Las correcciones duraron más de un mes, pero fue una práctica muy útil para el manejo de errores de JavaScript.

- crowdin.com - localización. Planeo hacer que el proyecto sea accesible para todos. Incluyendo que los cuadros de información se mostraban en su idioma nativo. Completarlos desde Wikipedia no es un problema, pero por coherencia también me gustaría tener una interfaz en el mismo idioma, y ​​hasta ahora solo se ha traducido al ruso y al inglés.

imagen

- CircleCI . Ningún proyecto moderno puede prescindir de CI / CD, pruebas y despliegue automático. Elegí CircleCI únicamente porque ya trabajaba con TravisCI cuando escribí la biblioteca para trabajar con Yandex.Disk . Tengo la impresión de que es más adecuado para probar bibliotecas, ya que Es fácil establecer la matriz de entornos en los que se debe probar el código. Pero con las pruebas en sí, tengo un problema: no hay tantas como quisiéramos, aunque la infraestructura ya está lista.

imagen

- Overoles . Servicio de visualización de cobertura de código. Capaz de dar también una etiqueta para su inserción en el proyecto README.md.

- SonarQube . Cosechadora para control de calidad de código. Comprueba el código de acuerdo con una variedad de reglas, considera la complejidad ciclomática, monitorea la cobertura mediante pruebas e incluso reconoce la duplicación de código. Un servicio muy interesante, que aún no tuve tiempo de entender completamente.

imagen

- Github bots. Hasta ahora, solo Dependabot está conectado, lo que actualiza las dependencias.

imagen

Sugiero en los comentarios compartir la lista de servicios y bots en sus proyectos.

Bichos


El análisis de errores y problemas merece un artículo separado. Eran divertidos, complejos y difíciles de arreglar (por lo tanto, Chukotka siempre está en su lugar). Actualmente, hay uno que realmente molesta a los usuarios. Cuando se recibe una respuesta, los polígonos se eliminan y se recrean (en la biblioteca react-google-maps), y si en ese momento el usuario arrastró algunos, el mapa de Google continúa asumiendo que el proceso aún no ha terminado. Parece que en el proceso de arrastrar y soltar, el polígono desaparece y ya no puedes tomar ningún otro. Por supuesto, puede bloquear el procesamiento de la respuesta en el proceso de arrastrar y soltar, pero se garantiza que esto matará al juego multijugador, cuya implementación estoy trabajando actualmente. Traté de encontrar una manera de interrumpir el arrastrar y soltar mediante programación, pero al final planteé una pregunta sobre StackOverflow y un error en Google Maps con la esperanza de que le prestaran atención. Hasta entonces, agregó un botón "¡el juego está roto!", Que reinicializa todo el mapa, pero no restablece el resultado.

Que sigue


  1. Diseño. Admito que con esto, todo es completamente malo. Es necesario contratar un diseñador y un diseñador de diseño, porque yo mismo no soy amigo del diseño y los diseños.
  2. Monetización Inicialmente, no planeé nada. El proyecto está dedicado a la educación básica, que en mi opinión debería ser accesible para todos. Me inspiró mucho una carta de una escuela danesa, pero pasó casi un año y durante ese tiempo solo hubo una transferencia de $ 5. Bueno, no creía que pudiera pagar el servidor. Sin embargo, comenzó una campaña en Patreon de todos modos. Al mismo tiempo, probablemente pueda pensar en introducir oportunidades pagas para maestros u organizaciones. Por ejemplo, tengo experiencia integrándome con Learning Management Systems, un conjunto de plataformas que le permiten crear cursos, y son muy populares en Europa y Estados Unidos. Según tengo entendido, aunque el código fuente también está bajo la GPL en Github, esto no me impide, como autor, desarrollar una versión comercial paralela.
  3. Teléfonos móviles. Quiero lanzar una aplicación para iOS / Android. A juzgar por la métrica de Yandex, una cuarta parte de los usuarios intenta jugar desde un teléfono o tableta, pero resulta que tienen dificultades.
  4. Desarrollo. Todo el trabajo se realiza en GitHub . Quiero seguir desarrollando el proyecto, pero hacerlo solo es difícil. Los planes incluyen agregar multijugador, hacer etiquetas, clasificaciones y filtros en el Taller, agregar polígonos para un mapa físico (montañas, mares, penínsulas). Todavía hay muchas cosas interesantes, por lo que uno de los objetivos del artículo es encontrar personas con ideas afines. Otra opción es ir a la fundación, por ejemplo, la Python Software Foundation y obtener una subvención.

Aquí está lo que hay en este momento. ¡Gracias por leer hasta el final! Puedes jugar aquí: geopuzzle.org , y mira el código fuente en GitHub .

Minuto de cuidado de ovnis


Este material puede causar sentimientos conflictivos, así que antes de escribir un comentario, actualice algo importante en su memoria:

Cómo escribir un comentario y sobrevivir
  • No escriba comentarios ofensivos, no se ponga personal.
  • Abstenerse de lenguaje obsceno y comportamiento tóxico (incluso en forma velada).
  • Para informar comentarios que violen las reglas del sitio, use el botón "Informar" (si está disponible) o el formulario de comentarios .

Qué hacer si: menos karma | cuenta bloqueada

Código de autores Habr y habraetiket
Versión completa de las reglas del sitio

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


All Articles