Panel de control de Unity: lecciones aprendidas al escalar nuestras interfaces, cultura de desarrollo y procesos

En Unity, nos propusimos recientemente mejorar nuestros paneles, una empresa que cambió drásticamente no solo nuestra pila de tecnología de interfaz, sino también la forma en que trabajamos y colaboramos.

Hemos desarrollado las mejores prácticas y herramientas para ayudarnos a escalar nuestra arquitectura de interfaz, crear productos con excelente UX y rendimiento, y ofrecer nuevas funciones antes.

Este artículo reúne estas prácticas y tiene como objetivo proporcionar el mayor razonamiento posible detrás de cada decisión. Pero primero, algo de contexto.

El legado

En cuanto al número de ingenieros, Unity cuadruplicó su plantilla en los últimos 4 años. A medida que la empresa creció tanto orgánicamente como a través de adquisiciones, su oferta de productos también creció. Si bien los productos desarrollados originalmente en Unity eran en gran medida uniformes en términos de tecnología y lenguaje de diseño, los recién adquiridos, naturalmente, no lo eran.

Como resultado, teníamos varios paneles de control visualmente distintos que funcionaban y se comportaban de manera diferente y que no compartían elementos de navegación comunes. Esto resultó en una mala experiencia de usuario y usuarios frustrados. En un sentido muy literal, el estado de las interfaces de nuestros productos nos estaba costando ingresos.

Después de analizar el portafolio de nuestros productos, obtuvimos tres secciones distintas que Unity Dashboard se dividiría en: Desarrollar, Operar y Adquirir, cada una de las cuales satisface una necesidad comercial diferente y está destinada a diferentes grupos de clientes, por lo que contiene conjuntos de características en gran medida independientes entre sí. .

Esta nueva estructura y la introducción de elementos de navegación comunes tenían como objetivo resolver el primer problema importante al que se enfrentaban nuestros usuarios: dónde encontrar la información y las opciones de configuración que buscan y, si bien todo se veía bien en papel, el viaje cómo llegar allí estaban lejos de ser obvios.

Consideraciones

Muchos de nuestros desarrolladores estaban muy entusiasmados con la posibilidad de pasar a React y su tecnología más moderna. Como estas soluciones habían sido probadas en batalla en aplicaciones grandes y tenían sus mejores prácticas y convenciones en su mayoría resueltas, las cosas parecían muy prometedoras.

Sin embargo, lo que nuestros desarrolladores sabían mejor y en lo que estaban escritas la mayoría de nuestras aplicaciones desarrolladas activamente era AngularJS. Decidir comenzar a migrar todo de una sola vez habría sido un desastre esperando a suceder. En cambio, nos propusimos probar primero nuestras suposiciones en una escala mucho menor.

Quizás el grupo de productos más inconexo que hemos tenido fueron los paneles de monetización . Estos proyectos, que eventualmente terminarían bajo el paraguas del tablero de Operate, eran muy diferentes en casi cualquier forma posible: tecnologías utilizadas, enfoque de UI / UX, prácticas de desarrollo, convenciones de codificación, lo que sea.

Así es como se veía aproximadamente la situación:

Después de una lluvia de ideas, identificamos las áreas principales en las que tendríamos que trabajar para reunir todos los productos:

1. Un solo producto

Necesitábamos estos paneles (divididos en múltiples aplicaciones, dominios y pilas de tecnología) para:

  • Siéntete como un solo producto (sin redireccionamientos de página completa mientras el usuario navega por las páginas de todas las diferentes aplicaciones)
  • Tener un aspecto y una sensación consistentes
  • Incluir elementos de navegación comunes que siempre están visibles y tienen el mismo aspecto, sin importar qué parte del panel de control esté visitando el usuario

2. Soporte heredado

Si bien tuvimos una pizarra limpia en lo que respecta a la elección de tecnología de nuestra nueva solución de interfaz, tuvimos que adaptarnos a los proyectos heredados que debían integrarse en el nuevo sistema. Una solución que no implicó grandes esfuerzos de refactorización y que no detendría el desarrollo de funciones ni se retrasaría durante meses sin un final a la vista.

3. Prácticas y herramientas

Si bien casi todos los equipos usaban AngularJS, se usaban diferentes herramientas para abordar el mismo conjunto de desafíos. Diferentes corredores de prueba y bibliotecas de afirmaciones, soluciones de administración de estado o falta de ellas, jQuery vs selectores de navegador nativos, SASS vs LESS, bibliotecas de gráficos, etc.

