Nueva aplicación "Medusa". ¿Por qué revolotear?

El director técnico Boris Goryachev habla sobre cómo Medusa trabajó en él durante un año y por qué fue escrito en Flutter


El 12 de mayo, tuvo lugar el lanzamiento de las nuevas aplicaciones móviles de Medusa ( iOS , Android ), casi dos años después de que decidimos reescribirlas. ¿Porque tan largo? ¿Por qué no aplicaciones nativas? ¿Por qué revolotear? Todo esto lo cuenta el director técnico de Medusa Boris Goryachev.



A diferencia de nuestras viejas aplicaciones, decidimos no hacer nativas las nuevas. En primer lugar, escribir el mismo código dos veces es tedioso. En segundo lugar, nunca funcionará, de modo que en dos proyectos diferentes escritos por personas diferentes, todo es sincrónico y lo mismo. Por lo general, alguien trabaja más lento, alguien se va de vacaciones, alguien tiene una deuda técnica que debe cerrarse. Toda nuestra experiencia en la creación y el soporte de aplicaciones nativas nos ha impulsado, o estamos haciendo algo mal o simplemente no es nuestro camino. Y comenzamos a buscar el nuestro. Intentamos React Native and Ionic, pensamos en el enfoque de Basecamp: todo en la web + una capa nativa delgada, incluso intentamos ir hacia la aplicación web progresiva y permanecer en línea.

Casi al mismo tiempo, asistí a una conferencia de Google I / O y conocí a personas que hacen Flutter allí. Inmediatamente probé Dart y trabajé un poco en Flutter, pero en ese momento la tecnología aún no estaba lista para Medusa: era imposible incrustar varios materiales interactivos e incrustados dentro de nuestros materiales, pero esto es crítico para los medios. Así que decidí esperar hasta que Flutter creciera.

Durante la espera, hicimos muchas cosas en la web: reescribí el sitio, escribí una nueva versión de AMP. Escribimos y transferimos todos los proyectos de Medusa a ui-kit, una biblioteca única de componentes que usa el sitio y gracias a la cual es posible un gran número de nuestras mecánicas de juego. Dividimos las versiones de escritorio y móviles del sitio, de modo que las páginas de distribución (páginas principal y de sección) comenzaron a formarse en dos lugares diferentes de acuerdo con sus propias reglas.

Paralelamente al trabajo en el sitio, estábamos pensando en una nueva aplicación: se nos ocurrió su navegación, significados, pantallas, características, etc.



Paralelamente, se produjeron cambios importantes en la estructura del departamento técnico. Comenzamos a usar activamente el calendario de Google y otras herramientas de planificación de reuniones, y cambiamos de Trello a Basecamp. Es tan obvio que incluso es extraño hablar de eso. Pero tomó mucho tiempo y esfuerzo racionalizar el caos. Una agenda clara de reuniones, un seguimiento rápido, archivos que no se pierden y alcances de gráficos de colinas permitieron hacer frente a una gran cantidad de tareas y no morir.

¿Por qué sigue siendo Flutter? Y un poco sobre Dart


Cuando las personas aprenden sobre Flutter, inevitablemente aprenden sobre Dart. Parece que se considera el mayor inconveniente de Flutter, pero exactamente hasta que intentes escribir en él. El es realmente genial. Seguir JavaScript es muy especial.

Dart es un lenguaje de programación desarrollado por Google. Fue anunciado en 2011, es decir, todavía es un idioma joven. No se ha convertido en un lenguaje de programación importante (al menos por ahora), pero al mismo tiempo se usa muy activamente en la propia empresa. Además de Google, hay otras grandes empresas, por ejemplo, Wrike, que usan Dart y escriben una pila completa en él.

Dado que Dart y Flutter son compatibles con la misma compañía, esto hace posible cambiar el idioma a las necesidades de Flutter. Hasta donde yo sé, ambos equipos interactúan activamente entre sí, por lo que los chips aparecen constantemente en el idioma, lo que le permite escribir un código más agradable en Flutter.

No intentaré explicar en qué consiste Flutter: Wikipedia se encargará mejor de esta tarea, pero solo diré que entre los autores hay personas que han interpretado en Chromium.

En diciembre de 2018, el equipo de Flutter lanzó la biblioteca incorporada Webview en Flutter. Fue en bruto y, por cierto, todavía no ha salido del estado de vista previa de desarrolladores, pero este hecho no se detuvo para comenzar a estimar la estructura de la aplicación futura. Durante varios meses experimenté en mi tiempo libre, y luego se tomó una decisión final.

