Todos estos puntos se pueden aplicar al desarrollo móvil, frontend web y backend. Reuní estas prácticas de diferentes equipos y a través de los problemas que enfrenté durante los últimos 6 años. Estas prácticas pueden ser especialmente útiles cuando crea un proyecto desde cero. Algunos de ellos pueden adaptarse perfectamente a ti, mientras que otros no. Si tienes tus propios enfoques y experiencias diferentes, me encantaría que las compartieras aquí. Por cierto, si eres un desarrollador de nivel medio o junior que busca un ascenso, implementar estas prácticas en tu equipo puede ser de gran ayuda. ¡Vamos!
En un proceso estándar de desarrollo de software, cuando la empresa solicita una nueva función, se distribuye entre varios equipos: front-end, back-end y desarrollo de aplicaciones móviles.
Luego, cada equipo procede con la planificación y la descomposición de tareas. Pero, ¿qué pasa si el equipo de back-end requiere mucho más tiempo para desarrollar su parte? ¿Qué pasa si pueden entregar terminales solo una vez a la semana?
El backend se convierte en un cuello de botella.
Los equipos de desarrollo móvil y front-end terminan trabajando así: "Oh, el back-end ya implementó esto. Déjame tomar esta tarea". Luego, toman un descanso, cambian su contexto a otra función y el ciclo continúa. Esto conduce a fatiga, disminución de la velocidad y reducción de la calidad.
Solución: acuerde un contrato con el equipo de back-end y simule todas las solicitudes.
1. Coordine con el equipo de back-end los puntos finales y las entidades.
2A. Implemente la API de back-end con respuestas de código auxiliar. La biblioteca Faker puede ayudar con la generación de datos de muestra.
2B. O implementar stubs en la interfaz. Puede ser un objeto con datos directamente en el código. Por ejemplo, en Node.js, puede implementar esto de manera eficiente mediante importaciones dinámicas y evitar aumentar el tamaño del paquete:
getUser() { return import('../../assets/mocks/users') .then(data => data.userById) .then(deserializeUser); };
Esto también puede ser un servicio HTTP simulado que obtiene archivos JSON de los activos en lugar de realizar solicitudes reales.
Oculte la entidad detrás de un indicador de entidad.
Cuando el backend esté listo, cambie a la API real si usó el enfoque de stubs de front-end y verifique que todo funcione como se esperaba. Y active esta función.
Ahora, como probablemente notó, en la sección anterior, mencioné los indicadores de funciones. En pocas palabras, los indicadores de funciones, también conocidos como conmutadores de funciones, permiten a los desarrolladores activar o desactivar funciones en un entorno en vivo. También hay un par de casos en los que son útiles: implementar nuevas funciones gradualmente, realizar pruebas A/B, habilitar funciones beta e implementar revisiones.
Usamos Gitlab para almacenar indicadores de características. Es un repositorio dedicado que es consumido por proyectos backend y frontend. La buena noticia es que tiene una interfaz de usuario fácil de usar, por lo que los gerentes de productos pueden administrar las funciones por sí mismos. Anteriormente, solíamos usar indicadores de funciones para cada repositorio de proyecto por separado. Sin embargo, este enfoque no ofrecía la posibilidad de desactivar funciones para todo el producto a la vez. Así que movemos todo al repositorio único.
En el código, parece bastante simple:
if features.YOUR_FEATURE
en el código que debe ocultarse.
Cuando nuestro producto pasó de la etapa MVP a una aplicación de producción, nos preocupaba que los usuarios recibieran errores que no podíamos reproducir y de los que ni siquiera nos daríamos cuenta. Después de investigar las herramientas de seguimiento de errores, nos decidimos por Sentry. La experiencia fue positiva. Y ahora, repasemos algunos matices importantes.
Bajo el capó, se rastreará cualquier excepción no detectada. A medida que crece la aplicación y la cantidad de usuarios, la cantidad de errores puede volverse tan abrumadora que se vuelve casi imposible notar algo verdaderamente importante. Sentry puede convertirse en un basurero si no filtra las cosas innecesarias. Por ejemplo, eventos como solicitudes canceladas, errores de conexión y errores de secuencias de comandos conectadas son completamente inútiles y solo enviarán spam a su correo electrónico de trabajo con notificaciones. Como solución, puede agregar filtros a la configuración. Para hacer esto, simplemente defina una devolución de llamada beforeSend
y colóquela en su sentryPackage.init
. En esta devolución de llamada, puede analizar cada error detectado y luego descartarlo (devolviendo nulo) si es inútil. Aquí hay un ejemplo de un filtro que excluye errores innecesarios:
function beforeSend(event, hint) { const error = hint.originalException; const externalScripts = [ 'gtm.js', // Google Tag Manager 'watch.js', // X Analytics ].join('|'); const errorsToIgnore = [ AxiosError.ERR_NETWORK, AxiosError.ECONNABORTED, AxiosError.ETIMEDOUT ]; if (axios.isCancel(error) || errorsToIgnore.includes(error.code) || error.stack?.match(externalScripts)) { return null; } return event; }
De forma predeterminada, es posible que Sentry no incluya el contenido de la solicitud y la respuesta en el informe de errores. Sin esta información, la depuración adecuada es imposible. Afortunadamente, en el controlador beforeSend
, podemos incluir esta información.
function beforeSend(event, hint) { const error = hint.originalException; if (error.isAxiosError) { const url = error.request?.responseURL; const response = error.response?.data; const request = error.config?.data; event.extra = { ...(event.extra || {}), url, response, request }; } return event; }
Los datos como contraseñas, direcciones de correo electrónico y claves no deben incluirse en el contenido del error. Sentry tiene un mecanismo incorporado para ocultar este tipo de información. Puedes configurarlo en los ajustes de seguridad. Además, también puede eliminar algo en el objeto de evento en beforeSend
Si la naturaleza de su negocio prohíbe almacenar este tipo de datos en un servidor en otro lugar, Sentry ofrece la posibilidad de usarlos en sus propios servidores.
Imagine una situación en la que captura con éxito un error en Sentry, pero la información en la descripción es insuficiente. Acude a los registros, pero ¿cómo puede identificar el error específico entre miles de solicitudes e incluso más líneas de registro por segundo? ¿Cómo puede distinguir los correctos, construir la cadena de solicitudes e identificar el error exacto, especialmente cuando su empresa tiene varios equipos y se integra con otros servicios? Aquí es donde entra en juego el rastreo.
En nuestra implementación específica, usamos Jaeger , que se basa en la API de OpenTracing.
En pocas palabras, cada solicitud y todas sus llamadas a métodos se etiquetan con una etiqueta única. Cada etiqueta tiene una referencia a su padre y algunos metadatos. La estructura de este número depende de la implementación, pero en cuanto a OpenTracing, puede leer cómo funciona y familiarizarse con términos como intervalo, referencia, hijo, padre, etc. en la página oficial del repositorio . En la vida real, afortunadamente, rara vez se utilizará el rastreo. Sin embargo, en estos raros accidentes, puede ahorrarle tiempo.
Cuando implementamos el MVP de la aplicación fintech, teníamos una forma bastante complicada. En ese momento, todavía era joven e inexperto. Y finalmente, nos dimos cuenta de que nuestro proyecto se estaba ralentizando. Tuvimos que pasar horas adicionales para averiguar el motivo. Tuvimos muchos renderizados innecesarios porque ignoramos las reglas básicas relacionadas con los accesorios en React. Quería hacer todo lo posible para evitar tales situaciones en el futuro.
Entonces, agregué al proyecto linters como este y una configuración de inicio adicional a package.json para ejecutar why-did-you-render . En resumen, este complemento emite una advertencia si algo se vuelve a procesar innecesariamente y sugiere cómo evitarlo. Además, incluimos la ejecución de Lighthouse en modo sin cabeza . Algunas personas dicen que las optimizaciones prematuras son malas, pero para mí es un principio: hacerlo bien desde el principio .
Probablemente hayas oído hablar de la teoría de las ventanas rotas. Si hay una ventana rota en un edificio y nadie la reemplaza, eventualmente no quedará una sola ventana intacta en ese edificio.
Cuantas menos reglas y controles haya en un proyecto, mayor será la tentación de escribir código de baja calidad o de escribirlo con un estilo completamente diferente. El código inconsistente aumenta el tiempo que lleva comprenderlo, mientras que el código claro, familiar y conciso permite una lectura rápida. En uno de nuestros equipos, describimos el estilo de codificación en un solo lugar . Como un excelente punto de partida, puede tomar el estilo de código Prettier o Airbnb .
Ya se ha escrito una cantidad significativa de literatura sobre los diferentes tipos de pruebas, enfoques y cómo escribirlos correctamente. Lo único que vale la pena mencionar aquí es que ninguna aplicación de producción puede sobrevivir sin pruebas de regresión. Es por eso que enfocamos todos nuestros esfuerzos en crear un marco de prueba completo de extremo a extremo y, en base a él, escribimos pruebas que están vinculadas con escenarios de BDD e historias de usuarios. Utilizamos el patrón de objeto de página para organizar nuestro código y el marco de Playwright para interactuar con el navegador. Para probar en diferentes navegadores, incluido Safari, puede usar una solución llamada Moon . Se puede implementar en uno de sus servidores.
¡Gracias por tomarse el tiempo de leer este artículo! En conclusión, este artículo destaca prácticas clave de ingeniería de software que mejoran los procesos de desarrollo y la calidad del código. Al adoptar técnicas como la simulación de respuesta de back-end, indicadores de características, monitoreo de errores, optimización del rendimiento, estándares de estilo de código, pruebas de regresión y seguimiento, puede crear un software más eficiente y confiable. ¡Sigamos mejorando nuestro software y manteniéndonos en contacto! :)