4. Productividad de los desarrolladores

Dado que cada equipo tenía su propia solución para desarrollar, probar y construir su aplicación, el entorno de desarrollo a menudo estaba plagado de errores, pasos manuales e ineficiencias.

Además, muchos de nuestros equipos trabajan en ubicaciones separadas por una diferencia de 10 horas (Helsinki, Finlandia y San Francisco), lo que hace que la toma de decisiones eficiente sobre cualquier pieza compartida sea un verdadero desafío.

El nuevo

Nuestras principales áreas de enfoque fueron:

  1. Fomentar y preservar formas ágiles de trabajar en nuestros equipos y permitir que los equipos sean en gran medida independientes entre sí.
  2. Aprovechar y desarrollar herramientas y convenciones comunes tanto como sea posible, para documentarlas y hacerlas fácilmente accesibles y utilizables.

Creíamos que lograr estos objetivos mejoraría significativamente nuestro tiempo de comercialización y la productividad de los desarrolladores. Para que eso sucediera, necesitábamos una solución que:

  • Cree funciones de productos con una mejor experiencia de usuario
  • Mejorar la calidad del código
  • Permita una mejor colaboración sin bloquear el progreso del trabajo de nadie en el proceso.

También queríamos alentar y facilitar el cambio a una pila de tecnología moderna para que nuestros desarrolladores estén más satisfechos con su trabajo y, con el tiempo, se alejen de nuestros marcos y herramientas anticuados.

El resultado en constante evolución de nuestro trabajo es un SPA basado en React construido dentro de un monorrepositorio donde todas las páginas y características más grandes se integran en paquetes de código en gran medida independientes cargados a pedido, y que pueden ser desarrollados e implementados por varios equipos al mismo tiempo. .

Como un medio para aislar todas las aplicaciones heredadas, pero aún mostrándolas en el contexto de la misma aplicación nueva, las cargamos dentro de un iframe desde el cual pueden comunicarse con el SPA principal usando un bus de mensajes implementado usando la postMessage()API.

El monorepositorio

Aquí está la estructura de directorio con la que comenzamos:

/src /components /scenes /foo /components package.json foo.js /bar /components package.json bar.js package.json index.js

El package.jsonen el directorio raíz contiene un conjunto de devDependencies responsables del desarrollo, prueba y entorno de compilación de toda la aplicación, pero también contiene dependenciesel núcleo de la aplicación (más sobre esto un poco más adelante).

Todos los fragmentos más grandes de la interfaz de usuario se denominan escenas . Cada escena contiene un lugar package.jsondonde dependenciesse definen los componentes de esa escena. Esto hace posible dos cosas:

  1. La implementación actualiza solo los archivos que han cambiado

    El paso de compilación compila paquetes de aplicaciones y proveedores separados para cada escena, nombrando cada uno con un hash que cambiará solo cuando el contenido del archivo haya cambiado. Esto significa que nuestros usuarios solo descargan archivos que han cambiado desde su última visita, y nada más.

  2. Las escenas se cargan solo cuando es necesario

    Cargamos todas las escenas de forma asincrónica y bajo demanda lo que mejora drásticamente los tiempos de carga de toda la aplicación. El "bajo demanda" aquí generalmente significa visitar una ruta específica o realizar una acción de IU que realiza una importación de módulo dinámico.

Así es como se ve dicha configuración en la práctica (simplificada para facilitar la lectura):

// In src/routes.jsconst FooLoader = AsyncLoadComponent( () => import(‘src/scenes/foo/foo’), GenericPagePreloader,);
// In src/scenes/foo/foo.js 

El AsyncLoadComponentes un envoltorio delgado alrededor React.lazy(), que además acepta un componente de precargador, el mismo que pasó a través de respaldo React.Suspense()y un retraso después del cual el precargador debe ser renderizado si la escena no ha terminado de cargarse.

Esto es útil cuando se asegura de que nuestros usuarios vean el mismo precargador sin ninguna interrupción o destello de contenido desde el momento en que se solicita una escena hasta el momento en que se han descargado todos sus archivos, se han completado todas las solicitudes críticas de la API y el componente ha terminado de renderizar.

Niveles de componentes

A medida que crece cada aplicación, su estructura de directorios y abstracciones evolucionan junto con ella. Después de aproximadamente medio año de crear y mover características a la nueva base de código, tener un directorio de componentes único resultó insuficiente.

