Se trata de entender el paso de historias de usuario al diseño inicial de una clase o clases en nuestro programa.
Se tendrá que haber avanzado en el objetivo 1 antes de poder avanzar a este.
Tras elegir el lenguaje de programación que se va a usar, se creará un módulo o módulos que compilen, aunque no pueden tener todavía ninguna funcionalidad. Estos módulos tendrán que usar las estructuras de datos más adecuadas para resolver el problema, así como el interfaz de la clase o de la estructura de datos que mejor permita implementar las historias de usuario existentes, evidentemente avanzando las historias de usuario que se hayan creado en el primer hito en la secuencia.
El convertir los deseos de los clientes en una realidad informática implica una serie de decisiones técnicas, y en principio no tiene nada de trivial. En entornos de desarrollo ágil hay que tener en cuenta no sólo los requisitos (historias de usuario) que se conozcan en ese momento, sino también posibles cambios que pueda haber en el futuro.
En desarrollo ágil, también, se va a separar lo más posible la lógica de negocio (lo que efectivamente hace la aplicación) de su implementación completa (cómo va a aparecer al público, cómo va interaccionar con el sistema). El hacerlo así permite asegurarse de que esta lógica de negocio cumpla todos los requisitos (que están expresados en historias de usuario), y que se pueda adaptar a diferentes entornos según evolucione la aplicación.
En todo caso, hay que pasar de una historia de usuario al diseño general de algunas de las clases (o módulos) que van a intervenir en una aplicación. La metodología más aceptada se denomina Domain Driven Design, y consiste en identificar las entidades (clases que van a incluir lógica de negocio, y van a ser capaces de gestionar otras clases, así como almacenamiento y otros objetos) y objetos valor (objetos inmutables cuyo ciclo de vida va a estar controlado por objetos de otras clases).
Diferentes conceptos a tener en cuenta:
- Interfaz vs clase. Un interfaz tiene sólo el API. Algunos lenguajes, como Java o TypeScript, permiten crear interfaces que se tendrán que implementar en una clase concreta, sin tener ninguna lógica de negocio.
- Mutabilidad frente a inmutabilidad: una clase inmutable no permitirá cambiar de valor tras su creación. A veces se denominan "congeladas" (frozen) o dataclasses (ya que, esencialmente, son datos, o sea, objetos que contienen sólo un valor).
- En esta mutabilidad se tendrá que tener en cuenta el uso de variables de instancia privadas, así como sólo los getters (ningún setter). En general, conviene usar lenguajes que tengan en cuenta este tipo de distinción.
- Composición frente a herencia. La programación dirigida a objetos es muy rica, y mientras que algunos lenguajes permiten sólo herencia, otros permiten composición de roles o mixins (como Ruby o Raku).
- Tiempo de ejecución frente a tiempo de compilación: Es mejor trabajar con un lenguaje que permita comprobaciones de tipos en tiempo de compilación, sobre todo en funciones; eso ahorrará un montón de trabajo más adelante.
Los factores anteriores son comunes a casi todas las aplicaciones, y llevarían normalmente a la elección de un lenguaje que tenga comprobación de tipos en tiempo de ejecución, o tipado "fuerte" o tipado gradual. Este objetivo se cumplirá evidentemente cuando se elija un lenguaje, porque sin él no se puede crear los primeros interfaces o clases sin código (sólo declaración de métodos y funciones).
Finalmente, en el momento que vaya a haber algo de código se tiene que comenzar a seguir las mejores prácticas del lenguaje correspondiente, que incluirán una disposición de directorios determinada, forma de llamar los ficheros y las clases dentro de los ficheros, y así sucesivamente. Conviene antes de crear el fichero informarse sobre el tema.
El hecho de que se escriba interfaz de la clase sin código corresponde a dos conceptos: primero, en test driven development (TDD) se escriben primero los tests y a continuación el mínimo código que haga que pasen los tests. Por otro lado, deben evitarse tests innecesarios con un diseño que incluya, desde esa misma etapa, los presupuestos incluidos en las historias de usuario.
Este objetivo construye sobre el anterior. Se tienen que empezar a implementar las historias de usuario y avanzar hasta el primer hito, que podría ser perfectamente el resultado de este objetivo (ya que es una clase diseñada con todos los elementos que permitan implementarse luego). Así que
- Consultar el milestone e historias de usuarios asignadas, ordenadas (si lo ha hecho el autor) en un orden lógico.
- Tratar de crear issues "como programador" asignados a esas historias de usuario, también organizadas de forma lógica.
- Usar esas issues como una guía para diseñar las clases (o módulos, entidades en general). En este proceso se tendrá en cuenta la metodología de diseño dirigido por dominio, decidiendo qué será un objeto valor, qué una entidad que los incluya, qué los agregados.
Implícitamente, en esta clase se seleccionará el lenguaje de programación.
Se pueden consultar los siguientes temas del curso 0:
- Diseño dirigido por dominio.
- Cómo implementar clases abstractas o definir los interfaces de clase antes de implementar.
Los recursos aportados por los estudiantes de la asignatura están en este fichero.
Todo el material para este objetivo se tiene que desarrollar, como siempre, en
una rama. Desde esta rama se hará un pull request a la rama principal del
repositorio propio del estudiante. Importante: el título de este pull
request *tiene que incluir la cadena [IV-21-22]
para que pueda filtrar
fácilmente los mensajes recibidos. Cuando se hagan mejoras en el PR, el
estudiante deberá pedir explícitamente revisiones adicionales con un comentario
en el mismo que diga "Listo para revisión".
Como en este hito el trabajo se hace sobre un repositorio ajeno, esa persona tendrá que revisar el trabajo que se ha enviado en un PR y aceptar (no fusionar). Cuando se haga, se etiquetará a JJ en un comentario donde se diga que está listo para revisión.
A este fichero se subirá (mediante un PR desde una rama) el nombre del proyecto, el autor y un enlace al pull request creado en el repositorio.
A partir de este hito, habrá que especificar ficheros y otros
parámetros de configuración para test en un fichero iv.yaml
que
estará en el directorio principal, escrito en formato
YAML. Por ejemplo, este
entidad: camino/a/loquesea.raku
Las claves, tales como en este caso entidad
, tendrán un valor que será lo
que se examine y se usará en un test para ver si se ha llevado a cabo
correctamente alguno de los elementos del hito requeridos. El formato YAML se
usa extensivamente en DevOps, y se puede consultar sobre él, por ejemplo, en la
Wikipedia. Se puede editar a mano (usando
el modo correspondiente del editor o IDE) o, por supuesto, generarse usando
alguna biblioteca o utilidad de línea de órdenes.
Como mínimo, y para pasar los tests, esta entrega incluirá, además de lo solicitado en las entregas anteriores:
- Los cambios en los ficheros de código que se haya creado corresponderán siempre, de forma directa (enlazando) o indirecta (a través de un issue que sea una tarea específica dentro de una historia de usuario) a una historia de usuario, y así tendrá que reflejarse en los mensajes de commit.
- El fichero
iv.yaml
, y, en la claveentidad
, el fichero donde se haya programado la entidad en forma de una clase, módulo o paquete que es el objeto de este hito, con el camino correcto, por ejemplo
lenguaje: node.js
entidad: src/Recordatorio.js
- Se tendrá que justificar mínimamente el lenguaje elegido, de acuerdo con los requisitos vistos aquí.
- No es necesario que los ficheros de clase tengan código, pero tendrá que hacerse un mínimo esfuerfo por que se ajusten, en los nombres y los tipos, a las historias de usuario.
Antes de proponer el material de este objetivo para revisión, hazte las siguientes preguntas
- ¿He seguido las mejores prácticas en nombre de las clases y ficheros y disposición de los mismos?
- ¿Se ha documentado qué análisis se ha hecho sobre el dominio para decir lo que se ha creado?
- ¿Se ha documentado por qué se ha elegido que lo creado sea un objeto valor, una entidad o un agregado?
- ¿He propuesto un producto mínimamente viable, que en general será un solo objeto valor que no dependa de ningún otro (y que sea la base de muchos otros)?.
- ¿Los issues representan un problema, y no una tarea?
- ¿Todos los mensajes de commit explican el cambio, y no se limitan a repetir el nombre del fichero que se ha cambiado?
- ¿Los mensajes de commit siguen el el formato estándar y las buenas prácticas.
- ¿Se ha hecho una revisión real del código para comprobar que todos los atributos y funciones creadas están respaldadas por una HU?
- ¿Todos los issues creados están asignados a una HU?
- ¿Todos los cambios en el código están asignados a un issue?
- Los issues sobre los que estoy trabajando, ¿han sido asignados al primer milestone?
- ¿Se ha asignado al mismo milestone el PR que se ha hecho?
- ¿Son los milestones sobre los que estoy trabajando productos mínimamente viables? ¿O tengo que solicitar al product manager que cree milestones adicionales o precise de qué producto se trata?
Se habrá alcanzado este objetivo si pasa los tests automáticos, y:
- Se ha organizado correctamente en el repositorio según las mejores prácticas del lenguaje de programación elegido.
- Se han creado una o varias entidades/objetos valor, en el lenguaje de programación elegido, que avancen hacia la implementación de las historias de usuario y el producto mínimamente viable del hito correspondiente.
- Los issues están correctamente encuadrados dentro de una HU y del primer hito, que es el que se está desarrollando ahora.
En todo caso, y como en todos los objetivos, se tendrá que esperar a que el profesor apruebe el PR en el repositorio del proyecto para considerarlo alcanzado.
El alcanzar este objetivo avanzará, en principio, 15% del apartado correspondiente de la asignatura.
Si has terminado, comienza con el siguiente.