Al principio me senté a escribir una nueva versión de la API específicamente para la aplicación. La ideología de esta API se puede formular de la siguiente manera: si se puede hacer algo en el back-end, entonces debe hacerlo en el back-end. Y no porque sea difícil hacer algo en el cliente. El hecho es que los lanzamientos en la App Store y Google Play son un proceso laborioso y largo. Debe adaptarse a sus horarios de trabajo y recordar que no todos los usuarios actualizarán inmediatamente la aplicación. Esto se puede evitar cuando la lógica principal ocurre en su servidor. ¿Necesita mover el título 10 píxeles hacia abajo? De nada. ¿Eliminar o agregar un componente rápidamente? ¡No hay problemas!



Por la misma razón, la API para una aplicación móvil contiene los componentes más simples posibles, de los cuales se recolecta casi cualquier material de forma recursiva. Digo "casi" porque mostramos juegos a través de WebView. La aplicación no importa qué mostrar: una tarjeta, un podcast, noticias o "Big Top". Todo se procesa mediante un código, y la tarea de la aplicación es tomar el componente y representarlo (o ir a la lista de sus hijos y llamarlo de forma recursiva).

Otro argumento importante a favor de Flutter: el desarrollador "controla todos los píxeles". Cuando necesita asegurarse de que en todas partes haya sombras correctas, como en el diseño en Sketch, o si desea que la transparencia cambie a lo largo de las curvas, o desea que los tamaños de fuente y toda la tipografía sean personalizables, todo en Flutter es simple y realista.

Otra característica asesina de Flutter es la comodidad del desarrollo. La recarga en caliente, a la que estoy tan acostumbrado en el desarrollo web, y la rápida velocidad de recarga de la aplicación sin perder el estado hacen que el trabajo sea lo más fácil posible. No necesita sentarse y esperar hasta que se reconstruya la aplicación, luego esperar hasta que el nuevo código esté funcionando y repetir el estado en el que está trabajando. Todo sucede muy rápido y genial.

Ecosistema


Aunque Flutter y Dart aún no son tecnologías muy populares, no tuvimos problemas para encontrar bibliotecas. La mayor parte de lo que se necesita en la aplicación está en el marco mismo o en pub.dev. La comunidad es muy agradable y está lista para ayudar. Esta comunicación es un verdadero soplo de aire fresco, muy solidario.

Además, Google mismo es compatible con Flutter. Utilizamos Firebase para empujar, análisis, perfiles y almacenar datos del usuario (historial de lectura, posiciones de episodios, marcadores), y todo "simplemente funciona" allí. Por supuesto, como una persona que nunca ha escrito aplicaciones nativas antes, a veces es una locura meterse en archivos gradle o poner propiedades en info.plist. Pero generalmente todo está en Google, y no hay nada increíblemente complicado.

Diferencias de plataforma


Puedes hablar infinitamente sobre la diferencia entre iOS y Android. Como regla general, recuerdan de inmediato que los patrones deben ser familiares para el usuario y que se deben seguir las pautas de diseño. Estamos de acuerdo con esto, pero no del todo. Es importante recordar su identidad corporativa, el sentido común y la lógica de comportamiento de los usuarios que ya le son familiares.

Si observa el historial de las plataformas en sí, vemos que algunos patrones cambian con los dispositivos, mientras que otros fluyen del sistema al sistema. Estas no son tabletas, nada se detiene. Hay docenas de ejemplos geniales en los que las empresas se desvían de las recomendaciones de Google y Apple y hacen lo que consideran correcto.



El ejemplo más simple y vívido es deslizar hacia atrás en iOS. El área de la pantalla que acepta deslizar es super pequeña por defecto, aproximadamente 20 píxeles. Así es como funciona la aplicación de Correo en iPhones, y es muy inconveniente. En Twitter, esta área se expande ligeramente, mientras que en Telegram, ¡es simplemente enorme! Telegram en Android tiene su propio tipo especial de navegación desde la lista de chat al chat, es un cruce entre iOS y Android. Sí, las pautas son geniales, pero en el iPhone XR, acercar el dedo al borde superior izquierdo del dispositivo es muy inconveniente. Así que decidimos (por supuesto, confiando en los datos) que en la aplicación "Medusa", el botón "Atrás" en iOS estará debajo. Pero en Android no lo será en absoluto. Para hacer esto, hay svaypas (nuestros propios y nuevos svaypas de Android) y un botón de sistema "Atrás".

Mi colega, director de arte de Medusa Nastya Yarovaya dice:

Tengo manos pequeñas y un teléfono grande. Parece ridículo, pero afectó dos decisiones importantes en el proceso de desarrollo. Primero, propuse aumentar significativamente la zona de deslizamiento hacia atrás (aumentó al 50%), la primera desviación de las pautas. Luego, cuando trabajamos en los botones de navegación y función dentro del material, sugerí colocar el botón Atrás en el menú general a continuación: esta es otra desviación del patrón habitual en la interfaz. Ahora puede alcanzarlo con el pulgar, ya que se desplazan principalmente por él.