Necesitábamos que nuestra estructura de directorio nos informara sobre:

  • ¿Se han desarrollado los componentes para que sean genéricos o están pensados ​​solo para un caso de uso específico?
  • ¿Son lo suficientemente genéricos para usarse en toda la aplicación o deben usarse solo en ciertos contextos?
  • ¿Quién es el responsable y el más conocedor del código?

En base a eso, hemos definido los siguientes niveles de componentes :

1. Específico de la aplicación (src / app)

Componentes de un solo uso que se adaptan a casos de uso específicos dentro de esta aplicación, y que no están destinados a ser reutilizados o extraídos a la biblioteca de componentes (rutas, pie de página, encabezado de página, etc.).

2. Genérico (src / componentes)

Componentes genéricos de usos múltiples que se utilizarán en toda la aplicación y sus escenarios. Una vez que hayamos llegado a una API estable para estos componentes, podrían trasladarse a la biblioteca de componentes comunes (más sobre eso a continuación)

3. Componentes de una sola escena (src / scenes / my-scene / components)

Componentes desarrollados con un caso de uso específico en mente; no está destinado a ser utilizado en otras escenas. Para los casos en que un componente de una escena debe usarse en otra, usaríamos:

4. Componentes de varias escenas (src / scenes / components / my-feature)

Los componentes se utilizan en múltiples escenas, pero no están pensados ​​para ser lo suficientemente genéricos como para usarse en cualquier otro lugar. Para ilustrar por qué simplemente moverlos a src/componentsno es suficiente:

Imagine que hasta ahora ha tenido una sola escena que contenía componentes que se usaron para construir algunos gráficos de datos bastante específicos. Su equipo ahora está construyendo una segunda escena que usará diferentes datos para los gráficos, pero visualmente los dos se verán más o menos iguales.

La importación de componentes de una escena a otra rompería la encapsulación de la escena y significaría que ya no podemos estar seguros de si los cambios realizados en los componentes de una sola escena solo afectan a esa escena.

Para este propósito, cualquier componente o grupo de componentes, a los que se hace referencia aproximadamente como una característica, se colocaría src/scenes/componentsdesde donde puede ser importado y utilizado por cualquier otro equipo, sin embargo:

Siempre que un equipo desee comenzar a usar componentes de escena que otro equipo desarrolló, la mejor práctica sería comunicarse primero con ese equipo para averiguar si el caso de uso para el que desea utilizar estos componentes puede ser compatible de manera segura en el futuro. Dar un aviso al equipo que desarrolló originalmente el código evitará que se envíen funciones defectuosas en el futuro cuando el código que ha puesto en uso inevitablemente se cambie de maneras que no esperaba (porque, por supuesto, ¡cómo podría hacerlo!) que no siempre pueden ser detectados por las pruebas unitarias.

5. Biblioteca común

Componentes que hemos probado en batalla en producción y queremos extraer a nuestra biblioteca de componentes compartidos, utilizados por otros equipos de tablero en Unity.

Oda a las dependencias compartidas

Si bien sería muy conveniente poder construir e implementar cada pieza de nuestra aplicación en un entorno completamente aislado, ciertas dependencias, tanto bibliotecas externas como código de aplicación interno, simplemente se utilizarán en todo el código base. Cosas como React en sí, Redux y toda la lógica relacionada con redux, componentes de navegación comunes, etc.

Implementando los cambios

Por el momento, encapsular completamente las escenas no es práctico y, en muchos casos, simplemente imposible. Sería necesario enviar muchas dependencias varias veces y, en el proceso, ralentizar la carga de las páginas, o crear abstracciones destinadas a hacer que ciertas bibliotecas funcionen de formas para las que no han sido diseñadas.

Sin embargo, a medida que el desarrollo web y su ecosistema evolucionan, las bibliotecas parecen volverse cada vez más independientes y encapsuladas, lo que esperamos que en el futuro signifique poca o ninguna dependencia compartida y un verdadero aislamiento entre todos los módulos.

Quizás el mayor inconveniente de la creación de aplicaciones a gran escala es realizar cambios de código y actualizaciones de dependencias sin romper algo en el proceso.

El uso de un monorrepositorio hace posible (aunque no obligatorio) implementar cambios y actualizaciones en el código de manera más gradual y segura; si un cambio causa problemas, estos problemas solo afectarán a una pequeña parte de la aplicación, no a todo el sistema.

