Cómo lidiar con la descomposición de tareas y no exagerar

¡Hola!



Mi nombre es Victor, soy analista de sistemas en Sportmaster. Y hoy me gustaría hablar sobre descomponer tareas y transferirlas al desarrollo. Cualquier objeto consta de partes, ya sea un automóvil o un producto de software. Y llevará tiempo ensamblar cualquiera de estos objetos en un solo todo a partir de sus partes componentes. A veces incluso lleva mucho tiempo. Especialmente si antes no solo desarmaste la parte principal, sino que decidiste llegar al fondo a nivel atómico.





¿Dónde está la línea entre un entorno adecuado de tareas y un caos total? Compartiré un ejemplo de cómo en Sportmaster recibimos periódicamente tareas de desarrollo de las empresas.















Como puede ver en los ejemplos anteriores, la descripción de cada tarea depende en gran medida de la imaginación y el sentido común del cliente. En algún lugar es más, en algún lugar es menos, pero los analistas necesitan trabajar con eso de alguna manera. A veces también indican los límites de la funcionalidad y, a veces, simplemente envían un tema. Si transferimos tal tarea directamente al desarrollo, obtendremos algo incomprensible en el resultado. ¿Que tienes que hacer?



Camine hacia el cliente con los pies y pregunte todos los requisitos, aclare qué debe haber exactamente en la salida. Es cierto que todavía hay clientes de oro, de los cuales, de hecho, la mayoría, escriben todos los requisitos en su Confluence, por lo que puede leerlo en cualquier momento y hacer preguntas. Y cuando todo esté claro con el marco de la función, puede comenzar a cortar la tarea.



Por que descomponer



El objetivo principal de la descomposición es que la empresa pueda implementar rápidamente todos sus deseos, y que el usuario tome el menor tiempo posible desde la idea en sí hasta la aparición de la funcionalidad. Para hacer esto, puede hacer tareas más pequeñas, de las cuales, aunque pequeñas, pero aún así, la funcionalidad de trabajo llegará al usuario.



Además de lograr el objetivo global de satisfacer las necesidades de los usuarios y las empresas, la descomposición de tareas le permite obtener comentarios más rápidos del cliente, ya sea que el desarrollo vaya en la dirección correcta o que no resulte en absoluto lo que el cliente imaginó.



Si la tarea es inicialmente grande y la asumimos por completo de una vez, entonces le dedicaremos mucho tiempo y después de los comentarios del cliente tendremos que tirar todo a la basura. Bueno, si la tarea es pequeña, uno o dos días de trabajo como máximo, está bien. El reproceso tomará aproximadamente la misma cantidad. El segundo enfoque también es más económico. Sin mencionar los nervios salvados en ambos lados.



Si una funcionalidad se divide en varias partes, los desarrolladores pueden trabajar en ellas en paralelo. Por lo tanto, paralelizaremos el flujo y aceleraremos la salida de la funcionalidad en prod. Lo importante es que las tareas dependan lo menos posible unas de otras.



Además de pruebas rápidas y corrección de errores. Una vez más, una pequeña funcionalidad es mucho más fácil y rápida de probar que un monstruoso coloso. Y si algo sale mal, el desarrollador gastará muy poco en "arreglar" y todo funcionará más rápido.



En la etapa de desglose de tareas, junto con el cliente, puede comprender de inmediato qué funcionalidad es importante aquí y ahora, para comenzar a obtener ganancias, qué se puede dejar para más adelante y qué, tal vez, se considerará innecesario.



Es importante para las empresas saber qué tan rápido aparecerá la funcionalidad de trabajo. Y cuando se divide en tareas, podemos predecir y estimar con mayor precisión el tiempo que llevará completarlas que cuando tiene un gran frente de trabajo. Pero además del hecho de que las pequeñas tareas son más fáciles de evaluar en términos del tiempo para resolverlas, también es más fácil para un desarrollador evaluar los riesgos que pueden surgir en el proceso.



Por ejemplo, se actualizaron los frameworks, se dejaron fuera de servicio algunos métodos, problemas con el código, etc. Al llevar pequeñas tareas al trabajo, minimizamos todos estos riesgos, e incluso si tal tarea bloquea algo en el hilo, no será tan crítico como si fuera una pieza pesada (que bloquearía todo). Si es necesario, será posible hacer una solución de trabajo y poner una deuda técnica en el backlog, que se puede tratar un poco más tarde, cuando se resuelvan los problemas.