Sabemos que definitivamente volaremos por el hecho de que hemos violado una serie de recomendaciones de Apple y Google. Pero, en todo caso, también usamos teléfonos y entendemos que muchos patrones están desactualizados, ya que fueron inventados para los dispositivos a la mitad.

Un poco de práctica: cómo funciona en Flutter


Después de React y otros frameworks reactivos, puedes construir un prototipo en Flutter en un par de días. Idea general de Flutter: todo es un widget. Flutter ofrece dos (en realidad tres) paradigmas: puede usar widgets de material que sigan el concepto de diseño de material. Puede usar widgets de Cupertino, widgets que se ven y se comportan como en iOS. Y puedes escribir todo tú mismo.

En términos generales, hay dos tipos de widgets con los que un desarrollador interactúa: sin estado y con estado.

Los widgets sin estado son widgets más o menos que no contienen lógica dentro de ellos que deberían cambiar el estado del widget.

Los widgets con estado tienen una función setState (¡hola, reacciona!). Cambia de estado y el widget se vuelve a dibujar.

Pero, por supuesto, una aplicación grande en setState simple no irá muy lejos, por lo que se necesita una solución de administración de estado.

Hay varias soluciones para Flutter. Por ejemplo, hay un patrón BloC en el que se utilizan secuencias y eventos de fuentes de datos, que contienen lógica de negocios que provoca el nacimiento de nuevos eventos. Los widgets escuchan estos eventos y los widgets responden a los cambios.

Los que vienen después de Reaccionar pueden querer probar Redux. En teoría, no debería haber un problema si escribiste en React usando este enfoque.

Intenté ambos enfoques y terminé eligiendo un tercero. La aplicación Jellyfish usa Provider. Esta es una biblioteca que no fue escrita por Google, pero es interesante que Google, después de haber probado el Proveedor en casa, comenzó a abandonar su BloC e incluso decidió repetir el Proveedor como una biblioteca separada. Pero al final, abandonó la idea de repetir el código de otra persona y comenzó a usar y mantener lo que nació como código abierto.

El dispositivo proveedor es bastante simple. Este es un widget dentro del cual hay un estado. Este estado es cambiado por funciones que internamente llaman a notifyListeners (). Los widgets que deben responder a los cambios están en el árbol de widgets: son hijos directos del proveedor de widgets o hijos de sus hijos. Cuando se llama a notifyListeners (), los hijos obtienen nuevos valores a través del contexto y se produce la reconstrucción.

Por lo general, los proveedores se anuncian en la "parte superior" de la aplicación, y puede usar muchos proveedores a la vez, cada uno es responsable de su propia lógica de negocios.

Ahora utilizamos ocho proveedores que están "escuchando" en diferentes lugares de la aplicación. Por ejemplo, así es como funciona el proveedor de marcadores, gracias al cual los lectores pueden guardar sus materiales favoritos, leerlos sin conexión y desde el mismo lugar en diferentes dispositivos.

La reacción se agrega a la instancia a los cambios en el documento desde Firebase, que contiene claves para los materiales marcados por los lectores. Para cada onChange de este documento, la variable asociada en el proveedor se actualiza y se llama a notifyListeners. Como resultado, todos los widgets que escuchan a este proveedor muestran el ícono correcto.

A través de los proveedores, el tema de la aplicación también se ha cambiado. La aplicación tiene ThemeProvider, que contiene dos instancias de temas y, de hecho, es solo un Mapa con nuestros nombres de colores y los colores mismos.

Como resultado, el color correcto llega al widget de esta manera:

TextSpan(
	text: block['data']['first'],
	style: TextStyle(
		color: Provider.of<ThemeProvider>(context)
        .current
        .bodyFontColor,                            
  fontFamily: 'Proxima Nova',
));

El código del proveedor, si se simplifica, sería:

class ThemeProvider extends ChangeNotifier {
  CustomThemeData current;
  
  CustomThemeData blackTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  CustomThemeData lightTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  ThemeProvider(withTheme, withFontMultiplier, withAutoTheme) {
    theme = withTheme;
    autoTheme = withAutoTheme;
    current = withTheme == 'light' ? lightTheme : blackTheme;
  }
}

En consecuencia, cuando cambia la variable actual, todos los widgets que toman colores del tema se mostrarán correctamente sin excepción.

Que sigue


En las últimas semanas, hemos estado probando activamente la nueva aplicación en un grupo de varios cientos de lectores de Medusa. Le diremos cómo fueron las pruebas en un artículo separado, pero solo notaré que Flutter cumplió con todas mis expectativas. Sí, tiene una manera de desarrollar, sí, no todas las bibliotecas ricas en características, pero, observando la velocidad con la que todo se mueve, yo, al menos para mí, concluyo que Flutter con Medusa durará mucho tiempo.

All Articles