Y aunque para algunos la capacidad de realizar actualizaciones en múltiples áreas no relacionadas de la base de código al mismo tiempo sería un beneficio, la realidad de tener varios equipos trabajando en la misma base de código y no conocer a fondo todas las características de los otros equipos significa que Se necesita mucha precaución al construir el andamio de aplicación y tomar medidas para minimizar el riesgo de rotura.

Cómo evitar romper cosas

Quizás la estrategia más fundamental que nos ayuda a hacerlo, además del aislamiento de la escena, es tener una alta cobertura de pruebas unitarias .

  1. Pruebas

Por supuesto, las pruebas unitarias no lo son todo: muchos productos maduros, incluso a una escala moderada, invierten después de todo en conjuntos de pruebas de integración y e2e que hacen un mejor trabajo al verificar si la aplicación funciona como se esperaba en general. Sin embargo, a medida que aumenta el número de funciones, también lo hace el coste de mantenimiento y el tiempo necesario para ejecutarlas, un coste que no siempre puede justificarse por funciones menos cruciales pero importantes.

Algunas lecciones que hemos aprendido de varias estrategias de prueba:

  • Intente realizar una prueba unitaria tanto del código como sea posible, especialmente: lógica condicional, transformaciones de datos y llamadas a funciones
  • Invierta y aproveche las pruebas de integración en toda su extensión antes de decidir escribir cualquier prueba e2e. El costo inicial de las pruebas de integración es mucho más alto, pero palidece en comparación con el precio de mantenimiento de una suite e2e
  • Intente no reaccionar de forma exagerada comenzando a escribir pruebas e2e para cosas que no fueron detectadas por pruebas unitarias o de integración. A veces, los procesos o las herramientas tienen fallas.
  • Deje que los casos de prueba expliquen el comportamiento de la interfaz de usuario en lugar de los detalles de implementación
  • Las pruebas automatizadas no pueden reemplazar completamente las pruebas manuales

2. Minimizar la superficie del código compartido

Aparte de las pruebas, el código reutilizado en toda la aplicación se mantiene en un mínimo razonable. Una de las estrategias más útiles hasta ahora ha sido mover los componentes y el código más comúnmente usados ​​a una biblioteca de componentes compartidos, desde donde se usan como dependencias en escenas que los necesitan. Esto nos permite implementar la mayoría de los cambios de forma progresiva, por equipo o por página.

3. Responsabilidad

Por último, pero no menos importante, un factor importante para que varios equipos puedan colaborar dentro de la misma base de código proviene de alentar y hacer que los desarrolladores asuman la responsabilidad personal y la rendición de cuentas por el producto , en lugar de descargar la responsabilidad de probar correctamente que todo funciona a QA, testers o automatización.

Esto también se traslada a las revisiones de código. Asegurarse de que cada cambio se revise cuidadosamente es más difícil de lo que parece en la superficie. A medida que el equipo trabaja en estrecha colaboración, se desarrolla un buen grado de confianza entre sus miembros. Sin embargo, esta confianza a veces puede traducirse en que las personas sean menos diligentes con los cambios realizados por los desarrolladores más experimentados o confiables.

Para fomentar la diligencia, enfatizamos que el autor del PR y el revisor son igualmente responsables de asegurar que todo funcione .

Biblioteca de componentes

Para lograr la misma apariencia en todas las páginas de nuestros paneles, hemos desarrollado una biblioteca de componentes. Lo que destaca en nuestro enfoque es que los componentes nuevos casi nunca se desarrollan dentro de esa biblioteca.

Cada componente, después de ser desarrollado dentro de la base de código del tablero, primero se utiliza en un montón de características dentro de esa base de código. Por lo general, después de unas semanas, comenzamos a sentirnos más seguros de que el componente podría moverse, dado que:

  • La API es lo suficientemente flexible como para admitir los casos de uso previsibles
  • El componente ha sido probado en una variedad de contextos.
  • El rendimiento, la capacidad de respuesta y la UX se tienen en cuenta

Este proceso sigue la Regla de tres y tiene como objetivo ayudarnos a liberar solo los componentes que son realmente reutilizables y que se han puesto en uso en una variedad de contextos antes de ser trasladados a nuestra biblioteca común.

Algunos de los ejemplos de los componentes sobre los que nos moveríamos incluirían: pie de página, encabezado de página, elementos de navegación lateral y superior, bloques de construcción de diseño, pancartas, versiones activadas de botones, elementos de tipografía, etc.

En los primeros días, la biblioteca de componentes solía estar ubicada en la misma base de código que la propia aplicación. Desde entonces, lo hemos extraído a un repositorio separado para democratizar más el proceso de desarrollo para otros equipos de Unity, algo importante a la hora de impulsar su adopción.

