Se trata de definir un proyecto entre las diferentes posibilidades que se planteen y organizar los hitos para el trabajo en el mismo, así como avanzar en lo posible en el interfaz y estructuras de datos de la clases iniciales que se vayan a implementar.
Lo esencial es entender bien el concepto de proyecto y cómo se organizan, según las pautas de trabajo ágil, el trabajo en el mismo de forma que cualquiera, incluso otra persona, pueda seguirlo. Por eso es esencial planificar, mediante hitos (que son productos mínimamente viables) que sean capaces de recoger las inquietudes del usuario, aportarle valor y a la vez maximizar los recursos del equipo de trabajo.
Para entregar este hito, el anterior tiene que haberse realizado ya que la entrega incluye tests para todas las características del hito anterior.
Una vez que en el hito 0 el MVP creado es simplemente la descripción de un problema que se va a resolver, en este hito el MVP será la planificación del proyecto a grandes rasgos, así como comenzar a especificar una serie de historias de usuario que describan qué es lo que diferentes roles (tales como usuario, administrador, otro…) van a necesitar del proyecto.
Supongamos que queremos resolver el proyecto de listas de la compra compartidas para una familia.
Este proyecto tendría una lógica de negocio relacionada con la predicción de qué compras se van a realizar cada día de la semana y del mes, y por supuesto una lógica cloud que realizaría informes masivos geolocalizados con los productos de la compra más habituales. La lógica de negocio es imprescindible en todo proyecto, y queremos dejarlo explícito aquí.
Las siguientes historias de usuario serían posibles, aunque no serían válidas:
En este caso, ni expresamos nada relacionado con la lógica de negocio ni expresamos ningún beneficio para ningún miembro de la familia. Esta, sin embargo, sería (más) correcta
Obsérvese que se ha convertido lo que se suponía que era el deseo del usuario en contexto, convirtiéndolo en algo que hay que hacer y que alimentará a la lógica de negocio, pero que habrá que resolver mediante un issue.
En este caso, tenemos (casi) los dos elementos fundamentales de la aplicación: un beneficio para el usuario (no tener que preguntarle a la gente y poder elaborarla automáticamente) y (algo) de lógica de negocio, un algoritmo que prediga lo que se ha gastado.
El casi viene porque la lógica de negocio está implícita, pero no es explícita. Podría resolverse el problema sin ninguna lógica de negocio, simplemente repitiendo la última.
La siguiente también sería inválida, por más o menos la misma razón.
No expresa ningún beneficio para el usuario, sino que el beneficio se deduciría de esta actividad. Pero sí encierra la lógica de negocio del mismo y por tanto será esencial para cualquier desarrollo posterior. Aunque rara vez será la primera HU, sí tendrá que estar en el primer producto mínimamente viable que se le entregue al cliente (precedido de una serie de productos mínimamente viables previos). Así que habrá que cambiarla para que efectivamente sea una HU
En general, hay que entender bien de qué se trata el problema y hacer un número de historias que nos lleven a una solución mínimamente viable del mismo, y que sea desplegable en la nube. Esas historias de usuario, además, deberán estar acompañadas de documentación (u otras historias) que definan claramente tanto los roles como cada una de las entidades que se mencionan. En particular, no se podrá avanzar con HUx hasta que el rol de “miembro de la familia” esté bien definido (y en particular si va a ser un usuario genérico o va a tener también algun tipo de objeto que lo represente en la aplicación), y las entidades producto y lista de la compra estén también bien definidas. En particular, en el caso “lista de la compra” sería conveniente crear un issue adicional:
En todas estas cosas es esencial tener siempre en mente el problema inicial que se ha planteado y por supuesto la lógica de negocio. Por ejemplo, en el caso de la lista de la compra lo que necesitábamos, por un lado, es una herramienta útil para una familia, pero por otro lado que se pueda analizar y extraer datos de ella. Por eso habría que considerar cosas adicionales como que, en mi caso, hay veces que se quedan cosas en la lista de la compra porque no hay existencias (o se te han olvidado), así que debería ser posible crear una lista de la compra a partir de la anterior. Eso implica, a su vez, una entidad (agregado) que sea capaz de almacenar un histórico de listas e la compra (lo que sería un issue, eso no es una HU). Y así sucesivamente. Como se explica un poco más adelante, las HUs no es algo que tenga que estar todo desde el principio. Generalmente se genera una única HU, que puede ser el objetivo final, y a partir de ahí van surgiendo otras HUs que definan claramente todo lo que se describe ahí, issues que pidan resolver el problema de la implementación, lo que a su vez dará lugar a otras HUs más adelante.
La planificación del resto del proyecto es la esencia de este hito, es decir, tras haber creado en el hito anterior una descripción general de la arquitectura y de las piezas del proyecto, en este tendréis que crear las historias de usuario en un issue y esos issues tendrán que estar, si no completos, al menos de una forma bastante completa en este hito. Como se ve, las historias de usuario son de alto nivel, y en general harán falta issues adicionales para que se llegue a un nivel en el que se pueda crear código y comprobar si ese código lleva a cabo la tarea propuesta.
Se recuerda que hay que seguir las recomendaciones presentadas en el el hito 0 sobre commits, issues y milestones.
Adicionalmente, el estudiante puede comenzar a programar estas clases. Como todavía no hemos llegado a un punto en el que se pueda testear el código, sólo se puede crear el “cascarón” de la clase, en el que debe de estar completa
Estos “cascarones” tendrán que ser sintácticamente correctos, y sobre todo estar ligados de la forma que se indicó en el hito 0 a las historias de usuario correspondientes y que se hayan comenzado a implementar en ellos.
Las historias de usuario son imprescindibles para definir, de forma precisa y exhaustiva, el funcionamiento de una aplicación. Estas historias de usuario tienen que definir
Las HUs van a guiar el desarrollo del código (la infraestructura-como-código en general requerirá solamente issues, aunque tendrán que estar en algún milestone) durante toda la asignatura. Es mejor no hacer un montón ahora que luego haya que reescribir, sino ir añadiendo poco a poco HUs según se vayan necesitando.
En general, no va a haber una correspondencia entre HU y clase o grupo de clases. Una historia de usuario puede implicar añadir un solo atributo a una clase o diseñar e implementar una jerarquía completa.
Si la historia de usuario es “una hechicera podrá crear un grimorio propio con encantamientos, y almacenar en él todos los encantamientos que lea en grimorios” puede implicar, por ejemplo, añadir un atributo (grimorio) y un método (almacenar encantamiento) (vía, posiblemente, un issue que aclare cómo se va acceder a esos encantamientos almacenados). En todo caso, será un sólo atributo de una clase y un método que trabaje con él.
Este tutorial de Atlassian (los creadores de Jira y BitBucket) explica qué son las historias de usuario, y su relación con las especificciones. En esta colección de consejos, además explica cómo se integran en una “épica”, que correspondería más o menos a los milestones con los que hemos estado trabajando nosotros. Menciona también los user journeys, que enlazan diferentes historias para crear una secuencia, aunque se pueden combinar “user journeys” e HUs en un mismo proyecto. En este otro artículo se explicita la relación entre “tema”, “épicas”, historias de usuario y tareas.
Generalmente, las HUs son historias de usuario, y eso implica que no van a especificar más que lo que, a alto nivel, se va a ver en la aplicación. De ellas se tendrán que sacar una serie de HUs. En realidad, los HUs y los issues relacionados con ellas tendrán la misma estructura. Una issue expresa un problema a resolver, no qué se va a hacer. Lo que se ha hecho para resolver ese problema y las decisiones que se han tomado se expresarán en el mensaje de commit, que hará siempre referencia al issue y HU de la que se obtenga.
Los issues tendrán la misma esructura que una HU, pero el rol en general será el de programador/a. Lo importante, en todo caso, es que el issue diga qué problema se va a resolver, y aporte información sobre las restricciones que hay. Un issue “crea esto” con un solo commit que lo cree será incorrecto. Un issue que diga
Hay que resolver el problema de acceso a los diferentes encantamientos
de forma segura y eficaz; si un usuario trata de acceder a un
encantamiento contenido en un libro prohibido, se producirá un error.
La solución (como explicamos más adelante) pasará por usar el sistema de tipos para, en tiempo de compilación o ejecución, dar acceso a ciertos encantamientos contenidos en ciertos libros sólo si eres del tipo adecuado. La jerarquía de clases incluirá un tipo “hechicero” genérico, y diferentes subclases cada una de las cuales tendrá privilegios crecientes; estos privilegios pueden estar asociados o no a atributos del objeto; y también habrá que tener en cuenta que tendrá que haber un “sanedrín” que permita tomar un objeto de una clase y crear un objeto de otra clase (pasar de diácono a archimandrita, por ejemplo). En todo caso, el issue lo que declara es el problema que hay que resolver, y se resolverá con un test donde se testeen todos los tipos de usuario con todos los tipos de encantamientos, y se produzca un error si no se tiene acceso; adicionalmente, se tendrá que comprobar también que no se puede cambiar de tipo. Como se explica más adelante, la forma más segura de hacer esto es usando el sistema de tipos del propio lenguaje que se haya elegido.
Las HUs no secuencian, ni dicen cómo se van a agrupar, pero lo más importante es que no hacen ningún “empaquetado” ni deciden qué se va a “pasar a producción”. En general, “pasar a producción” es algo que se va a enseñar al cliente; en esta asignatura el cliente es el profesor (y uno mismo, claro); eso quiere decir que lo que se “pase a producción” corresponderá, en general, a lo que se va a entregar en un hito, por ejemplo, en este.
Los hitos se tienen que organizar para que en cada hito se pase a producción algo, es decir, haya un producto mínimamente viable. La secuencia de hitos tendrá que, en cada caso, construir un hito a partir del siguiente si hay interdependencia (normalmente la habrá), o simplemente junto al siguiente para posteriormente integrarlos en un producto mínimamente viable.
Un hito es, por tanto, equivalente a un producto mínimamente viable, pero evidentemente hay que especificar cuál es ese producto mínimamente viable que se va a “pasar a producción”. En este caso se pide (y para crédito adicional) una entidad o entidades; ese será por tanto el MVP en este caso.
Pero el plan, que se deberá ir actualizando durante la asignatura, incluye éste y cuales van a ser los próximos hitos/MVP que se van a ir entregando, y una vez más, un MVP es un MVP, no “tres funciones de esta clase”. Es un algo que hace algo.
Hay muchas estrategias para llevar estos planes a cabo; pueden desarrollarse de forma horizontal (en el primer hito identifico todas las entidades que voy a usar y defino su API) o vertical (defino de forma estricta una sola entidad, que a continuación voy a seguir desarrollando en el segundo hito, donde además, voy a empezar a desarrollar una segunda entidad que necesita la primera).
Lo que tiene que quedar meridianamente claro es que los hitos marcan un punto de control. Dentro de un hito no se pueden usar los productos del mismo hito; hasta que no se termine un hito no se puede pasar al siguiente.
Pero esa organización de hitos es, en principio, ortogonal a las HUs. Normalmente las HUs hablan de usuarios finales, lo que, salvo que nuestro producto final sea un backend completo y lo definamos de esa forma, no vamos a alcanzar en esta asignatura. Así que los hitos no van a incluir en realidad HUs (salvo excepciones), sino tareas dentro de cada HU, que, para aclarar, deberían ser issues independientes dentro de la HU. Las HU se pueden mantener fuera de los hitos, o bien irse moviendo de un hito al siguiente cuando las tareas que se vayan a realizar continúen en el hito siguiente.
En todo caso, los hitos deben ser secuenciales, tener siempre un MVP sobre el cual se construya el siguiente hito, y este MVP debe estar descrito explícitamente. En este otro artículo hace una serie de consejos prácticos para integrar épicas con hitos.
Todas las HUs, y los issues que se deducen de ellos, deben tener un test (que se empezarán a escribir en el hito siguiente) para comprobar si se han llevado a cabo efectivamente. Sin embargo, el código más correcto es el que no se escribe, y todos los lenguajes tienen un sistema de tipos que permite, en tiempo de compilación y/o de ejecución (dependiendo del tipo de lenguaje), comprobar si los argumentos que se están dando para una función son los correctos. En este hito hay, precisamente, que usar esas facilidades que da el lenguaje para tratar de crear esas comprobaciones sin necesidad de recurrir a un test, que crea un overhead sobre el código.
Es decir, supongamos que una HU dice que un tipo de usuario “archimandrita” puede llamar a una función “impetración” de un “grimorio”. Lo adecuado sería o bien definir un método
class Archimandrita:
def impetra( grimorio: Grimorio ):
o bien
def impetra_por( archi: Archimandrita)
dentro de grimorio. Definir un “usuario” genérico con un campo que indique si es diácono, postulante o archimandrita implicaría que hay, primero, que hacer un test (en el hito siguiente) que comprueba que no se pueda llamar a esa función si no se tiene ese rol y por supuesto comprobar con un “if” en cada llamada a la función si el rol que se pasa es el correcto.
Estas restricciones, por supuesto, tienen que estar en la HU correspondiente, pero en este hito se pueden incluir, ya que corresponden a definición de tipos y de funciones y conviene que se usen.
Lo más importante, en todo caso, es tener bien en cuenta que las clases deben poder ser capaces de hacer lo que se pida en la HUs o HU que se esté usando en este momento.
Como la base de código tiene siempre que avanzar con las HUs, siempre tiene que haber una relación, directa si es posible, con el mismo. Cada fragmento de código tiene que estar relacionado con una HU, o bien con una issue que a su vez diga claramente que es parte de una HU o una tarea de una HU.
Las HUs, por otro lado, tienen que expresar también qué ocurre si el código entra en un estado erróneo o detecta un error; eso se tiene que convertir en excepciones específicas diseñadas para capturar los posibles errores; y esas excepciones tienen que tener también tipos, y cierta especificad en cómo exprese o almacene los errores, porque eso también se tendrá que testear (en el hito siguiente).
Se pueden consultar los siguientes temas del curso 0:
De la forma habitual, editando el fichero con un enlace al repo y un número de versión que se incrementará con cada hito y también con cada envío adicional. Como este es el hito 1, la versión major de la entrega corresponderá a este número.
En cada hito, el estado del README no debe de incluir “capas” donde se incluyan todos los hitos anteriores, sino que tiene que estar adaptado a la realidad de cada hito, es decir, ir directamente al grano. Lo que se haya incluido en hitos anteriores y que ya no sea relevante se puede enlazar donde corresponda, tras moverse (preferiblemente) a un fichero específico.
En concreto, se enviarán y testearán los siguientes aspectos en este hito:
HU
o US
(como en user stories
)
en la descripción y la etiqueta user-stories
, en número suficiente
para poder trabajar en este hito y algunos de los siguientes.cc.yaml
, y, en la clave entidad
, 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 ejemploentidad: src/Recordatorio.js
Tras la primera corrección, para reenviar hay que seguir las siguientes instrucciones.
Se recuerda al estudiante que la lógica de negocio adecuada es impresincible para poder desarrollar en resto del proyecto correctamente. Si no se ha superado esa rúbrica en el hito anterior, tendrá que reescribirse en este, porque la primera y segunda rúbrica dependerán de que se haya hecho correctamente. En concreto, si la rúbrica referida a aplicación en la nube/lógica de negocio se ha considerado inadecuada en el hito 0 y no se ha corregido para la entrega de este hito, las rúbricas 1 y 2, como claramente indica, no se podrán superar.
Si el repositorio no existe, tiene algún error, no se ha hecho pull request correctamente o hay alguna evidencia de plagio, la práctica estará suspensa.
Este hito contribuirá 0.75 puntos a la nota final.