Describe a grandes rasgos la arquitectura (división de módulos, flujos de control, despliegue de nodos, tecnologías usadas…). Utiliza la notación descrita en clase (notación UML donde consideres oportuno).
Existen un backend y un frontend comunicados por paso de mensajes a través de DBUS.
El frontend se encarga de la presentación y utiliza GTK y GLADE. En nuestro proyecto implementamos una interfaz gráfica y otra modo texto.
El backend implementa la funcionalidad principal (excluyendo la interfaz de usuario) y agrupa tres grandes módulos: el Watcher, que vigila cambios en los archivos mediante Inotify y planifica los backups en función de condiciones externas (batería, uso de CPU); SnapshotManager que, estando implementado mediante una factoría abstracta, permite varios sistemas de backups, entre ellos uno basado en diferencias binarias que utiliza XDelta3 y un tercer módulo de herramientas que incluye: DatabaseWrapper, un patrón adapter para la base de datos para esconder SQLite; HDLogger, un sistema de control de logs y ConfigFileManager, un sistema de acceso y modificación a la configuración.
Estima el número de horas que ha requerido el proyecto incluyendo el esfuerzo que le has dedicado.
Podemos estimar que hemos dedicado entre 2 y 4 horas por persona cada día, durante 5-6 días a la semana a lo largo de los 8 meses de curso (4 semanas/mes).
3*5.5*4*8=528 horas/persona.
Desde el principio de curso hemos sido 11 personas y al falta de 2 meses y medio hemos tenido una incorporacion a nuestra plantilla:
11*528+2.5/8*528=5973 horas totales dedicadas.
Estima cuánto tiempo se dedicó a la formación en las técnicas o tecnologías utilizadas.
El equipo de trabajo original dedicó los meses de Octubre y Noviembre (2 meses) a conocer las tecnologías relacionadas y se produjo un periodo de entrenamiento de un par de días para enseñar a un nuevo miembro del equipo la arquitectura de la aplicación. Además, se produjo una investigación paralela al desarrollo durante los meses de Diciembre y Enero.
Describe las tareas básicas que ha requerido el proyecto, cómo se han distribuido en el tiempo y qué miembros de tu equipo han participado en cada una.1
En la fase inicial, todos los miembros del equipo colaboraron en la elaboración de los requisitos funcionales y no funcionales (a través de historias y casos de uso) y el diseño base de la aplicación. En cuanto esto se tuvo claro, y prácticamente estable, se divide el equipo asignando al personal en los distintos módulos basándose en preferencias (para que en la medida de lo posible disfrutemos de nuestra responsabilidad), conocimientos (los que más experimentados son los responsables de un grupo, y un grupo de programadores se mantiene a su cargo) y, por supuesto, según necesidades (en principio, GUI tenía mucha porque en Diciembre había que entregar algo que representativo al cliente). Los grupos fueron variando según las necesidades en las siguientes iteraciones, hasta llegar a la última en la que todos nos dedicamos a calidad (unos probando y documentando, otros arreglando los bugs).
Octubre y Noviembre
Durante los meses de Octubre y Noviembre se llevó a cabo la investigación inicial.
Diciembre
En Diciembre comenzaron los procesos de desarrollo supeditados a la gestión del proyecto.
Enero y Febrero
En Enero y Febrero se comenzó la integración con DBUS.
Marzo
Marzo fue muy parecido pero tuvo que ser necesaria una redistribución del personal.
Abril
Durante Abril se llevó a cabo la mayor parte del bugfixing.
Mayo
En Mayo sometimos al proyecto a una fase intensiva de revisión de calidad.2
Integración
De forma intercalada, al término de cada iteración suspendíamos el procedimiento de gestión de proyectos para priorizar el de integración.
Explica como habéis organizado el proceso de implementación, hasta que punto habéis utilizado como referencia el diseño, cómo habéis repartido el trabajo y cómo habéis integrado los resultados. Discute qué parte del código habéis podido reutilizar de lo que ya había hecho, y cómo ha influido eso en el diseño, en la implementación y la integración.
Organización de proceso de implementación horriblemente resumido
La implementación se ha llevado a cabo mediante iteraciones de un mes de duración(menos aquella fatídica vez que hubo que entregar antes de semana santa). En cada iteración se dedicaban las tres primeras partes a programar y probar(haciendo hincapié la última de estas tres semanas en las pruebas) y empleando la última semana para integrar y depurar de cara a la entrega.
Importancia del diseño
El fundamento del diseño original se ha respetado durante todo el año y todas las pequeñas modificaciones se realizaron los primeros meses de curso. Durante el desarrollo surgieron situaciones en las que las soluciones más evidentes( y en algunos casos las más rápidas) sugerían forzar cambios en la arquitectura, o "violar" algunos conceptos básicos de ésta(por ejemplo saltarse los mecanismos de comunicación entre procesos y hacerlo de forma directa). Ninguno de estos cambios se llevó a cabo y se buscaron soluciones alternativas que encajaran en el diseño.
toda esta parrafada de arriba se puede resumir en que el diseño ha sido nuestra referencia durante el desarrollo hasta el punto de que se puede cambiar todo, menos el diseño, aunque sea doloroso y vil
Reparto del trabajo
Desde el comienzo, 12 monos fue dividido en minúsculos pequeños grupos, cada uno de ellos con una labor muy concreta. La primera división dio lugar a grupos encargados de GUI(encargados de la interfaz gráfica), SnapshotManager(encargados de la magia en general…hacer backups y gestionarlas), Watcher(monitorización de archivos, decidir qué se guarda y cuándo) y DB(responsable de las bases de datos que maneja HDlorean). DB desapareció a mediados de ¿abril? ya que se finalizó su desarrollo y no era preciso mantener un equipo para arreglos esporádicos. En febrero-marzo se agregó el grupo Console, encargado de realizar otra interfaz de usuario, esta a través de terminal.
Las tareas a realizar se decidieron en las reuniones mensuales. A cada miembro de cada grupo se le asignaba trabajo(generalmente tareas concretas y completas) procurando que a nadie le faltara trabajo
Integración
El proceso de integración se llevaba a cabo la semana de la entrega suena mal, pero es lo que hay.
Para la primera iteración, cada grupo disponía de un repositorio que contenía exclusivamente su trabajo. Esto dio bastantes dolores de cabeza a la hora de integrar, de modo que se cambió la forma de proceder. Pasamos a tener un repositorio "central" de integración, desde el que se sacaban ramas para los equipos de trabajo para desarrollar características concretas, que al compartir historia con el central integraban fácilmente. Además, de ese central se extraían baselines a otro de pruebas para estabilizar el código y arreglar bugs sin que hubiera problemas por añadir código nuevo.
El proceso de integración consiste en mezclar todos esos branches en uno (que ha pasado de ser testing a unstable, perdiendo al final la rama de estabilizar por minimizar el tiempo usado) incorporando toda la nueva base de código con los últimos cambios de cada grupo. Este proceso no termina aquí, ya que divergencias entre los diversos branches en zonas comunes del código suelen ocasionar que la primera versión "integrada" no funcione, así como los mergeos sin suficiente cuidado. Existe (o existió) la figura del integrador, cuya misión es preparar esa primera versión, para después dirigir la segunda etapa que dará como resultado la versión integrada final. Una vez que se obtiene esta versión se tagea (etiqueta) y se establece como baseline para la siguiente iteración, partiendo los nuevos desarrollos desde ahí. Además, existe un branch adicional (trunk) al que solo van a parar versiones entregadas.
Para última iteración este proceso cambió radicalmente ya que se decidió no implementar nuevas features y dedicar esfuerzos a testear y corregir posibles fallos en la aplicación. La forma en la que se lleva a cabo este desarrollo no precisa que cada grupo trabaje en un repositorio separado, por lo que los arreglos se implementaron directamente sobre unstable por eficiencia.
código reutilizado
esta sección si que se acaba rapido. Reutilizamos casi por completo el primer prototipo de GUI, así como sus archivos de interfaz. Además la compresión binaria no la hemos implementado nosotros, sino que aprovechamos módulos existentes (xdelta3); idéntico para las bases de datos (sqlite) o wrappers python de funcionalidad del sistema (pyinotify).
Describe la relación entre el proceso de trabajo real que habéis seguido y el modelo de proceso que se propuso en clase para este trabajo.
Nos hemos ceñido al modelo visto en clase…iteraciones mensuales de implementación, revisión de planes, etc, si bien hemos tenido que reducir algunas partes del mismo (testing en concreto, y revisión por pares) por falta de personal. (aquí contar un poco de lo que se cuenta en la anterior pregunta, con esto no llenas una cara :P)
Da detalles sobre las dificultades que hayáis encontrado a la hora de seguir el modelo de proceso original
Lo más doloroso han sido las pruebas o entregas. No contar con el software necesario en el laboratorio dio lugar a una solución bastante imaginativa pero alejada de los supuestos iniciales(el software tiene que correr en los ordenadores del laboratorio). Cuadrar los horarios para establecer las reuniones no ha sido fácil y en el segundo cuatrimestre optamos por realizarlas en horas de laboratorio(viendo lo poco que rendían si las dedicábamos a programar). Además, hacia el final hemos encontrado problemas de falta de liderazgo al estar todo el mundo muy ocupado con otras asignaturas, que han llevado a bastante descordinación.
(eze: discrepo ampliamente. Lo más doloroso *no* han sido las pruebas, ya que eso lo resolvimos en la primera entrega y no ha dado más por culo más que a Adri -por no tener su ordena y tener que andar trayéndolo-, y además nos simplificó propagar rápidamente cambios de última hora, ya que solo había que hacerlos en *un* sitio via ssh, a diferencia de si hubiéramos tenido que pullear desde todas las máquinas para cualquier chorradita.
(jorge: es que el dolor es subjetivo xD. Lo doloroso no eran las entregas en si, sino las integrafest que le tocaban a adri, y que como esbirro número uno me papeé en primera fila. Aquí también se puede hablar del abandono que hicimos algunos de la documentación, es una dificultad que nos encontramos al carecer de tiempo optamos por empujar el código y dejar los papelorios abandonados, aunque…¿realmente podemos hablar de dificultades "genéricas"? Yo creo que más bien hemos tenido pequeños problemas, como lo de no tener el soft en los labos, la incomunicación que ha habido en determinados momentos del curso, la dispersión del último mes y medio, etc.)
Para mí lo más doloroso ha sido la falta de personal, y lo ocupados que estábamos todos. Por una parte por el tema de las reuniones (aunque cuando quedábamos no cundían demasiado, pero supongo que eso es consustancial a toda reunión de más de 3 ó 4, y es el precio que hemos pagado por la jerarquía horizontal - que por otra parte debería conllevarnos beneficios a todos a la hora del examen), pero sobre todo porque todas las carencias que hemos tenido - falta de testing; picos de trabajo para algunos, sea por exceso o por defecto; falta de features en el baseline final - han sido por falta de gente o de horas para poder implementarlo. Y es que, echando cuentas y al margen de otras asignaturas, como poco el 30% del grupo teníamos laburos aparte de la facultad - Adri, Salva, Robs y el que suscribe.
Explica qué otras ideas sobre modelos de proceso podían haber servido para mejorar los resultados del grupo.
(eze: hmmm cabe preguntarse si con XP hubiéramos mejorado y reducido bugs. El problema del XP es que no hay diseño al ppio, sino que se refactoriza. Suponiendo (que no lo sé) que pydev hubiera refactorizado a nivel de todo el proyecto, y no solo a nivel de archivo -oye, con java puede- el desarrollo podría haber sido bastante rápido, a coste de código cromulento y de no separar las bases de datos más que hacia el final. No sé, para mí es un modelo de desarrollo que se me hace muy raruno, pero la verdad IGr lo hemos hecho un tanto así, aunque nos daban parte de la estructura hecha.
La ventaja, por otra parte, es que hubiéramos tenido tests desde el día 0, que hubiéramos desaprovechado muucho menos el personal repartiendo bien las parejas y rotándolas, y que yo no hubiera perdido tiempo documentando - claro que habria que ver qué piensa Gervás de eso.
No sé muy bien qué puede estar preguntando si no es eso…)
—> Jorge WIP
Resume en pocas líneas cómo ha funcionado la planificación en vuestro grupo: cómo se ha decidido qué se hacía en cada iteración, cómo se han asignado las fechas y personas a cada tarea, cómo se ha informado a la gente de lo que se había planificado, cómo se ha comprobado si el proyecto avanzaba según lo planificado, qué desviaciones ha habido, qué imprevistos han surgido, qué se ha hecho para intentar resolver esas situaciones…
En nuestro grupo la planificación se hacía entre todos. Hemos intentado aprovechar los tiempos en que la mayoría del grupo podía reunirse para planificar las iteraciones, de esta manera se reducía la probabilidad de que los desarrolladores no estuviesen de acuerdo con el trabajo asignado, y se asegura que cada uno ha comprendido qué tarea debe acometer; de todos modos la planificación se colgaba en el wiki y se enviaba un correo electrónico, por si algún miembro del grupo no hubiera podido asistir a la reunión.
Lo que hacíamos en cada iteración venía en principio determinado por el modelo de proceso de espiral, aunque a partir de la primera beta funcional se acabó pareciendo más a un proceso de refinamiento iterativo, ya que obtenido el primer baseline las iteraciones consistían principalmente en reparar los bugs e ir añadiendo ciertas funcionalidades. Las fechas y las personas se asignaban a las tareas dependiendo de la carga de trabajo que se estimaba que la tarea iba a suponer.
El seguimiento de la planificación se realizaba a la vez que la siguiente planificación, así como un poco informalmente siguiendo las estimaciones temporales concretas para tener algo más de información. De esta manera, se intentaba solventar los errores cometidos en la planificación anterior y no cometerlos en la siguiente, ya fueran de estimación, de reparto de personal para las tareas…
Una desviación de la planificación ideal e inicial surgió al detectar en el módulo de snapshot-manager, que el sistema que habíamos elegido para hacer los backups no nos servía. Tuvimos que poner en marcha el plan de contingencia, que consistía en hacernos nosotros mismos un módulo que gestionase los backups. Esto nos supuso modificar la configuración de personal, ya que este módulo llevaría mucha lógica y necesitaría más recursos, así como consumir el tiempo extra que teníamos reservado para testing intensivo y contingencias varias.
Explica las decisiones de diseño más significativas que habéis tomado, y cómo han determinado el diseño final.
(eze sugiere: python y prototipado rapidísimo con glade, sqlite en lugar de mysql para hacerlo ligero, correr un demonio por usuario para minimizar riesgos de seguridad y problemas de diseño, arquitectura cliente / servidor obligada por usar un demonio, separar journal y history para lograr planificar y conseguir "transacciones").
(Fede pasando del Eze…)
Las decisiones de diseño más significativas fueron la separación del interfaz gráfico y el demonio en procesos independientes, y la separación en módulos diferentes del sistema de gestión backups (snapshot-manager) respecto del módulo watcher que es quien detecta los cambios en el disco duro y planifica los backups. Esto se ha mantenido así hasta el final, y creemos que ha sido una decisión acertada, pues ha permitido que los diferentes módulos puedan avanzar sin verse apenas afectados por los retrasos que otros módulos hubiesen tenido. (yo juntaría aquí lo de las bases de datos).
Relacionado con lo anterior, pero no por ello menos significativa ha sido la decisión de utilizar arquitectura cliente-servidor con el interfaz gráfico y el demonio, que permite tener varios interfaces gráficos independientes funcionando con un único demonio como servidor, además de minimizar los riesgos de seguridad y evitar problemas de diseño haciendo a cada uno totalmente independientes. (ya, fede, pero insisto que esta decisión de diseño te viene casi casi impuesta por tener un programa corriendo de fondo, así que no es una *decisión* sino que te viene dado por los requisitos de la aplicación - que haga backups constantemente. Yo no la contaría).
Otra cuestión de diseño importante ha sido dividir las bases de datos de los backups que ya están hechos de los que aún no, de manera que éstos últimos también se almacenan de forma "permanente" en una base de datos "Journal" hasta que se completa el backup, consiguiendo que aunque se cerrase el sistema en un mal momento, las peticiones de backups son persistentes y se ejecutarán cuando se vuelva a iniciar, y no afecta en absoluto a la integridad de la base de datos de backups finalizados.
Por último, nos queda comentar la importancia de la interfaz factoría de wrappers de almacenamiento y algoritmos de compresión que ofrece el módulo snapshot-manager, de manera que permite que funcionen bajo la misma interfaz (y en el mismo sistema) diferentes formas de almacenamiento, de las cuales nos dio tiempo a terminar una y empezar otra, y que permite que la lógica de compresión de los datos, el sistema de ficheros y el soporte de almacenamiento usado sea independiente de todo lo demás, (eze) simplificando la implementación y el testeo independiente de estas funcionalidades críticas.
Valora este diseño aplicando los criterios teóricos que se discutieron en clase(cohesión, acoplamiento, reusabilidad, facilidad de comprensión…).
(eze: Cohesión? weno, lo hemos hecho pocos… acoplamiento? Backend y gui separadísimos, independencia de todas las tecnologias mediante wrappers. Reusabilidad? sí, de esos wrappers. Facilidad de comprensión no sé porque no lo he leído, pero el gui era más o menos legible. Quizá tienen demasiadas funciones los proxys? no lo sé; por una parte quieres que el backend haga todo, pero por otra quieres dar un api bueno, y eso implica ortogonalidad, una única forma de hacer las cosas, y todo eso… no sé si cumplimos ahí. De acuerdo con lo de scheduler though; ahí pega un Strategy a saco, pero no ha dado tiempo).
Creo que este diseño tiene un alto nivel de cohesión y bastante bajo nivel de acoplamiento, gracias a la arquitectura cliente-servidor. Sobre todo ciertos módulos, como el de snapshot-manager aportan en cuanto a cohesión una funcionalidad reducida, condensada y explícita, también sucede así con los proxies del frontend y el backend (que cumplen un cometido muy claro y transparente), y con watcher que tiene la funcionalidad explícita de detectar los cambios en el disco duro y avisar sobre ellos, o cronhandler que es quien maneja los backups ordenados de forma temporizada. El punto que quizá tiene menos cohesión puede ser scheduler, por el hecho de tener una funcionalidad tan abierta como "ser quien decide qué se hace en cada momento", lo que implica que recibe llamadas desde los proxies, desde watcher y cronhandler y las canaliza en el orden debido haciendo llamadas a snapshot-manager. Se podría decir que todos nuestros módulos tienen cohesión funcional, que es la mejor cohesión que puede haber.
En cuanto al acoplamiento, todos los módulos tienen acoplamiento de datos, es decir, que los datos provienentes de un módulo y que necesita otro, siempre son pasados por parámetros en funciones. El único caso de soportes compartidos, si es que se puede considerar así, es la base de datos de Journal, en la cual escriben tanto Scheduler como Snapshot-manager, pues es Sheduler quien prepara los datos del backup, en esta base de datos, y es el propio Snapshot-manager quien los marca como backups terminados.
En cuanto a reusabilidad y a facilidad de comprensión, puesto que existen wrappers y proxies en la mayoría de módulos, el diseño es bastante reusable a ese nivel, en cuanto a facilidad de comprensión, gracias a la limpieza que tiene el código en Python, el código es bastante comprensible a pesar de lo turbias que pueden llegar a ser algunas funcionalidades.
Si has llegado a la conclusión de que el diseño utilizado es mejorable, explica por qué y dí brevemente cómo lo mejorarías.
(eze: explicitar la lógica de decisiones en watcher, para que sea el auténtico façade. Separar el scheduler de esa lógica con Strategy. Mejorar el diseño del proxy, parece que es demasiado "grande", con demasiadas cosas y pudiera ser más ortogonal. Proporcionar implementaciones para los módulos que hereden de istoragewrapper (convertir el interfaz en clase abstracta, y así p.e. das facilidades si necesitan usar una bbdd). Centralizar en un único punto la gestión de threads para que sea más sencillo el diseño de todos los demás módulos. Pero claro, eso último es mi opinión :P).
(Fede: Aquí me pierdo, para mí el diseño es jodidamente inmejorable, y no tengo ni zorra aún* de lo que es un façade)
(façade: como un wrapper para simplificar, pero con muchas clases debajo. El turrón dispatcher, pa entendernos :P).
Resume como se ha llevado a cabo el proceso de probar vuestra aplicación a lo largo de las distintas etapas de su desarrollo. Menciona si ha habido alguna relación entre las pruebas y la especificación inicial (por ejemplo casos de uso o documentos de requisitos). Explica, si las hubo, que pruebas se han llevado a cabo para comprobar los requisitos no funcionales.
(eze: nota que en las pruebas con usuario final se ha prestado mucha atención al feedback sobre usabilidad. Las pruebas de requisitos no funcionales eran "esto va muy lento, a ver qué huevos pasa", dedicando iteraciones enteras a localizar los problemas y solucionarlos).
—> Adri
De forma resumida, procurando no utilizar los conceptos específicos de IS que se han explicado en clase, describe lo que te parezca más importante de lo que has aprendido en esta asignatura a lo largo del curso.
(eze: a no dedicarme al desarrollo de software XDDD. A la importancia de la gestión de personal y las jerarquías, en particular el concepto de liderazgo y su influencia en toda la organización -a mi juicio nos ha faltado dirección al final-. A la importancia de la figura del integrador, que evita el exceso de burocracia de un modelo centralizado y proporciona la calidad. También a lo que vale el testing, y en mi caso a lo que importa tener todo por escrito y muy clarito, las responsabilidades muy muy delimitadas y explicitas - aka "el uml lo hacemos entre todos" - pero aquí que cada uno ponga lo que haya aprendido, claro está).
(diana: la importancia de un buen diseño desde la etapa inicial. Ha de conseguirse un diseño que cumpla la funcionalidad básica y al mismo tiempo sea fácilmente ampliable y ello no implique cambiar la arquitectura. Hacerlo lo más modular posible, de forma que un problema que surja en un módulo se pueda solucionar sin afectar apenas al resto y de manera menos costosa. Coincido con Eze en el concepto de liderazgo, aunque en nuestro caso haya sido menos determinante por ser un equipo reducido.)
—> Carmen
Explica con qué conceptos de IS está relacionado lo que hayas descrito en la pregunta anterior.
(eze: proceso, proceso y proceso. Documentado, explicitado. Sea el que sea, sea XP o Rational).
—> Carmen