Diseño de componentes modulares

Durante mucho tiempo, construir componentes reutilizables significó lidiar con múltiples desafíos, muchos de los cuales a menudo no tenían buenas soluciones:

  • Cómo importar fácilmente el componente junto con sus estilos, y solo eso
  • Cómo anular los estilos predeterminados sin guerras de especificidad del selector
  • En componentes más grandes que constan de varios más pequeños, cómo anular el estilo del componente más pequeño

Nuestro panel, así como nuestra biblioteca de componentes, dependen y utilizan en gran medida la interfaz de usuario de Material. Lo que es especialmente atractivo en la solución de estilo de Material UI es el potencial que aporta JSS y su lenguaje de estilo unificado (que vale la pena leer), que hace posible desarrollar interfaces de usuario encapsuladas por diseño como en el caso de los módulos CSS, y resolver lo mencionado anteriormente. problemas con paso rápido.

Esto difiere significativamente de enfoques como BEM que proporcionan encapsulación por convención que tienden a ser menos extensibles y menos encapsulados.

Guía de estilo de vida

Una biblioteca de componentes no estaría completa sin una forma de mostrar los componentes que contiene y poder ver los componentes a medida que cambian a lo largo de las versiones.

Hemos tenido una experiencia bastante buena con Storybook, que fue ridículamente fácil de configurar y comenzar, pero después de un tiempo nos dimos cuenta de que se necesitaba una solución más sólida y de un extremo a otro. Bastante parecido a lo que ofrece Styleguidist, pero más adaptado a nuestras necesidades.

Documentos de diseño existentes

La documentación que sirve como fuente principal de información sobre la última especificación de diseño se ubicó en Confluence, donde los diseñadores mantuvieron una especificación actualizada para cada componente usando capturas de pantalla que ilustran los casos de uso permitidos, estados y variaciones en las que el componente podría estar, enumerado mejores prácticas, así como detalles como dimensiones, colores usados, etc. Siguiendo ese enfoque, nos hemos enfrentado a una serie de desafíos:

  • La especificación de diseño de materiales sigue evolucionando y debido a eso, a menudo nos encontramos pasando tiempo actualizando todas las capturas de pantalla y pautas, o dejando que nuestras pautas de diseño se vuelvan obsoletas.
  • Averiguar cuál es más correcto: la implementación o la especificación no siempre fue una tarea fácil. Debido a que hemos estado publicando demostraciones de Storybook de cada componente y para cada versión de la biblioteca, pudimos ver qué y cómo cambió. No pudimos hacer lo mismo con las especificaciones de diseño.
  • Las capturas de pantalla y los videos solo pueden comunicar algo . Para proporcionar componentes de alta calidad y que puedan ser utilizados por varios equipos, es necesario revisar si cada componente funciona en todas las resoluciones, está libre de errores y tiene una buena experiencia de usuario; esto era difícil sin que el diseñador se sentara literalmente a tu lado para ver el demostración de implementación que se muestra en la pantalla

Aplicación de documentación de componentes

Nuestra aplicación de documentación tiene como objetivo proporcionar los medios de colaboración eficiente entre diseñadores e ingenieros para que sea más simple y menos costoso para ambas partes documentar, revisar y desarrollar componentes. Para ser más específicos, necesitábamos:

  • Tener un único punto de referencia que muestre los componentes , cómo¿Deberían verse, comportarse y usarse? Se proporcionan para cada versión, reemplazando descripciones detalladas con demostraciones en vivo
  • Facilite la colaboración de diseñadores y desarrolladores en componentes y sus documentos y hágalo antes de que se publiquen los componentes, sin la necesidad de compartir videos, capturas de pantalla o estar físicamente en la misma ubicación
  • Separe los diseños en lo que planeamos hacer frente a lo que se ha hecho

De manera similar, como antes, cada versión de la biblioteca de componentes provoca la publicación de una nueva versión de la guía de estilo viva. Sin embargo, esta vez hay algunas diferencias:

  1. Los diseñadores contribuyen a la documentación de los componentes directamente editando los archivos de documentación a través de la interfaz de usuario de Github, confirmando cambios en la última versión.
  2. Demostraciones de componentes como WYSIWYG : el mismo código que ve como ejemplo de cómo implementar el componente se utiliza para representar la demostración, incluidas las importaciones de archivos intermedios, declaraciones de variables, etc. Como beneficio adicional, los componentes envueltos en withStyles()se muestran correctamente (problema presente en Storybook en este momento).
  3. Los cambios en los documentos y el código son visibles casi instantáneamente sin verificar la sucursal localmente e iniciar la aplicación de documentación: la aplicación se reconstruye y publica en y para cada confirmación.

