Una manera simple de gestionar riesgos en Jira es usando ROAM con los estados mostrados en la tabla (con workflow customizado) y usando prioridades para indicar severidad (usando carriles en tableros Kanban) o filtrados por Prioridad.
Los estados en riesgos usando ROAM son:
Estado TODO:
New: creado sin analizar.
Estados Inprogress:
OWNED… Riesgo asignado y asumido, sobre el que una persona del equipo actúa y se responsabiliza.
ACCEPTED… Riesgo que es asumido por el equipo, se monitoreará y se irá resolviendo según aparezca.
MITIGATED… Riesgo sobre el que establecemos una acción o acciones preventivas como plan de mitigación.
Estados DONE:
RESOLVED… Riesgo que ha sido eliminado. Resuelto.
El Workflow sería como sigue:
Y podremos hacer tableros Kanban con la siguiente estructura:
Aquí configuramos carriles 'swimlanes' para prioridades (priority = Highest AND priority = Crítica) y columnas por estado del workflow.
Un compañero me dijo que con los KPIs vemos el pasado y con los OKRs vemos el futuro. ¡Y tiene razón!
Un KPI es un indicador y siempre será un valor medible, una métrica, que muestra cómo está el desempeño del negocio. Los KPIs sirven para ‘gestión basada en datos’. Por ejemplo, el KPI “Tasa de abandono” puede ser un KPI de ventas.
Por otro lado, un OKR es un ítem estratégico para ‘gestión orientada a objetivos y basada en datos’. Entonces un OKR será un objetivo o un resultado clave. Los OKRs determinan cuáles son los objetivos y resultados que deben ser logrados. Por ejemplo, “aumentar la retención de clientes” (objetivo) “en un 15%” (resultado clave) puede ser el OKR.
Los OKR no son excluyentes de los KPI, sinó que los incluyen para proyectar y medir los resultados claves.
Con los KPI vemos el pasado y con los OKR planificamos el futuro.
Nota:
El compañero es Jose Arellano Galarce. 'Gracias por la frase'.
¿Cómo podemos usar arquitectura limpia para desarrollar ecosistemas de aplicaciones distribuidas con equipos ágiles?
Una forma es usando arquitetura Hexa3 que a continuación paso a comentar.
Patrón de tres capas
Antes de contestar esta pregunta anterior, podemos comenzar por… ¿Cómo podemos implementar una arquitectura limpia?
Una manera de ir en este camino es usar un patrón de arquitectura de software basada en capas. El “patrón de capas” (Layers Pattern) se centra en una abstracción y cohesión jerárquica de los roles y responsabilidades, proporcionando una separación efectiva de las preocupaciones (cada espacio de módulos o componentes en conjunto se encarga de lo que le corresponde). Es una manera de implementar el principio de diseño: “Separation of Concerns” (SoC). Bajo este patrón se han propuesto diferentes niveles de capas de abstracción.
Se han usado de 2 a N capas para implementar el patrón y alejarse de esas estructuras monolíticas. El más conocido es el de tres capas (3-Tier Architecture) desarrollado por John J. Donovan (POSA Volumen 1). Este es un patrón que he aplicado infinidad de veces porque es el que me ha resultado más simple. Autores como Craig Larman (en su libro “Applying UML and Patterns”) y Martin Fowler han propuesto el uso de las tres capas como las siguientes: Presentation layer, Domain Layer (business logic layer or application logic layer) y Data Layer (storage).
Implementar las tres capas ya es un gran paso para desarrollar código limpio. Y es tan simple como usar tres directorios en tu proyecto (independientemente del lenguaje de programación): Presentation, Domain y Data (o App, Domain y Data). Si agregamos la idea de Arquitectura Hexagonal (Hexagonal Architecture), dada a conocer por Alistair Cockburn, podemos considerar a la capa de datos como capa de infraestructura. Es decir que no solo se trata de acceso a datos, sino a cualquier recurso externo (archivos, apis, servidores de email, drivers, etc.). En esta línea, cambiando la nomenclatura, tu proyecto podría contener tres directorios claves: app (Application), domain e infra (Infrastructure).
Application: aquí va la interacción con los casos de uso. Todo el código de vista y lógica de presentación (vistas, páginas, estilos, etc.) con el cual interactúa el usuario para acceder a los casos de uso. En esta interpretación incluye la capa UI (si es necesario) y no el core de casos de uso, sino la interface de casos de uso. En mi caso prefiero bajar lo de casos de uso con la lógica de dominio al dominio. En esta capa de aplicación es necesario colocar el “¿Qué hace la aplicación?” o “¿Qué casos de uso tiene?”.
Domain: esta capa se encarga del “¿Cómo hacen los casos de uso para cumplir su función?”, es decir: el código de lógica, lógica compartida, de negocio o de dominio. Esto incluye los servicios de dominio y modelo de datos (agregados, entidades, value object, etc.).
Infrastructure: aquí va el código de acceso a recursos (acceso a base de datos, recursos, archivos, clientes api para servicios externos, consumo de colas de eventos específicos, etc.).
Ejemplo de 3 capas basado en DDD
Por ejemplo se puede estructurar un proyecto backend de la siguiente manera:
Ejemplo de una estructura de backend MERN NestJS en 3 capas
Patrón de puertos y adaptadores
Claro que con separar en capas no alcanza para tener un código limpio y lejos de ser una madeja de código en monolito. Necesitamos seguir un gran principio en el desarrollo de software: “aumentar cohesión y disminuir acoplamiento”; y eso lo podemos hacer aplicando el principio de inyección de dependencias (“Dependency inversion principle”) con el patrón de “puertos y adaptadores”, también conocida como arquitectura de “Ports and Adapters” o como parte de la Arquitectura Hexagonal.
La idea detrás de la inversión de dependencia es “depender de abstracciones, no depender de implementaciones”. Y para eso vamos a acoplar ‘capas’ por medio de ‘interfaces’. Una capasuperior usara una capa inferior solo por medio de interfaces que funcionan como puertos. Luego, la interfaces será implementadas por adaptadores concretos (implementaciones) de la capa inferior.
En resumen la distinción entre puerto y adaptador es la siguiente:
Puerto: Es la interfaz que deberán implementar las distintas variantes de nuestro código para abstraerse de la implementación concreta. En ella se ha de definir la firma de los métodos que existirán.
Adaptador: Es la implementación de la interfaz, en ella se generará el código específico para consumir una tecnología en concreto. Esta nunca se usará de forma directa desde otras capas, ya que su uso se realizará a través del tipo del puerto.
Ejemplo de puerto/adaptador en tres capas
De este modo, la capa que usa un puerto usará la implementación inyectada de algún modo, pero solo conoce la interfaz. Hay diferentes formas de hacer inyección de dependencias: inyección por argumento, inyección por constructor, inyección por anotaciones, etc.
Ejemplo con el patrón repositorio.
Ejemplo de inyección de dependencia con anotaciones NestJS (MERN stack) donde se inyecta en el dominio la implementación de infra. Se usa el patrón repositorio (código del ejemplo anterior).
La pauta del dominio como núcleo
Además, si nos guiamos por la propuesta de la Arquitectura Hexagonal que consiste en que el “dominio sea el núcleo de las capas y que este no se acople a nada externo”. Entonces será nuestro dominio el que contenga los puertos de entrada (incoming) y salida (outgoing). Es decir que toda acción o evento externo (i.e. como pedidos http) que llega a la aplicación por un puerto, es convertido, a través de un adaptador específico, a la tecnología del evento exterior, pasando por el dominio solo a través de sus puertos. Por ejemplo la GUI es un ejemplo de un adaptador que transforma las acciones de un usuario en la API de su puerto. La inversión de dependencia hace que la capa de aplicación y la capa de infraestructura conozcan a la capa de dominio, pero no a la inversa. Y en el caso de la capa de aplicación y la de infraestructura, es la de aplicación quién puede conocer a la de infraestructura y no a la inversa.
Diagrama de dominio como núcleo
Aplicación hexagonal
Una manera de interpretar e implementar esta arquitectura es considerar cada gran pieza de software (que será un proyecto), como una aplicación que empaqueta un conjunto de funcionalidades bajo algún concepto o dominio de problema.
En esta interpretación, la aplicación es el paquete completo, la celda hexagonal. Y esta aplicación es una hexagonal de tres capas, con la capa central como dominio núcleo. Esta aplicación puede ser una standalone desktop, mobile app, web app, una API o un microservicio.
Ejemplo de un API backend hexagonal
Frontend hexagonal
Inclusive, en aplicaciones cliente servidoras u orientadas a micro-servicios, un frontend puede ser desarrollado como una app hexagonal en sí misma, que depende de otras que forman el backend. Habitualmente no se implementa la arquitectura hexagonal de esta manera y se llega a tener frontends que son una verdadera madeja enredada de código. La propuesta aquí es aplicar arquitectura hexagonal también al frontend.
Ejemplo de una aplicación cliente-servidor
Un frontend puede seguir el patrón de tres capas, con la vista UI en la capa aplicación; la lógica del frontend, modelo de datos y dominio en la capa ‘core’ (Domain); y en en la capa de infraestructura el código de llamado a APIs, recursos, o servicios externos.
Ejemplo de estructura de un proyecto frontend en React (MERN stack)
Testing por capas
También tenemos que pensar en el testing. Sin ‘test’ no hay software de calidad. Un beneficio importante de esta arquitectura de software es que facilita la automatización de pruebas independientes por capas usando inyección de dependencias de Mocks y/o Stubs.
Ejemplo de full test por capas
Usar puertos y adaptadores nos ayuda a hacer testing limpio. Cuando se nos complica hacer inyección de dependencia es que ensuciamos el código. Por ejemplo inyectando módulos a un módulo que usa componentes por imports de implementaciones directas. O muchas veces no se hace buen test unitario por la dificultad de aislar el testing para hacer simulaciones.
Estructora de carpetas
Al implementar la arquitectura en un proyecto recomiendo que quede la distinción explícita en 3 directorios (uno por capa). Un ejemplo es como la siguiente:
Estructura de carpetas en un proyecto Back-end
Red de aplicaciones hexagonales
Entonces… ¿Cómo podemos desarrollar ecosistemas de aplicaciones distribuidas con arquitectura limpia? Lo podemos hacer con esta arquitectura hexagonal, distribuida, orientada a microservicios y microapps. Es decir que, en sistemas mayores o en el escalamiento, se pueden conformar sistemas distribuidos como una red de aplicaciones hexagonales interconectadas. Es decir que podemos desarrollar ecosistemas de aplicaciones interdependientes, aunque robustas, y conformadas por micro-apps (incluyendo micro-frontends de ser necesario) y micro-services hexagonales.
Red de equipos ágiles
En honor al principio de Conway, que dice que las estructuras del sistema desarrollado serán congruentes con las estructuras sociales de la organización que lo produce, es que tendremos un ecosistema de equipos acorde a esta arquitectura. En este sentido, tendríamos equipos encargados cada uno de una o varias Apps relacionadas bajo un mismo dominio de contexto. Estos equipos deberían poder desplegar software de forma independiente, en sus propios repositorios y entregar de forma evolutiva e incremental.
Vertical slicing
Y para entregar de forma evolutiva e incremental, los equipos pueden desarrollar desglosando entregables/soluciones en features con ‘vertical slicing’ que a su vez se pueden desglosar en historias de usuario. En un verticalslice pueden haber una o más historias de usuario y/o historias técnicas para completar una feature completa.
Ejemplo de ‘vertical slicing’ de una feature
Desarrollo evolutivo
Estos entregables/soluciones evolucionarían desde algún MVP a productos más complejos, adaptándose a las necesidades de los usuarios según la población foco de cada momento cronológico del ciclo de vida del producto/servicio.
Conclusión
Finalmente, concluyo que estos patrones de arquitectura, como otros semejantes, ofrecen una manera de aplicar buenas practicas de código para crear código funcional, mantenible, de fácil crecimiento y que satisfaga las necesidades de los usuarios. Lo que se recomienda es usar los principios de desarrollo de software que llevan a este tipo de arquitecturas, en busca de encontrar mejores formas de desarrollar software de calidad.
Aquí las claves fueron:
Principio de ‘Separation of Concerns’ (SoC) con patrón de ‘3-Tier Architecture’.
Principio de ‘Dependency Inversion’ con el patrón ‘Ports and Adapters’ y el patrón de diseño ‘Dependency Injection’.
El principio de ‘Testing’ con el patrón de diseño ‘Dependency Injection’ (de Mocks y Stubs).
Y por último, el clásico principio de “más cohesión y menos acoplamiento”.
Espero con este artículo haber podido transmitir esta idea de Hexa3L, que no es otra cosa que una manera de implementar la arquitectura hexagonal.
Si quieres conocer realmente el corazón del marco de trabajo Scrum, debes leer el paper de Hirotaka Takeuchi and Ikujiro Nonaka que le dio origen a principios de los 80. Aunque, si no lo has leído, aquí te comparto mi resumen.
En su estudio y paper “The New New Product Development Game”, Nonaka y Takeuchi compararon una nueva forma de trabajo en equipo, con el avance en formación de scrum de los jugadores de Rugby, a raíz de lo cual quedó acuñado el término 'Scrum' para referirse a ella.
Estos autores ofrecieron el enfoque de Scrum como alternativa al enfoque tradicional secuencial (cascada) o al de "carrera de relevos", para el desarrollo de productos en el vertiginoso mundo actual, con contextos de requisitos inestables, donde se necesita velocidad y flexibilidad. Ellos propusieron un enfoque holístico, compuesto por un núcleo de seis características:
Control por misión (Built-in Instability): la alta dirección crea un elemento de tensión en el equipo al darle gran libertad para llevar a cabo un proyecto de importancia estratégica para la empresa y al mismo tiempo establecer requisitos muy desafiantes. Es decir: dar gran libertad y objetivos muy exigentes. Dar libertad con exigencia. Algo que los autores llamaron 'Built-in Instability' y que prefiero, por simplicidad, llamar "control por misión".
Equipos autoorganizados: es un equipo que exhibe tres condiciones: autonomía, autotrascendencia y fertilización cruzada. En el día a día, la alta dirección rara vez interviene; el equipo es libre de establecer su propia dirección. En cierto modo, la alta dirección actúa como capitalista de riesgo. O como dijo un ejecutivo: “Abrimos nuestro bolso pero mantenemos la boca cerrada”.
Fases de desarrollo superpuestas: es la integración de diferentes profesionales de una cadena de valor para lograr objetivos comunes, en vez del trabajo aislado y en secuencia. Aquí se introduce la idea del rugby, las fases se superponen considerablemente, lo que permite que el grupo absorba la vibración o “ruido” generado a lo largo del proceso de desarrollo trabajando como bloque unido. Un equipo trata de recorrer la distancia como una unidad, pasándose el balón de un lado a otro, en equipo.
Control sutil: se busca seleccionar a las personas adecuadas, crear un entorno de trabajo abierto, alentar a los ingenieros a salir al campo y escuchar lo que los clientes y stakeholders tienen que decir, establecer un sistema de evaluación y recompensa basado en el desempeño del equipo, manejar las diferencias de ritmo a lo largo del proceso de desarrollo y tolerar y anticipar los errores. La gerencia establece suficientes puntos de control para evitar que la inestabilidad, la ambigüedad y la tensión se conviertan en caos; y al mismo tiempo, la gerencia evita el tipo de control rígido que perjudica la creatividad y la espontaneidad fomentando el ‘autocontrol’.
Aprendizaje múltiple (Multilearning): hay que dedicar tiempo al aprendizaje individual constante, fomentando la iniciativa y el aprendizaje práctico por parte de los empleados y ayudando a mantenerlos al día con los últimos avances. Además incluye el aprendizaje en otras áreas de la experticia de cada profesional.
Aprendizaje Organizacional: los autores proponen la 'transferencia organizacional del aprendizaje' que incluye el impulso para acumular conocimiento a través de niveles y funciones distintas en el ecosistema de la organización; y el impulso por parte de los miembros del equipo para transferir su aprendizaje a otros fuera del grupo. El conocimiento también se transmite en la organización al convertir las actividades del proyecto en una práctica estándar. Es decir que se busca en estos dos últimos puntos el aprendizaje multi-nivel, multi-funcional y transversal en la organización, algo que podemos llamar aprendizaje organizacional.
Si buscamos seguir estas claves en el desarrollo de software o en nuestra organización, nos estaremos acercando a este Scrum pragmático. El framework, en el fondo termina implementando estas ideas, aunque fue años más tarde cuando fue creado por Ken Schwaber y Jeff Sutherland, quienes le dan forma y lo popularizan, basados en la idea de estos autores, en sus propias experiencias y en los numerosos experimentos del incipiente framework hechos por Jeff. Pero esa es otra historia.
Nota: la traducción de las seis características no son textuales, sino que se ajustaron según el autor de este artículo tomando una licencia por didactismo, ya que algunas frases del Inglés generan algo de confusión en su interpretación.