Enfoques básicos y reglas de descomposición.



Hay dos enfoques principales para la descomposición de tareas: horizontal y vertical. Con horizontal, las tareas se dividen por tipo de trabajo, por nivel o por componente. Por ejemplo, cada tarea pasa por varias etapas: front-end, back-end, bases de datos. Y con un enfoque horizontal, una tarea va hacia atrás, la segunda hacia el frente y la tercera conduce a cambios en la base de datos.



¿Por qué este enfoque es malo? No obtenemos la funcionalidad de trabajo después de completar cada tarea individual. Solo al recopilar los resultados de tres fuentes, podemos obtener algún tipo de resultado y comentarios al respecto. Por esta razón, la descomposición horizontal no se usa con mayor frecuencia.





Mucho más conveniente es el enfoque vertical, en el que se puede realizar una funcionalidad visual en cada tarea: la tarea pasa por todas las etapas y la salida contiene un resultado que se puede analizar, probar, mostrar al cliente y corregir, si es necesario. Y rápidamente inicie y use.



Si hablamos de las reglas, aquí solo he identificado tres. Primero, la tarea debe ser lógicamente completa, es decir, independiente en sí misma. No debe romper la lógica que lo rodea y necesariamente debe tener al menos algún sentido comercial que el usuario recibirá como resultado. Al mismo tiempo, no debe dividir en partes aquellas tareas que no tienen sentido comercial (idealmente, no deberían existir en absoluto).



En segundo lugar, el resultado de completar una pequeña tarea debería traer pequeños cambios. Cuanto más pequeños son los cambios, más rápido entran en el código común y, por lo tanto, el código no se vuelve obsoleto. Además, las pequeñas tareas ayudan a evitar conflictos entre desarrolladores cuando se fusionan.



En tercer lugar, no debes dividir la tarea en partes muy microscópicas. Si se desglosa demasiado pequeño, llevará mucho tiempo administrar estas tareas. En cada etapa, es posible que tengan que volver a priorizarse, volver a colocar dependencias, y eso es todo. Por lo tanto, la velocidad de desarrollo no aumentará, sino que, por el contrario, disminuirá drásticamente. Por lo tanto, debe buscar un término medio.



Métodos de descomposición



Dependiendo de la fuente, el número de métodos de descomposición varía enormemente: en algún lugar hay solo ocho, en algún lugar diez, en algún lugar veinte. Me gustaría resaltar las formas que tengo que utilizar todos los días en el trabajo.



Múltiples necesidades



Este método es más conveniente cuando hay conjunciones "y", "o" en la historia. Por ejemplo, un consumidor desea realizar un pedido y pagar con una tarjeta o bonificaciones. Esta tarea se puede dividir en tres: la primera, en la que el usuario realiza un pedido, la segunda, donde paga con una tarjeta, y la tercera, donde se utilizan bonificaciones.



Escenarios de uso



Otra forma común es dividir las tareas según el caso de uso. En este caso, una historia es un camino principal y varios alternativos. Digamos que un usuario quiere comprar un artículo y ese sería el escenario principal. Pero todavía hay formas alternativas: puede poner el producto en la canasta de inmediato y pagar, o puede querer comparar este producto con otros antes de comprarlo. Y luego hacemos de la comparación de productos una tarea separada.



Quizás no quiera comprar en este momento, pero posponerlo en algún lugar, agregarlo a favoritos, para que pueda regresar más tarde. O al usuario le gustó el producto y está listo para comprarlo, pero está agotado. Por lo tanto, debe informarle cuándo aparecerán los productos. Y así es como obtenemos cuatro escenarios.



De lo simple a lo complejo



La página principal del sitio "Sportmaster" consta de banners. Y lo más simple que podemos hacer es tomar una foto y mostrársela al usuario. Esta es la forma más fácil y rápida de transmitir la información correcta. Luego, podemos aumentar la funcionalidad y agregar no una imagen, sino tres o cuatro, que se combinan en una cuadrícula. Esta es una tarea separada.