Experiencia de desarrollo

Uno de los principales objetivos de las revisiones de código es asegurarse de que cada cambio se revise, considere y pruebe cuidadosamente antes de fusionarse e implementarse.

Para que esta tarea esté lo más libre de obstáculos posible, hemos desarrollado un servidor de vista previa capaz de crear una nueva versión de nuestra aplicación cada vez que se crea o actualiza un PR.

Nuestros diseñadores, gerentes de producto e ingenieros pueden probar cada cambio antes de fusionarlo, tanto en los entornos de producción como en los de ensayo y en cuestión de minutos después de realizar el cambio.

Palabras de cierre

Ha pasado casi un año desde que nos comprometimos a consolidar nuestros paneles. Hemos pasado ese tiempo aprendiendo cómo hacer crecer un proyecto de software grande pero saludable, cómo mejorar la colaboración y la comunicación, y cómo elevar el nivel de calidad por nosotros mismos.

Escalamos un proyecto frontend no solo en términos de líneas de código, sino también en términos de la cantidad de ingenieros que trabajan dentro de su base de código, una cantidad que se cuadruplicó desde el principio.

Hicimos un cambio de 180 grados al tratar con las diferencias de tiempo entre nuestros equipos, alejándonos de un modelo en el que nuestros equipos trabajaban en total aislamiento a uno en el que la colaboración y la comunicación cercanas son algo cotidiano.

Si bien todavía tenemos un largo camino por recorrer para asegurarnos de que podemos escalar nuestro enfoque a más equipos y a desafíos más grandes, ya hemos notado una serie de mejoras:

  • Hoja de ruta y visibilidad del trabajo

    Debido a que hay un lugar donde se lleva a cabo todo el trabajo, se realiza un seguimiento del progreso y todos los problemas se recopilan en

  • Velocidad de desarrollo y tiempo de comercialización

    Se pueden crear nuevas funciones en gran parte a partir de componentes ya existentes y bien probados, que se pueden encontrar fácilmente a través de nuestra aplicación de documentación.

  • Calidad de código y cobertura de prueba

    Al construir cosas nuevas, normalmente ya existe una solución a un problema similar y está al alcance de la mano, junto con ejemplos de cómo probarlo.

  • Calidad general y UX

    Probar funciones y garantizar su calidad es ahora más fácil que nunca, ya que los diseñadores, gerentes de producto y otras partes interesadas pueden probar cada cambio en su propia máquina, con sus propias cuentas y conjuntos de datos.

Naturalmente, a lo largo del camino nos hemos encontrado con una serie de desafíos que debemos resolver, o que tendremos que resolver en el futuro:

  • Rendimiento de construcción y CI

    A medida que aumenta el número de dependencias, paquetes de compilación y pruebas, también aumenta el tiempo necesario para realizar una implementación. En el futuro, necesitaremos desarrollar herramientas que nos ayuden a construir, probar e implementar solo las piezas que cambiaron.

  • Cultura de desarrollo

    Para crear software saludable, necesitamos trabajar continuamente en formas saludables de comunicar e intercambiar ideas, y las comunicaciones basadas en texto hacen que esta tarea sea más difícil. Estamos trabajando para abordar este problema a través de una serie de sesiones periódicas de capacitación en liderazgo y adoptando formas de trabajo más de código abierto, además de organizar algunas sesiones de reunión al año para que los equipos se conozcan cara a cara.

  • Aislamiento de roturas y actualizaciones

    A medida que aumenta el número de funciones y páginas, necesitaremos una forma más sólida de aislar nuestros módulos de aplicación para evitar que el daño se extienda cuando las cosas salgan mal. Esto podría lograrse mediante la creación de versiones de todo el código compartido (lógica redux, src / componentes) o, en casos extremos, produciendo compilaciones independientes de ciertas características.

Estado entonces, ahora y en el futuro

La migración ha implicado pasar de AngularJS a React. Así es como cambió la situación durante el año pasado:

¡Es una envoltura! ¡Gracias por leer! Puedes encontrarme en LinkedIn aquí.

Si trabajar en desafíos similares le parece interesante, siempre estamos buscando ingenieros talentosos para unirse a nuestros equipos en todo el mundo.