Con este enfoque, con cada tarea posterior, la funcionalidad debería crecer. Por ejemplo, podemos hacer un carrusel a partir de la cuadrícula y luego agregar algunos enlaces, textos, botones y el resto. En general, primero implementamos la versión más simple y de rendimiento más rápido, y luego pasamos a una más compleja.



Hace poco estuve involucrado en una tarea similar de implementar un banner. Se suponía que la pancarta colgaría en la principal y se controlaría desde el CMS. Si le pregunta al cliente qué es exactamente lo que le gustaría administrar, responderá felizmente sin parpadear: todos. Por lo tanto, aquí era importante profundizar un poco en el tema y resaltar lo que se debe administrar en este momento, lo que se usa con frecuencia y lo que casi nunca se usa. Y así, priorizar la implementación y dividir en tareas.



Operaciones (CRUD)



Esta es probablemente la forma más común de descomposición. Aquí, las tareas se dividen en operaciones de creación, lectura, actualización y eliminación. Es adecuado para tareas en las que necesita administrar algo o configurar algo. Por ejemplo, la tarea de realizar un pedido se divide en cuatro más pequeños: crear un pedido, visualizarlo, editarlo y eliminarlo.



Opciones de interfaz



Se utiliza cuando es necesario admitir varias opciones de interfaz. Por ejemplo, un sitio debe admitir varios idiomas. Primero, creamos la versión rusa. Luego, al lanzar en otros países, agregamos inglés. Si el país usa un idioma que no sea el inglés, también podemos agregarlo. En este caso, es más fácil hacer todo primero en un idioma y luego agregar gradualmente las traducciones.





Más recientemente, completamos un proyecto para una cuenta personal para entidades legales, que necesitaba soporte multilingüe. Los plazos eran ajustados, por lo que inicialmente hicieron todo en un idioma, pero sentaron las bases para futuras traducciones. Ahora, agregar soporte para un nuevo idioma solo requiere una pequeña tarea. Si necesita agregar varios idiomas a la vez, se crea una tarea separada para cada uno de ellos.



Separación por rol



Adecuado para situaciones en las que la funcionalidad implica el funcionamiento de varios roles y grupos de usuarios. En el sitio de Sportmaster, un usuario puede tener diferentes roles. Por ejemplo, los usuarios se dividen por roles en un usuario autorizado, un usuario anónimo y, digamos, un usuario del centro de llamadas. Este último rol también se puede dividir en dos: puede ser un usuario normal o un administrador.



Para cada rol, podemos hacer una tarea separada. Comience mostrando para un usuario anónimo y luego agregue algunas funciones avanzadas como parte de una tarea para un usuario autorizado. Y no se olvide de los roles técnicos de los operadores del centro de llamadas y la funcionalidad para ellos.



Procesamiento de errores



Si los plazos son ajustados y se necesita la funcionalidad mínima lo más rápido posible, puede mover el manejo de errores a una tarea separada. Aquí no estamos hablando de escribir pruebas, sino de manejar errores de usuarios y sistemas con los que está integrado el sitio. Digamos que estamos procesando una página de catálogo que contiene un mosaico de producto. Cada tarjeta tiene una descripción, foto e información adicional.



Ocurrió que parte de la información no proviene de las bases de datos.

Quizás, si estamos hablando de una marca o material, entonces esto se puede descuidar y simplemente no se muestra información. Pero si el precio o el nombre no sube, ¿vale la pena mostrar esta tarjeta?



¿Qué hacer en tal situación? Esta pregunta se puede sacar en una tarea separada y luego procesar cada campo por separado. Es decir, si el precio no llegó, entonces realizamos una acción, la descripción del producto se pierde, otra. Lo mismo ocurre con los errores del usuario. Si ingresó algo incorrectamente y se mostró un error, por ejemplo, "Página no encontrada" o error 500, debemos mostrarle información específica sobre lo que sucedió y ofrecerle un script de lo que puede hacer a continuación.



Este método también es adecuado para situaciones en las que necesita obtener rápidamente comentarios sobre la funcionalidad para decidir si conservarla o no.



Estático luego dinámico



Esta es una de mis formas favoritas. Adecuado en situaciones en las que es posible implementar la funcionalidad "en stubs", es decir, los sistemas externos no están preparados para admitir la funcionalidad. Por ejemplo, algunos bloques de la página principal no se pueden controlar desde el CMS. O un menú, cuando lo creamos en nuestro código y se lo mostramos al usuario, pero al mismo tiempo no puede ser controlado por la empresa. Y para poder realizar cambios, la empresa necesita ir constantemente al desarrollo y solicitar hacerlo.



Aquí, priorizamos las necesidades y los beneficios de los usuarios. El usuario obtiene la funcionalidad lista para usar de inmediato, aunque es posible que experimentemos algunos inconvenientes en el interior. Por lo tanto, dividimos la tarea en varias y primero ponemos el nuevo bloque a disposición del usuario, pero la empresa aún no puede administrarlo directamente. Pero luego podemos integrarnos con algún sistema o base de datos, donde la propia empresa puede intercambiar elementos y agregar otros nuevos por sí mismo, y los dibujaremos sin participación de desarrollo.



A menudo usamos este método: primero, creamos funcionalidad en nuestros propios datos, que no se pueden controlar desde afuera, y luego agregamos dinámicas y comenzamos a recibir datos de sistemas de terceros.



Actuación



Si la tarea en su conjunto es compleja y voluminosa, no está claro con qué fin abordarla, entonces se puede descuidar el desempeño. La primera tarea es sacar una funcionalidad lista para usar que de alguna manera, aunque lentamente, funcionó. Y la siguiente tarea es acelerar el trabajo. Por ejemplo, puede ser un trabajo lento de buscar productos, aplicar filtros, obtener cualquier información.



A veces, la mayor parte del esfuerzo se invierte en crear rápidamente una función, la implementación inicial no es tan difícil. Pero puede aprender mucho de la implementación lenta, además de que tiene algún valor para el usuario que de otra manera no podría realizar alguna acción importante. En todos estos casos, las tareas se dividen en "hacer que funcione" y "hacerlo rápido".



Posibles dificultades



Si decide utilizar la descomposición de tareas en sus proyectos, lo más probable es que la primera dificultad que encontrará será la dependencia de las tareas entre sí. En mi experiencia, este es el problema de bloqueo de hilos más común. Para evitar esto, la descomposición debe abordarse de manera responsable y debe darse el tiempo suficiente.





Otra dificultad es determinar qué tan finamente necesita descomponer la tarea. Y aquí solo el sentido común actúa como límites. Por ejemplo, tomamos el componente de selección de ciudad. Tiene botones, algo de texto, un campo de entrada. ¿Qué tan pequeño debería superar esta tarea?



Hemos deducido una regla para nosotros mismos de que la tarea debe realizarse a lo largo de todo el flujo en no más de una semana (aproximadamente 40 horas). Estamos hablando de todas las etapas: la etapa de análisis, desarrollo, pruebas. Además, se tienen en cuenta dos etapas de desarrollo de backend y frontend, incluida la revisión y las pruebas en cada una.



También tuvimos un problema con el hecho de que los límites de la epopeya no siempre están claros. Recientemente nos dieron la tarea de realizar un pedido. ¿Dónde están sus fronteras? ¿Cuál debería ser la salida? No teníamos claro si teníamos que hacer toda la funcionalidad hasta el final o elegir alguna parte. ¿Esta epopeya incluye el pago, o ya es una epopeya separada?



Hay tareas que son difíciles de entender cómo descomponer y cuándo. Descomponemos la mayoría de las tareas en la etapa de recibir la epopeya, pero hay situaciones en las que es necesario hacerlo, por ejemplo, en la etapa de análisis. Nos tomamos la tarea a trabajar y creemos que todos los datos necesarios ya están en nuestros sistemas de integración, pero durante el análisis resulta que o no estamos satisfechos con el formato de los datos, o el problema está en la calidad de los datos en sí, o se requiere mejora de otros sistemas con los que Estamos conectados. Luego tenemos que hacer la tarea "en stubs" y agregar otro elemento al backlog, que iniciaremos después de haber resuelto los principales problemas.



Eso, al parecer, es todo. Será genial si comparte historias en los comentarios sobre qué enfoque de descomposición de tareas usa y por qué.



¡Gracias por leer!



All Articles