Índice
Índice de páginas de documentación
Para un índice extensivo, referirse a la tabla de contenidos
- Introducción a HD Lorean
- Requisitos
- Viabilidad
- Alcance
- Casos de uso
- Historias de Uso
- Arquitectura del sistema
- Especificación del formato de snapshots
- Informes de Investigación
- Gestión
Introducción a HD Lorean
HD Lorean no es sólo una aplicación de copias de seguridad totalmente integrada en Linux que te permitirá ver cualquier documento que elijas en cualquier instante de tiempo. No. Es mucho más. Deja que te descubramos algunos de sus usos.
Comenzar es fácil
Por defecto, HD Lorean ya sabe qué debe vigilar, HD Lorean guardará información importante para ti y tu sistema. Tan sólo deberás indicarle dónde debe guardar las copias de seguridad.
Vuelve al pasado
Utilizando tu explorador de siempre, podrás buscar archivos que perdiste o borraste hace mucho tiempo y comprobar el aspecto exacto que tenían en ese instante. Busca utilizando tu propia clasificación de archivos para que te resulte más natural. Con un clic en el botón Traer Al Presente, HD Lorean recuperará los archivos seleccionados haciéndolos visibles en el presente. HD Lorean es capaz de recuperar archivos individuales, carpetas enteras y archivos específicos indicados por programas de terceros.
Cómo funciona HD Lorean
HD Lorean supervisa automáticamente los cambios de los archivos aunque también puedes indicar manualmente cada cuánto deseas que se realice una copia de seguridad.
¿Dónde deseas guardar las copias de seguridad?
Selecciona prácticamente cualquier tipo de soporte para tus copias de seguridad, ya sea externa o no: un disco duro, una memoria USB, una partición, un dispositivo o carpeta en red… Da igual qué soporte elijas, HD Lorean sabe cómo manejar cualquiera de ellos y si uno no está disponible en un momento dado, la copia de seguridad se almacenará provisialmente en tu disco duro hasta que el soporte vuelva a estar disponible.
Diferentes equipos, una misma unidad
HD Lorean crea una carpeta dónde guardará las copias de seguridad, dentro de esta creará una por equipo y dentro de cada una, otra por usuario permitiendo así que todos los usuarios de cualquier equipo trabajen con la misma unidad.
¿Cómo es una copia de seguridad?
HD Lorean realiza una primera copia de seguridad sin compresión y a partir de allí realiza copias incrementales, es decir, que sólo guarda los cambios ocurridos desde la última vez. Esto no garantiza que tu disco duro no se llene nunca, pero lo hará mucho más lentamente que si siempre se copiara absolutamente todo.
Carpe Diem: vive el momento
Día a día, hora a hora o cuando tú decidas se realiza automáticamente una copia de seguridad de tu información más importante.
No alteres tu ritmo de vida
Has terminado de trabajar. Tienes que apagar el equipo e irte pero HD Lorean está realizando una copia de seguridad. No te preocupes, simplemente apaga: HD Lorean pausará la copia de seguridad hasta que vuelvas a encender el equipo.
Copia lo que quieras
En primera instancia, HD Lorean guarda una copia de los archivos de tu cuenta, pero si deseas que esto no sea así, tan sólo accede al menú Archivos Excluidos y añade tanto tipos de archivos que no quieras guardar como archivos expresos que quieras que queden fuera de la copia de seguridad.
¿Y si se acaba el espacio?
No pasa absolutamente nada, HD Lorean puede retomar sus tareas en otro disco duro o bien puede ayudarte a crear una colección de DVDs o CDs dónde guardar las copias de seguridad más antiguas.
Descubre una nueva dimensión temporal
Por qué tener una carpeta para las fotos de verano de este año, otra para las del anterior, otra para el de hace dos años, etc. Mejor tener una sola carpeta fotos de verano con las más recientes y poder consultarla en distintos momentos del tiempo. HD Lorean permite asociar un periodo de caducidad al contenido de una carpeta. Finalizado el periodo de caducidad, el contenido de la carpeta será archivado en el pasado y la carpeta quedará vacía para nuevos usos. Tus archivos siguen ahí, en el pasado, listos para ser consultados utilizando HD Lorean.
Sincroniza tus copias
HD Lorean te da la posibilidad de llevarte las copias de lo que has hecho en la oficina a casa, simplemente indica el mismo dispositivo de copias y pide que se sincronicen las carpetas que tú quieras.
¿Quién tiene el control?
Tú y sólo tú. HD Lorean trabaja de manera invisible a tus ojos a menos que tú se lo indiques. Puedes indicar a HD Lorean qué copias de seguridad ha de borrar, qué archivos debe copiar y cada cuánto tiempo, si las copias de seguridad han de estar comprimidas o no… Así que si te gusta tenerlo todo vigilado, HD Lorean no escapará a tu alcance.
¿No te sientes identificado?
Quizá alguna de estas situaciones se parezca más a la tuya. Échales un vistazo, son situaciones reales.
Requisitos
Requisitos funcionales
El usuario puede…
- Recuperar diferentes versiones (anteriores en el tiempo) de un archivo. Casos de uso que corresponden: CLado, SobUltVr
- Decidir qué carpetas y archivos tendrán seguimiento de versiones. Casos de uso que corresponden: Config, ConfigExc, AñadirC, EliminarC
- Decidir en qué soporte físico se almacenarán estas versiones. Casos de uso que corresponden: Config
- Trasladar las copias de seguridad a otros soportes (tanto copias completas, como historiales de ficheros). Casos de uso que corresponden: Exp,Imp
- Buscar y mostrar por nombre de fichero o por los contenidos, donde podemos ver todas las versiones de los archivos (incluso archivos borrados). Casos de uso que corresponden: BusBack
- Gestionar el espacio en disco, de forma que cuando el disco duro se llene, se recomienda al usuario borrar versiones inútiles de archivos o exportar a CD's y DVD's.Casos de uso que corresponden: Exp,Imp
- Definir fecha de caducidad a los archivos, de forma que se borren de las carpetas (ya están guardados en HD Lorean) los archivos más antiguos o los que menos se han usado últimamente. Casos de uso que corresponden: DimTemp
- Contratar un servicio de copias de seguridad por red en servidores dedicados. Casos de uso que corresponden: AlmEx
- Dedicarse a otras tareas con total normalidad y despreocupación, el sistema trabaja de forma autónoma y transparente. Tus archivos están bajo control desde el momento en que los creas. Casos de uso que corresponden: GuaVrAuto
- Apagar el equipo con HD Lorean funcionando, éste continuará desde el mismo punto cuando el ordenador se vuelva a encender. Casos de uso que corresponden: IntBack
- Excluir las copias de seguridad de determinados archivos (por tipo, tamaño, etc). Casos de uso que corresponden: ConfigExc
- Posibilidad de borrar un archivo y todas sus versiones (o algunas) del backup. Casos de uso que corresponden: BorraT, BorraV
- Ver el estado de las carpetas en cada momento del tiempo. Distintos interfaces de uso. Casos de uso que corresponden: VerVerCarp
- Restaurar archivos/carpetas en otro equipo y sincronizarlos entre ellos. Casos de uso que corresponden: Sinc
- Varios ordenadores/usuarios pueden compartir el mismo soporte físico. Casos de uso que corresponden: CompDisp
- Aplicaciones de terceros pueden utilizar el sistema para sus propias necesidades: Por ejemplo: Los juegos cargan todas tus versiones de partidas guardadas, o el programa de correo puede buscar correos borrados.Casos de uso que corresponden: ApTerceros
Requisitos no funcionales
Requisitos recomendados del sistema:
- Tener un ordenador con Linux. Recomendado Ubuntu 7.10 con inotify y 10 GB de disco duro libre. Red, otro disco duro bastante grande y grabadora de DVD.
- Entorno de escritorio Gnome. Recomendado 2.20
- Python 2.4. Recomendado 2.5
- Compilable desde fuente. build-essentials
- Beagle
- Acceso de lectura a los archivos que se quieren guardar.
Requisitos no funcionales ampliados
- Backups incrementales.
- Inotify (se archiva cada versión de un fichero, siempre que se guarde) hay que mirar para no guardar temporales, swap de programas, etc… Con Inotify no hay problema, se puede seleccionar lo que guardas a nivel de fichero o de directorio, así que podemos hilar tan fino como queramos en ese sentido.
- Funcionamiento en modo desconectado del almacenamiento externo.
- Monitorización del espacio del HD.
- Uso logarítmico del disco duro/tiempo: Cuanto más antiguas sean las copias más separadas en el tiempo estarán las versiones. De los cambios recientes, por ejemplo última semana, el archivo están todas las versiones. Probablemente esto exija colapsar copias de seguridad, de forma que se mantenga la integridad en las copias incrementales.
- Optimización del uso de CPU y disco.
Ventajas de la aplicación
- Guardado de la información de modo logarítmico, de modo que cambiar algo en un archivo de gran tamaño no ocupe de nuevo el tamaño completo, sino que ocupa el espacio de los cambios realizados (Inbox de correo, bases de datos, etc.)
- Integración con Nautilus de GNU/Linux. Se muestran lineas de tiempo.
- API para aplicaciones externas.
- Transparencia y código libre.
Estimaciones de tiempo y espacio
Estimación de espacio
HD Lorean es una aplicación de backup basada en diferenciales. Esto es, si sus ficheros han cambiado, HD Lorean no los copiará de nuevo, sólo considerará los cambios realizados desde la última vez, lo que permite ahorrar espacio en su disco duro. Si no han cambiado, sencillamente no los copiará y no gastará ningún tipo de espacio extra. Sin embargo, en ocasiones las modificaciones son tan grandes que los archivos de diferencias ocupan más que el archivo original; esta situación es detectada por HD Lorean, que sencillamente realiza una nueva copia. Además, los archivos de diferencia también deben guardar información extra que indique si se ha eliminado, añadido o cambiado información, y esta información extra también conlleva sobrecarga de espacio.
Por lo general, para documentos de texto, la realización de archivos de diferencia es una práctica muy eficiente y, suponiendo que los archivos de texto de un usuario aumenten de manera lineal (o un poquito cada día) el tamaño $T$ ocupado en disco al cabo de $n$ copias de seguridad viene dado por la expresión:
(1)En esta expresión, $c$ es la cantidad de bytes añadidos por cada copia de seguridad y $\delta$ es un valor entre 0 y 1 que indica cuánto mejor es el programa de creación de archivos de diferencias. Esto es, cuanto más cerca de 0, mejor. Un valor típico es 0.1 y usaremos este para las simulaciones.
Como se puede observar, el crecimiento del tamaño es parabólico y la siguiente tabla refleja algunos resultados esperados para archivos de diferente tamaño inicial al cabo de 30 diferenciales (uno al día durante un mes) en los que, cada vez, se han añadido 4000 bytes de información nueva.
$T_{inicial}$ | $T_{con\_diferenciales}$ | $T_{sin\_diferenciales}$ | Espacio de disco ahorrado |
---|---|---|---|
8KB | 2MB | 1.9MB | 5% |
80KB | 4.1MB | 2MB | 51% |
800KB | 21.2MB | 2.7MB | 87% |
Los resultados son, a la vista, muy buenos.
Ahora bien, los archivos de otros tipos multimedia como la música, las imágenes o los vídeos vienen muchas veces comprimidos lo que impide realizar diferenciales de manera eficiente. No obstante la edición de estos archivos es mucho más esporádica, y localizada en áreas pequeñas del mismo (EXIF, ID3, etc). En cualquier caso, si se llegasen a cambiar probablemente lo más rentable sea realizar una copia en vez de un archivo de diferencias. Por tanto para este tipo de archivos el tamaño ocupado en disco es de la forma:
(2)Aunque pudiera parecer un inconveniente, la experiencia confirma que son los archivos de texto los más susceptibles a cambios mientras que los archivos multimedia se editan poco. Este equilibrio unido a la potencia de los archivos de diferencias hace de HD Lorean la aplicación ideal en su género en cuanto a consumo de espacio en disco.
Estimación de tiempo
HD Lorean puede realizar copias de seguridad integrales (esto es, copiar el archivo tal cual) en cuyo caso la velocidad del snapshot vendrá determinada por el número de archivos que lo compongan y el tamaño de los mismos así como la velocidad de acceso, lectura y escritura del hardware. O bien puede realizar copias incrementales, en cuyo caso la velocidad depende por un lado del tiempo necesario para crear el diferencial (que depende a su vez del tamaño del archivo) y por otro lado de los parámetros ya citados.
De esta forma, la expresión que rige el tiempo $t$ tardado por un snapshot viene dado por la expresión:
(3)Donde $t_{sistema}$ es el retraso debido al hardware y considerando que existen $dif$ archivos sobre los que se va a crear un diferencial y $int - dif$ archivos que se copiarán íntegramente. Para los archivos de los que se creará un diferencia, el tamaño del mismo se encuentra multiplicado por el retraso en la creación de dicho diferencial $t_{diferencial}$.
La estimación en tiempo, lineal respecto del número de archivos esta vez, puede parecer simple y previsible pero también hay que tener en cuenta que HD Lorean monitoriza los archivos en uso de manera constante y por lo tanto, a excepción de la primera copia de seguridad que probablemente se realice sobre todo el sistema, el resto de copias quedará reducido al conjunto de archivos que cambien. Y esto precisamente reducirá el tiempo empleado por snapshot del sistema.
Conclusiones
De esta forma, se concluye que la eficiencia en el uso del espacio es significativamente mejor cuanto más copias de seguridad se realicen sobre un archivo grande (debido a la creación de archivos de diferencias) o, en el peor de los casos, tan buena como guardar todas las versiones del archivo.
Por otro lado el coste en tiempo es lineal respecto del número de elementos que compongan el snapshot.
Viabilidad
- La base de la aplicación es perfectamente viable a base de guardar copias de los archivos en carpetas ocultas cada vez que se detecten cambios. Es necesario también un índice de datos para búsquedas eficientes, implementable mediante una base de datos como p.e. sqlite.
- Métodos más eficaces de almacenamiento dependerían de la plataforma (p.e. un sistema de archivos que almacene solamente cambios como ZFS, o diffs binarios entre archivos).
- Sin Tracker instalado en los equipos cliente se complicará bastante la implementación de clasificación de archivos y su búsqueda. Es factible, no obstante, ampliar el source de Tracker para adaptarlo a nuestras necesidades.
- La comparación de versiones es trivial para archivos de texto, y para archivos binarios con formato conocido se pueden reutilizar los extractores del citado Tracker. Queda simplemente conseguir una interfaz de usuario sencilla y eficaz.
- El mecanismo inotify del kernel de linux, presente en los equipos cliente, permite indexar un archivo en el momento que es creado y evitar largas búsquedas de cambios.
- La pausa y reanudación de los backups requerirá de un sistema de transacciones similar al de una base de datos o un sistema de ficheros con journal; es necesaria investigación para detectar si es posible reutilizar funcionalidad presente en el sistema.
- Sincronizar archivos entre dos sistemas, ya sean interno y disco duro externo o dos ordenadores con red requiere todavía investigación pero podría hacer uso de rsync, o de mecanismos similares al control de versiones distribuido en caso de que se vayan a integrar las historias de cada archivo.
- Servidor externo de almacenamiento es viable si se nos proporcionase la infraestructura necesaria, pero hasta el final del desarrollo del proyecto será dificil integrarlo.
- GTK es una tecnología nueva para el equipo, así como python, lo que dificultará el desarrollo. Confiamos en que sea lo bastante sencillo de usar como para que sea mínimo el aprendizaje, a la vista de su gran implantación en el software libre. Se usará para ello pygtk.
- El equipo tampoco conoce el uso de dbus para comunicación IPC entre backend y frontend, y en general entre los diferentes procesos que pueda tener la aplicación.
- La integración y transparencia vendría por un lado del software como demonio, y por otra parte de integrarlo con el entorno de escritorio (concretamente con nautilus); es necesaria investigación también al respecto para determinar las posibilidades, pero en última instancia podría ser modificado el código fuente.
Alcance
- Una primera fase de la aplicación sería desarrollar el backend con la funcionalidad mínima para soportar la base de la aplicación, y un desarrollo de interfaz para probarlo.
- Es importante también desarrollar lo antes posible la integración con el entorno de escritorio a fin de estudiar la usabilidad del sistema, fundamental en los requisitos del mismo.
- El almacenamiento diferencial de copias para utilizar poco espacio en disco es viable (mediante diff o mecanismos similares).
- Externalizar copias de seguridad requerirá de investigación sobre la arquitectura pero es factible.
- La caducidad automática de las copias de seguridad es viable, pero en una primera fase del desarrollo se hará manualmente para asegurarse del funcionamiento.
- La sincronización en red será complicada pero en principio no es diferente a sincronizar con un disco duro externo.
- La integración con el entorno de escritorio dependerá de las facilidades que proporcione el mismo (como plugins para nuevas vistas del navegador de archivos).
- Realizar un API sencillo será una prioridad media en el desarrollo; integrar alguna aplicación existente con el mismo es menos viable al exigir el conocimiento de esa aplicación a nivel código fuente para modificarla.
- El servidor externo no es viable en el tiempo proporcionado, puesto que además del sistema completo y estable finalizado requiere de infraestructura que no tenemos y de administración que está completamente fuera del ámbito del desarrollo.
Casos de uso
Definición
En Ingeniería del Software, un caso de uso1 es la representación de una interacción entre el usuario final y el software que sirve para estudiar el comportamiento potencial de un sujeto en el entorno de la aplicación. Dado que es posible que un mismo usuario pueda acceder al sistema con múltiples roles, en el ámbito de los casos de uso se prefiere el uso de la palabra actor para designar a cada usuario en cada uno de los posibles roles (por ejemplo, administrador, moderador, supervisor, gestor…)
Las principales características de los casos de uso son las siguientes:
- Están expresados desde el punto de vista del actor
- Se describen mediante un lenguaje informal
- Exponen alguna funcionalidad puntual de la aplicación.
Lista de casos de uso
Nota: los pantallazos adjuntos pueden no corresponder al estado final del software, ya que han sido usados como prototipos para el desarrollo.
Añadir una dimensión temporal a una carpeta (No implementado)
Identificador de caso: | DimTemp | |||
Nombre de caso: | Añadir una dimensión temporal a una carpeta | |||
Creado por: | Salva | Fecha de creación: | 29-10-07 | |
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Tras instalar el programa es posible activar una característica especial para ciertas carpetas vigiladas que permite mantener en ellas sólo los documentos recientes borrando automáticamente los antiguos y archivándolos como copia de seguridad. |
|||
Precondiciones: | El programa debe estar instalado, el seguimiento activado y debe haber al menos una carpeta bajo vigilancia. | |||
Flujo normal: | caso 1 1. Abrir el panel de control de la aplicación 2. Seleccionar "Carpetas con dimensión temporal" entre sus opciones. 3. Seleccionar "Añadir nueva carpeta" y buscar la carpeta deseada. 4. Establecer el periodo de caducidad tras el cual los archivos contenidos en la carpeta serán borrados y archivados como copia de seguridad. 5. Hacer clic en aceptar. caso 2 1. Hacer clic derecho sobre cualquier carpeta. 2. Seleccionar el submenú HD Lorean. 3. Seleccionar la opción "Añadir dimensión temporal." 4. Establecer el periodo de caducidad de la carpeta. 5. Hacer clic en Aceptar. |
|||
Flujos alternativos: | 3.1 Falta espacio en disco para almacenar las versiones caso recuperable: Se libera espacio caso no recuperable: No se libera espacio en disco y por tanto se suspende la monitorización |
|||
Postcondiciones: | Nueva carpeta con dimensión temporal establecida. |
Añadir una nueva carpeta a indexar
Identificador de caso: | AñadirC | |||
Nombre de caso: | Añadir una nueva carpeta a indexar | |||
Creado por: | Fecha de creación: | 28-10-07 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Después de tener el programa instalado y el configurador inicial hecho, con el programa corriendo, se decide añadir una nueva carpeta a las ya elegidas para que también realice un backup. | |||
Precondiciones: | El programa está instalado y el configurador inicial se ha ejecutado | |||
Flujo normal: | 1. Elegir nueva carpeta a indexar. 2. Se añade el nuevo contenido al backup ya realizado del resto de carpetas. |
|||
Flujos alternativos: | 2.1 El espacio disponible en el medio de almacenamiento del backup puede ser inferior al tamaño adicional que se necesita: caso no recuperable : Se vuelve al menú donde se seleccionaba la nueva carpeta, habiendola excluido (de momento) de la lista de carpetas a realizar backup, para poder elegir otra ruta o cancelar el menú |
|||
Postcondiciones: | Nueva carpeta con backup realizado, e incluida dentro de la lista de carpetas de las que se hace seguimiento |
Borrar todas las versiones de un archivo
Identificador de caso: | BorraT | |||
Nombre de caso: | Borrar todas las versiones de un archivo | |||
Creado por: | Fecha de creación: | 26-10-07 | ||
Actualizado por: | Jorge | 2-11-2007 | ||
Actores: | Usuario | |||
Descripción: | Borra un archivo seleccionado por el usuario | |||
Precondiciones: | Ninguna | |||
Flujo normal: | 1. Selección del archivo. 2. Se recorre el sistema de backups eliminando las versiones del archivo. |
|||
Flujos alternativos: | 2.1 Alguna versión del archivo ha sido movida a soporte óptico, u otro medio externo. caso recuperable se limpia su información de la base de datos caso recuperable se advierte al usuario de que las versiones están presentes en un medio externo, y se le ofrece volver a grabarlo eliminando esas versiones para que no quede huella. |
|||
Postcondiciones: | Eliminación del sistema de backups de todas las versiones de un archivo. |
Borrar una versión de un archivo
Identificador de caso: | BorraV | |||
Nombre de caso: | Borrar una versión de un archivo | |||
Creado por: | Fecha de creación: | 26-10-07 | ||
Actualizado por: | Jorge | 2-11-2007 | ||
Actores: | Usuario | |||
Descripción: | Borra una versión de un archivo seleccionada por el usuario | |||
Precondiciones: | Ninguna | |||
Flujo normal: | 1. Selección de la versión del archivo. 2. Se busca la versión correspondiente del archivo en el sistema de backups. 3. Se elimina del sistema de backups. |
|||
Flujos alternativos: | 2.1 la versión no se encuentra en el sistema. caso recuperable se borra su información de la base de datos |
|||
Postcondiciones: | Eliminación del sistema de backups de la versión correspondiente del archivo. |
Configurar Exclusión
Identificador de caso: | ConfigExc | |||
Nombre de caso: | Configurar Exclusión | |||
Creado por: | Fecha de creación: | 31-10-2007 | ||
Actualizado por: | Jorge | 2-10-2007 | ||
Actores: | Usuario | |||
Descripción: | El usuario no quiere que un cierto patrón de archivos se guarde. Esto implica avisar al usuario de que se va a dejar de monitorizar esos archivos así como perder versiones anteriores. | |||
Precondiciones: | Este tipo de archivo estaba siendo monitorizado | |||
Flujo normal: | 1. Abrir el configurador. 2. Elegir la opción excluir. 3. Elegir el tipo de archivos a excluir de la vigilancia. 4. Preguntar al usuario si desea borrar las copias existentes en el sistema de backups de este tipo de archivos. 4.a En caso afirmativo borrar dichos archivos. 4.b Avisar de que los archivos seguirán en el sistema de backups. 5. Borrar los archivos del tipo indicado. |
|||
Flujos alternativos: | 4.a.1 Hay ficheros que han sido volcados a soporte externo. caso recuperable: Se borran de la base de datos |
|||
Postcondiciones: | Los archivos de tipo excluido no serán guardados por HD Lorean |
Configuración inicial
Identificador de caso: | Config | |||
Nombre de caso: | Configuración inicial | |||
Creado por: | Fecha de creación: | 26-10-07 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Al instalar el programa se le pide al usuario que introduzca una serie de opciones para que el programa funcione a su gusto. | |||
Precondiciones: | El programa no está configurado aún. | |||
Flujo normal: | 1. Elegir qué carpetas indexar. Se va a avisar al usuario del espacio que va a ocupar todo esto. 2. Elegir Lugar donde guardar backups. Las opciones que aparecen son: HD Local (ruta en el sistema), HD externo con un desplegable de los dispositivos conectados al sistema, Red, con un campo de texto para poner la url. 3. Elegir tipos de archivos y patrones a excluir. 4. Elegir el intervalo de backup (cada vez que se modifican los archivos o cada cierto tiempo, activar el inotify o el planificador de backup). 5. Se hace un backup inicial (caso Bini). Se le pregunta al usuario si lo desea hacer ahora o si prefiere cancelar y hacerlo en otro momento. Se avisa al usuario que HD Lorean no estará funcionando hasta que no se termine este backup inicial. |
|||
Flujos alternativos: | 2.1. En el paso 2 el espacio disponible en el medio selecionado puede ser inferior al necesario para guardar el backup inicial caso recuperable 2.1.1 : existe otro medio disponible con espacio suficiente caso recuperable 2.1.2 : se eliminan carpetas a monitorizar mermando su tamaño hasta uno inferior al disponible caso no recuperable 2.1.3 : no se prescinde directorios preseleccinados y no existe espacio suficiente en ningún medio 4.1 Para que el programa funcione con inotify, tiene que funcionar éste siempre que se ejecute HD Lorean. En caso de que no esté funcionando en el momento de hacer la configuración, no se da esta opción al usuario. |
|||
Postcondiciones: | Programa correctamente instalado y listo para ejecutarse según las opciones |
Copiar al lado
Identificador de caso: | CLado | |||
Nombre de caso: | Copiar al lado | |||
Creado por: | Fecha de creación: | 30-10-2007 | ||
Actualizado por: | Diana | Fecha de Actualización: | 11-4-2007 | |
Actores: | Usuario | |||
Descripción: | Restaurar una versión anterior del archivo sin sobreescribir la actual | |||
Precondiciones: | Tener la versión del archivo que se desea recuperar guardada en el sistema de backups | |||
Flujo normal: | 1. Seleccionar la versión deseada del archivo mediante la barra de tiempo. 2. Elegir la opción "Restaurar sin sobrescribir". 3.a Restaurar el archivo con el nombre original terminado con la fecha correspondiente, si la versión es accesible 3.b Si la versión solicitada está almacenada en soporte óptico se requerirá al usuario que introduzca el disco adecuado y se procederá a restaurar el archivo |
|||
Flujos alternativos: | 3.b.1 Se introduce un disco erróneo. caso recuperable: se solicita de nuevo. 3.b.2 El usuario ha perdido el disco. caso no recuperable: el usuario cancela el proceso |
|||
Postcondiciones: | El archivo elegido ha sido restaurado y no se ha machacado el actual. |
Eliminar una carpeta a indexar
Identificador de caso: | EliminarC | |||
Nombre de caso: | Eliminar una carpeta a indexar | |||
Creado por: | Fecha de creación: | 29-10-07 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Después de tener el programa instalado y el configurador inicial hecho, con el programa corriendo, se decide eliminar una carpeta de las ya elegidas para que deje de realizar backup de esa carpeta. | |||
Precondiciones: | El programa está instalado, el configurador inicial se ha ejecutado | |||
Flujo normal: | 1. Elegir entre las ya existentes una carpeta para dejar de indexar. 2. Se borra la ruta de la lista de carpetas que se indexaban. 3. Se pregunta al usuario si quiere eliminar los backups existentes en el sistema de esas carpetas. 3.a En caso afirmativo se eliminan los backups. 3.b En caso contrario se le avisa de que se mantendrán el sistema. |
|||
Flujos alternativos: | 1.1 No hay ninguna carpeta indexada: caso recuperable: Se avisa de que no hay ninguna carpeta indexada al usuario y se cierra el menú. 3.a.1 Si los backups se han volcado a un dispositivo externo: caso recuperable: se eliminan las entradas correspondientes en la base de datos. |
|||
Postcondiciones: | La carpeta que se ha especificado ya no está entre las que se indexan. |
Sincronizar (No implementado)
Identificador de caso: | Sinc | |||
Nombre de caso: | Sincronizar | |||
Creado por: | Fecha de creación: | 18-11-2007 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | El usuario realiza una sincronización entre 2 carpetas. | |||
Precondiciones: | Programa instalado en 2 ordenadores. | |||
Flujo normal: | 1. El usuario elige la opción de sincronizar. 2. El usuario elige la carpeta del backup y la carpeta que quieres sincronizar. 3. Se copia en la carpeta a sincronizar toda la carpeta de backup. 4. Se hace backup de todas las modificaciones que se hagan de la carpeta sincronizada. 5. Finalización del proceso. |
|||
Flujos alternativos: | ||||
Postcondiciones: | El usuario tiene 2 carpetas iguales. La carpeta de backup se sincronizará como última versión cuando se conecte al ordenador original. |
Exportar a un dispositivo externo (No implementado)
Identificador de caso: | Exp | |||
Nombre de caso: | Exportar/Importar a un dispositivo externo | |||
Creado por: | Rober | Fecha de creación: | 30-02-2007 | |
Actualizado por: | Ezequiel | Fecha de actualización: | 18-12-2007 | |
Actores: | Usuario, Dispositivo externo | |||
Descripción: | El usuario realiza un backup en un dispositivo externo, un HD o un CD/DVD | |||
Precondiciones: | Programa instalado y configurado | |||
Flujo normal: | 1. Elegir el soporte externo donde se va a guardar. 2. Elegir la carpeta/s que se van a guardar. 3. Elegir si se guarda toda la historia de los archivos, o solo su versión más actual (posiblemente automático según el espacio disponible en el medio de almacenamiento) 3. Comenzar la ejecución del guardado. Presentar al usuario informe de progreso de la misma. 4. Finalización de la copia. 5. Preguntar si el usuario desea hacer otra copia. 6. Pasos 3,4 y 5 un numero determinado de veces. 7. Fin del proceso. |
|||
Flujos alternativos: | 4.1 Error en la copia. caso recuperable: se solicita al usuario que la realice de nuevo. |
|||
Postcondiciones: | El usuario tiene un backup funcional en un dispositivo externo. |
Importar de un dispositivo externo (No implementado)
Identificador de caso: | Imp | |||
Nombre de caso: | Importar de un dispositivo externo | |||
Creado por: | Ezequiel | Fecha de creación: | 18-12-2007 | |
Actualizado por: | Diana | Fecha de actualización: | 10-04-2008 | |
Actores: | Usuario, Dispositivo externo | |||
Descripción: | El usuario quiere importar la información de un backup externo al sistema, posiblemente tras un formateo o cambio de equipo. | |||
Precondiciones: | Programa instalado y configurado | |||
Flujo normal: | 1. Insertar el medio externo con la información 2. Detectarlo y preguntar al usuario si desea importarlo. 3. Cargar la información en la base de datos y contrastarla con la local. 4. Añadir la información nueva y almacenarla, marcándola como "guardada en medio externo" para poder usarla. 5. Preguntar al usuario si se desea restaurar la última versión de la información presente en el medio externo |
|||
Flujos alternativos: | 3.1 Conflicto de archivos. El archivo que importamos ya existe en el disco duro. caso recuperable: se añade la historia importada a la presente, y al acabar el backup le aparecerá al usuario resaltado que tenía un archivo de mismo nombre en su backup. 3.2 Conflicto de versiones. Un archivo tiene dos versiones en tiempos idénticos pero diferentes (identificadas por su checksum); se puede dar si el usuario importa desde otro ordenador con el que se trabajó a la vez que en este. caso no recuperable: se informa al usuario de la inconsistencia. Por defecto no se modifica la información local. Se continúa con el resto de archivos. |
|||
Postcondiciones: | El usuario tiene un backup funcional en un dispositivo externo. |
Guardar una versión
Identificador de caso: | GuarV | |||
Nombre de caso: | Guardar una versión | |||
Creado por: | Fecha de creación: | 26-10-07 | ||
Actualizado por: | David | Fecha de actualización: | 30-10-07 | |
Actores: | ||||
Descripción: | El sistema guarda una versión de un archivo modificado. | |||
Precondiciones: | Ocurre un cambio en un fichero (se crea, se guarda o se borra) de una carpeta vigilada. | |||
Flujo normal: | 1. Se hace un archivo de diferencias entre el archivo original (el más antiguo en los backups disponibles) y el nuevo estado del fichero. 2. Integrar en el sistema de backups. |
|||
Flujos alternativos: | 2.1 Falta de espacio en disco caso recuperable : Liberamos espacio de disco: integrando en el backup los ficheros de diferencias anteriores y borrando estos. caso no recuperable : No se libera espacio |
|||
Postcondiciones: | Integración de una nueva versión de un archivo en el sistema de backups. |
Guardar versiones automáticamente
Identificador de caso: | GuaVrAuto | |||
Nombre de caso: | Guardar versiones automáticamente | |||
Creado por: | Fecha de creación: | 30-02-2007 | ||
Actualizado por: | Dani | Fecha de actualización: | 02-11-2007 | |
Actores: | Usuario | |||
Descripción: | Automáticamente se van guardando las versiones de un archivo. | |||
Precondiciones: | 1. Tener activada la vigilancia en tiempo real. 2. El archivo existe en una carpeta vigilada, y el usuario lo modifica. |
|||
Flujo normal: | 1. El usuario guarda el archivo con modificaciones. 2. HD Lorean detecta que se ha modificado el fichero y se ha guardado. 3. Se hace un backup (caso de uso GuarB). |
|||
Flujos alternativos: | ||||
Postcondiciones: | Se tiene el backup actualizado con las modificaciones del fichero. |
Backup inicial
Identificador de caso: | BIni | |||
Nombre de caso: | Backup inicial | |||
Creado por: | Fecha de creación: | 26-10-07 | ||
Actualizado por: | Adri | Fecha de actualización: | 02-11-07 | |
Actores: | ||||
Descripción: | El sistema realiza el primer backup después de la instalación y configuración. | |||
Precondiciones: | Existe espacio para alojar el primer backup | |||
Flujo normal: | 1. Se copia todo el contenido de las carpetas vigiladas en el dispositivo o carpeta de bakcup. | |||
Flujos alternativos: | 1.1 El usuario no tiene permisos de escritura sobre el dispositivo o carpeta seleccionado. caso recuperable: se solicita al usuario que seleccione un nuevo dispositivo o corrija los permisos. 1.2 El usuario no tiene permisos de lectura sobre las carpetas que quiere vigilar. caso recuperable: se avisa al usuario para que corrija los permisos. caso no recuperable: se cancela el backup de las carpetas sobre las que no se dispone de permisos. |
|||
Postcondiciones: | Primer backup realizado correctamente. |
Sobrescribir última versión
Identificador de caso: | SobUltVr | |||
Nombre de caso: | Sobrescribir última versión | |||
Creado por: | Fecha de creación: | 30-02-2007 | ||
Actualizado por: | Adrián | Fecha de actualización: | 02-11-07 | |
Actores: | ||||
Descripción: | Sobrescribimos la última versión de un archivo con una versión anterior | |||
Precondiciones: | Se tiene un archivo indexado y con varias versiones guardadas en el backup del programa. | |||
Flujo normal: | 1. Seleccionar la versión deseada anterior a la actual del archivo mediante la barra de tiempo. 2. Elegir la opción "Restaurar sobrescribiendo". 3. Restaurar el archivo con el nombre original. |
|||
Flujos alternativos: | 2.1 La versión del archivo se encuentra en un dispositivo externo. caso recuperabe: Se pide el dispositivo correspondiente. caso no recuperable: No se dispone del dispositivo y se cancela la acción. |
|||
Postcondiciones: | El archivo ha sido restaurado machacando el actual. |
Buscar contenidos en el backup (No implementado)
Identificador de caso: | BusBack | |||
Nombre de caso: | Buscar contenidos en el backup | |||
Creado por: | Jorge | Fecha de creación: | 7-10-2007 | |
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Buscamos un archivo en las copias de seguridad | |||
Precondiciones: | Existen copias de seguridad | |||
Flujo normal: | 1. El usuario introduce el nombre del archivo a buscar. 2. Se busca entre los archivos de respaldo. 3. Se presentan los resultados al usuario. |
|||
Flujos alternativos: | 3.1 No se obtienen resultados en la búsqueda. caso recuperable: se comunica que no hay versiones anteriores. |
|||
Postcondiciones: |
Almacenamiento extra (No implementado)
Identificador de caso: | AlmEx | |||
Nombre de caso: | Almacenamiento extra | |||
Creado por: | Fecha de creación: | 16-11-2007 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Se le indica al programa que debe guardar los backups en el servidor de HD Lorean | |||
Precondiciones: | 1. Existen copias de seguridad. 2. El usuarios ha contratado el servicio. |
|||
Flujo normal: | 1. El usuario elige la opción de almacenar los backups en el servidor. 2. Se le pide que introduzca la clave que se le proporcionó al contratar el servicio. 3. Se exporta la información al servidor. |
|||
Flujos alternativos: | 2.1 El usuario introduce una clave errónea. caso no recuperable: se le pide que vuelva a introducir la clave. |
|||
Postcondiciones: | Todos los backups se han transferido al servidor y a partir de ahora, siempre y cuando haya conexión, los backups se almacenaran en el servidor. En caso contrario se almacenarán en la carpeta predeterminada y cuando haya conexión la información se volcará al servidor. |
Interrupción backup
Identificador de caso: | IntBack | |||
Nombre de caso: | Interrupción backup | |||
Creado por: | Fecha de creación: | 18-11-2007 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | Se interrumpe el backup y el programa ha de guardar ese estado para poder retomarlo en un futuro | |||
Precondiciones: | 1. El programa ha comenzado a hacer una copia de seguridad y no la ha terminado. | |||
Flujo normal: | 1. Por algún motivo se para la copia de seguridad (el usuario apaga el pc, etc). 2. Cuando el programa se vuelve a iniciar retoma la copia en el lugar que se quedó. |
|||
Flujos alternativos: | ||||
Postcondiciones: | La copia de seguridad es igual de fiable que si no se hubiese producido la parada. |
Aplicaciones terceros (No implementado)
Identificador de caso: | ApTerceros | |||
Nombre de caso: | Aplicaciones terceros | |||
Creado por: | Fecha de creación: | 19-11-2007 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario, Aplicación de terceros | |||
Descripción: | El usuario utiliza nuestro programa desde otra aplicación, para conseguir la funcionalidad de recuperar documentos borrados, o versiones anteriores de los documentos. | |||
Precondiciones: | 1. La aplicación de terceros utiliza la API de HD Lorean. 2. Existen copias de seguridad de los ficheros que se utilizan a través de la aplicación de terceros. |
|||
Flujo normal: | 1. Desde la aplicación de terceros, el usuario quiere buscar una versión anterior de un fichero o un fichero que ha borrado. 2. La aplicación se comunica con HD Lorean pidiendo versiones de un fichero, o una versión concreta de un fichero. 2.1 En caso de existir varios resultados posibles, HD Lorean le devuelve a la aplicación de terceros una lista con los resultados posibles. 2.2 La aplicación de terceros muestra la lista de resultados posibles al usuario. 2.3 El usuario elige qué resultado es el que desea. 3. HD Lorean le devuelve a la aplicación el fichero que el usuario desea, de forma que ésta pueda abrirlo. |
|||
Flujos alternativos: | ||||
Postcondiciones: | La aplicación abre un fichero que estaba almacenado en las copias de seguridad como si fuera un fichero normal, el usuario puede editarlo y guardarlo si lo desea, dentro del sistema de ficheros del ordenador. |
Ver versiones de carpetas
Identificador de caso: | VerVerCarp | |||
Nombre de caso: | Ver versiones de carpetas | |||
Creado por: | Fecha de creación: | 19-11-2007 | ||
Actualizado por: | Fecha de actualización: | |||
Actores: | Usuario | |||
Descripción: | El usuario quiere ver el contenido de las copias de sus carpetas a lo largo del tiempo | |||
Precondiciones: | 1. Existe al menos una copia de seguridad de las carpetas vigiladas. | |||
Flujo normal: | 1. El usuario abre el navegador temporal de archivos o en la consola ejecuta el comando para ver el contenido de una carpeta en algún instante de tiempo. 2. (En caso de existir más de una copia de seguridad de esa carpeta) El usuario decide ver el contenido de esa misma carpeta en algún otro instante de tiempo. |
|||
Flujos alternativos: | ||||
Postcondiciones: | El usuario ha podido comparar los contenidos de una carpeta en una versión y en otra. |
Historias de Uso
Introducción
A continuación presentamos una serie de situaciones de la vida cotidiana donde se muestran las funcionalidades básicas de HD Lorean.
Historias de uso
Configuración de aplicación de copia de seguridad
Me han hablado de una aplicación nueva que me salvará de lo patrañas que soy con mi pobrecito ordenador. Me pasan el paquete para instalar y salen unas ventanitas que me dicen dónde quiero guardar las copias de seguridad, cada cuánto tiempo y otras cosas que me resultaron muy fáciles de entender. Mi madre ya no se cabrea cuando borro su lista de la compra, porque siempre está guardada, y vuelvo a poder salir todos los fines de semana.
Casos de uso que corresponden: Config, BIni
Carpetas con dimensión temporal
Me gusta tener la documentación de mi carrera en mi equipo para que siempre pueda acceder a ella. Suelo distinguirla por cursos y tengo una carpeta con otras llamadas Curso 04, Curso 05, Curso 06, Curso 07… Siempre me he preguntado de que forma podría simplificar esta organización. Ya sé cómo, con HD Lorean. Ahora, cada vez que comienza el curso mi carpeta está como nueva, dispuesta a albergar los documentos presentes sin haber perdido los anteriores y pudiendo acceder a ellos desde el navegador.
Casos de uso que corresponden: DimTemp
Documentación Gervás
En una de las últimas iteraciones Gervás nos dice que no le gusta como hemos reformateado la documentación. Menos mal que teníamos HD Lorean y pudimos volver a la versión anterior donde sí le gustaban.
Casos de uso que corresponden: CLado
Exclusión De Videos
El usuario Pepe, que se baja muchos archivos con el aMule de internet, sobre todo películas, ve que su disco duro se está llenando de películas que ya ha visto, y de versiones de los archivos temporales que está usando aMule. El usuario decide que no quiere guardar todo eso en HD Lorean. El sistema le advierte de que entonces no podrá recuperar esos archivos ni sus versiones anteriores, y le ofrece sacarlo a un cd o disco externo.
Casos de uso que corresponden: ConfigExc
Disco duro Viejo
Juan no se fía de su viejo disco duro, y decide hacer un backup reciente completo en un dvd de todo su ordenador por si las moscas. Entonces utiliza HD Lorean para hacer una copia de la historia de un archivo.
Casos de uso que corresponden: Exp, Imp
Hermano Malintencionado
La semana pasada al levantarme encendí el ordenador para dejarlo descargando. Al volver a casa por la tarde me dí cuenta de que mi hermano había eliminado mis documentos.
Lo que él no sabe es que tengo un programa fantástico llamado HD Lorean que guarda copias de seguridad, gracias al cual pude recuperar mis documentos. Finalmente mi hermano fue severamente castigado.
Casos de uso que corresponden: SobUltVr
He Sobreescrito Mi Carpeta De Fotos
Vengo del veraneo con una cantidad ingente de fotos y quiero verlas por que voy a mandar a imprimir las mejores. Enchufo la cámara, selecciono las fotos y las copio en mi carpeta de fotos. Aceptar, deseo sobreescribir. Acepto… ¡rayos! no me he dado cuenta de que mi cámara pone siempre el mismo nombre a las fotos y acabo de sobrescribir otras fotos que había hecho en semana santa.
¡Menos mal que tengo HD Lorean instalado y puedo recuperar mis queridas fotos!
Casos de uso que corresponden: SobUltVr
Llevamos 5 años
Uf! llevo 5 años utilizando el maravilloso HD Lorean y ¡me encanta!… pero mi disco duro se está llenando y no quiero contratar el servicio de almacenamiento extra. Bueno, supongo que no necesitaré más las versiones antiguas de mis prácticas de Lp1, Lp2, Lp3, Plg, etc, etc. No hay problema! Borraré todas las versiones anteriores al martes 27 del año 2004 y recupero mucho espacio!
Casos de uso que corresponden: BorraT
Me Han Matado Quiero Recuperar Mi Partida
Dios… Se acerca el final, llevo un mes jugando a este juego y estoy cerca del enemigo final, llego a la última puerta y… ¿¿Que tenía que haber cogido qué?? Cachis, y ahora no puedo volver, tendría que volver a empezar a jugar…
Menos mal que tengo HD Lorean y puedo recuperar la partida desde justo antes de cuando me olvidé de coger ese objeto crítico.
Casos de uso que corresponden: SobUltVr
Me Piden Apuntes
Soy un buen estudiante pero algo desorganizado y nunca sé dónde tengo cada tema en mis apuntes del ordenador. A veces incluso he borrado archivos que no debía porque no sabía lo que eran.
Menos mal que cuento con la inestimable ayuda de HD Lorean, que me permite buscar contenidos entre mis apuntes de otros años, y además entre los que he borrado o versiones antiguas.
Mis amigos están encantados y me han pedido el cd del programa por que lo encuentran muy útil.
Casos de uso que corresponden:BusBack
Partidas De Juego
Main » Documentación » Historias de uso » Partidas De Juego
Hace años Juan jugaba a un juego en su ordenador, cuando se aburrió lo desinstaló pero antes, previsor él, añadió la carpeta de saves a HD Lorean. Ahora lo ha vuelto a instalar y ha podido retomar el juego en el punto donde lo dejó gracias a HD Lorean, un programa que le hizo una copia de seguridad de esos archivos.
Casos de uso que corresponden:BusBack, SobUltVr
Pasar a DVD
Bueno, mi disco duro es muy fiable… HD Lorean es realmente robusto… pero no me fío del todo. Voy a coger todo lo que llevo cambiando en Mis Documentos a lo largo de este año… y me lo voy a poner en un DVD. ¡Libero espacio y sigo manteniendo mis versiones!
Casos de uso que corresponden: Exp
Recuperar Correo
Ayer borré todos mis e-mails y hoy me he dado cuenta de que necesito uno de ellos en el que estaba la dirección de un amigo. Ahora con HD Lorean no es problema, porque puedo recuperarlo desde el propio programa de correo.
Casos de uso que corresponden: Caso de uso para la API.
Restaurar Config
Una mañana fría de Agosto decidimos instalar el nuevo compiz en nuestra distribución. Nos han gustado mucho sus efectos de escritorio y nos aventuramos en una wiki que nos indica cómo instalarlo.
Por no saber mucho, nos ponemos a tocar el xorg.conf intentando conseguir una mejor aceleración gráfica y conseguimos todo lo contrario. En lugar de revisar las líneas del archivo, simplemente podemos restaurar nuestra versión anterior con HD Lorean.
Casos de uso que corresponden: SobUltVr, GuaVrAuto
Archivos Indiscretos
Mantienes conversaciones nocturnas con una "amiga danesa" de hace años. Tienes copia de las conversaciones y de las fotos en HD Lorean, pero ahora tu novia quiere ver qué cosas tienes por ahí ocultas… Así que decides borrar una versión de los archivos especialmente maligna para que no haya problemas conyugales, HD Lorean te lo permite.
Casos de uso que corresponden: BorraV
Se Va La Luz
Una fría noche de tormenta, estaba yo programando cuando de repente se oyó un estruendo y se fue la luz. Al reiniciar el ordenador, ¡sorpresa! el disco duro se había churrascado y había perdido todo lo que tenía en el ordenador.
¡Pero no pasa nada! Tenía HD Lorean instalado, así que después de sustituir un disco duro nuevo por el chamuscado, conecté al ordenador mi disco duro externo donde tengo la copias de seguridad hechas por el programa y restauré mis configuraciones y archivos quedando tal y como estaba justo antes de la catástrofe.
Casos de uso que corresponden: Exp, Imp, SobUltVr
Sincronización Con Portátil
Juan tiene muchos documentos en su portátil, que utiliza diariamente en su trabajo. Quiere hacer un backup de todos sus documentos para traspasarlo a su ordenador de sobremesa, en el cual es mas cómodo trabajar. Con HD Lorean puede crear un backup de sus documentos del portátil y sincronizarlo con el sobremesa.
Casos de uso que corresponden: Sinc
Ya no quiero copias de esta carpeta
Elegí algunas carpetas para las que quería copia de seguridad. Sin embargo ahora no necesito vigilar una de ellas. La he eliminado de las carpetas que el programa monitorizará y listo.
Casos de uso que corresponden: AñadirC, EliminarC
Contratar servicio de almacenamiento
Utilizo HD Lorean para guardar copias de seguridad de mi trabajo, las cuales ocupan mucho espacio. Por ser algo tan importante decidí contratar el servicio de almacenamiento extra que me ofrecían. Ahora no me tengo que preocupar de cuánto ocupan mis copias, sé que tendré espacio para almacenarlas.
Casos de uso que corresponden: AlmEx
Arquitectura del sistema
Arquitectura de la aplicación
Diseño inicial de la arquitectura:
Clases
Tras el brainstorming de clases, llegamos a las siguientes:
Database (base de datos)
Descripción
Interfaz sobre las bases de datos para encapsular la funcionalidad que se requiera de las mismas.
Responsabilidades
Abstraer el comportamiento interno de las bases de datos al resto de la aplicación para no depender de ellas y ocultar la complejidad del SQL.
Journal
Descripción
Mantiene un listado de operaciones pendientes de realización a fin de poder recuperarnos de caídas del sistema y de no sobrecargar el sistema, permitiendo planificar.
Responsabilidades
- Escribir en la base de datos lo que le ha pedido Watcher.
- Borrar la tarea una vez terminada.
Colaboraciones
History (Historia)
Descripción
Guarda toda la información del sistema de snapshots.
Responsabilidades
- Mantener la información de todas las versiones que guarda el usuario, tanto locales como en dispositivos externos.
Colaboraciones
XDelta3 Wrapper
Descripción
Ofrece a HD Lorean la funcionalidad presente en la aplicación xdelta que cubre necesidades del programa y traduce entre la misma y las facilidades que ofrece xdelta. Parte de una factoría gestionada por storage manager.
Colaboraciones
LVM Wrapper
Descripción
Ofrece a HD Lorean la funcionalidad presente en el sistema de archivos LVM que cubre las necesidades del programa y traduce entre las mismas y las facilidades que ofrece LVM. Parte de una factoría gestionada por storage manager.
Por ahora no desarrollada por estar fuera del alcance.
ZFS Wrapper
Descripción
Ofrece a HD Lorean la funcionalidad presente en el sistema de archivos ZFS que cubre las necesidades del programa y traduce entre las mismas y las facilidades que ofrece ZFS. Parte de una factoría gestionada por storage manager.
Por ahora no desarrollada por estar fuera del alcance.
Snapshot manager (Administrador de snapshots)
Descripción
Administra los snapshots.
Responsabilidades
- Borrar un snapshot.
- Crear un snapshot.
- Recuperar determinada versión de un archivo en un instante dado.
- Busca una versión entre todas las almacenadas en un instante dado.
Colaboraciones
Storage manager (Administrador de almacenamiento)
Descripción
Interfaz para los distintos sistemas de archivos que puede soportar la aplicación.
Responsabilidades
Abstraer el comportamiento interno del sistema de archivos al resto de la aplicación para no depender de él.
Colaboraciones
Snapshot viewer (Visor de diferencias entre los snapshots)
Descripción
Permite la comparación visual entre dos snapshots.
No desarrollado por el momento por estar fuera del acance
Scheduler
Descripción
Establece el orden en que se realizan las operaciones de copia de seguridad y cuándo deben suceder.
Responsabilidades
- Atender al journal.
- Planificar los snapshots mediante los monitores de carga del sistema.
- Ordenar grabar y borrar los snapshots.
- Avisar a Watcher de que se ha finalizado una operación.
Colaboraciones
- Monitor de carga del disco duro
- Monitor de espacio libre en disco
- Monitor de carga de la CPU
- Monitor de estado de la batería
- Journal
- Snapshot manager (para ordenar que se haga un snapshot)
Watcher
Descripción
Atiende a los cambios que se hayan realizado en el sistema (ya sea por eventos periódicos del planificador del propio sistema operativo, esto es cron, por cambios en archivos vigilados que se deban almacenar, usando inotify, o bien por orden del usuario). Asímismo ordena realizar backups.
Responsabilidades
- Escribir en el journal cuando se reciba un evento.
- Actualizar inotify.
Colaboraciones
Metadata Indexer (Indexador de metadatos)
Descripción
Indexa información útil para la posterior búsqueda de archivos en el sistema (tanto mediante su contenido como mediante metadatos).
Por ahora no desarrollada por estar fuera del alcance.
Help (ayuda)
Descripción
Muestra el manual de la aplicación.
Stats (Estadísticas)
Descripción
Recopila información útil sobre el uso de HD Lorean que permite elaborar estadísticas y predicciones (por ejemplo, sobre el uso del disco).
Por ahora no desarrollada por estar fuera del alcance.
Usuario
Descripción
Representa los datos del usuario y estadísticas sobre el mismo.
Por ahora no desarrollado por estar fuera del alcance.
Colaboraciones
Preferences (Diálogo de preferencias)
Descripción
Permite configurar la aplicación.
Responsabilidades
- Permitir la configuración de todo tipo de opciones, como indexar y/o excluir nuevos contenidos (carpetas, archivos, patrones…), periodicidad, uso de disco, etc.
Colaboraciones
Config wizard (Asistente de configuración)
Descripción
Permite fijar de manera sencilla y rápida las opciones de configuración más comunes del programa.
Por ahora no desarrollada por estar fuera del alcance.
Responsabilidades
- Obtener todos los datos de configuración necesarios.
- Almacenar esos cambios.
- Avisar al backend de que se han producido.
Colaboraciones
Config file manager (lector de archivo de configuración)
Descripción
Lee el archivo de configuración y lo traduce a parámetros de la aplicación.
Responsabilidades
- Validación de los datos.
- Escritura de opciones.
- Crear lista de archivos monitoreados.
Colaboraciones
En función de la implementación, con regexp parser.
Regexp parser (Parser de expresiones regulares).
Descripción
Interpreta expresiones regulares y ofrece funcionalidad basada en las mismas.
Inotify handler
Descripción
Interpreta las señales que envía inotify y ofrece una API para su manejo.
Responsabilidades
- Añadir o eliminar notificadores.
- Notificar los eventos recibidos.
Cron handler (manejador cron)
Descripción
Ofrece una API para interactuar con el demonio cron de planificación de tareas del sistema operativo.
D-Bus Manager
Descripción
Permite la comunicación vía paso de mensajes entre el frontend (o GUI) y el backend de la aplicación.
Responsabilidades
- Transformar los mensajes de D-Bus en órdenes internas del programa => enviar órdenes.
Colaboraciones
Battery monitor (control de la batería)
Descripción
Monitoriza el estado de la batería.
Parte de una factoría, aún no implementada en su conjunto.
HD Load monitor (Control de carga del disco duro)
Descripción
Monitoriza la carga del disco duro (nivel de operaciones de entrada/salida del sistema) a fin de proporcionar información al planificador sobre cuándo conviene efectuar las operaciones.
Por ahora no desarrollada por estar fuera del alcance.
Posiblemente parte de una factoría para unificar las interfaces.
CPU load monitor (control de carga de la CPU)
Descripción
Monitoriza el estado de carga de la CPU. Posiblemente parte de una factoría.
Por ahora no desarrollada por estar fuera del alcance.
Storage monitor (Monitor de almacenamiento)
Descripción
Supervisa el espacio de almacenamiento y proporciona información sobre el mismo. Posiblemente parte de una factoría.
Responsabilidades
- Comprobar si hay espacio en disco para escribir.
- Comprobar cuánto va a ocupar el backup que se almacene.
FUSE adapter (Adaptador FUSE)
Descripción
Clase que permite traducir la información almacenada en nuestro sistema de snapshots a una vista compatible con las operaciones de archivo estándar de linux.
Por ahora no desarrollada por estar fuera del alcance.
HAL manager (notificador de cambios en el hardware)
Descripción
También conocido como "HAL 9000", se encarga de notificar los cambios en las unidades conectadas al sistema que puedan afectar a los backups (por ejemplo si se extrae un disco sobre el que se está efectuando un backup).
Por ahora no desarrollada por estar fuera del alcance.
Device manager (administrador de dispositivos externos)
Descripción
Gestiona las copias de los snapshots de HD Lorean en medios de almacenamiento externos como discos ópticos o memorias externas.
Por ahora no desarrollada por estar fuera del alcance.
Optical Media manager (Administrador de la grabadora)
Descripción
Permite exportar snapshots a medios ópticos. Posiblemente parte de una factoría para unificar las interfaces.
External API (API pública del sistema)
Descripción
Exporta la funcionalidad de HD Lorean y permite su uso por parte de aplicaciones de terceros.
Por ahora no desarrollada por estar fuera del alcance.
UI (Interfaz de usuario)
Descripción
Implementa la interfaz de usuario.
Nautilus integration (Integración con Nautilus)
Descripción
Se encarga de la integración con Nautilus, a modo de adaptador entre la interfaz que ofrezca el API de Nautilus y la información que proporciona HD Lorean.
Por ahora no desarrollada por estar fuera del alcance.
Colaboraciones
Snapshot finder (Buscador de versiones)
Descripción
Busca entre las versiones almacenadas, posiblemente por contenido.
Por ahora no desarrollada por estar fuera del alcance.
Colaboraciones
Beagle integration (Integración con Beagle)
Descripción
Se encarga de la integración con Beagle para permitir al sistema de indexación de contenidos que indexe nuestros archivos y posiblemente integrarlos con sus resultados para realizar nuestras búsquedas.
Por ahora no desarrollada por estar fuera del alcance.
Interacción clases
Introducción
HD Lorean posee dos bloques bien diferenciados, uno es el backend y el otro el frontend o interfaz de usuario. El primero se encarga de la comunicación entre el hardware y las tecnologías que permiten la gestión de snapshots y la monitorización de ficheros. El otro se encarga de la comunicación con el usuario.
Entre ellos, pero formando parte de backend, se encuentra el módulo D-Bus Manager. Esta clase no se limita únicamente a encapsular d-bus sino que su misión es la de traducir los mensajes que reciba en un conjunto de órdenes internas de HD Lorean, las cuales enviará a los distintos módulos de la aplicación para que se realice el trabajo necesario.
Dentro del backend, a su vez, es posible distinguir dos subgrupos importantes que separan además dos cursos de colaboración frecuentes. Por un lado, el grupo formado por las clases config file manager, watcher, scheduler, inotify handler y cron handler forman la ruta de planificación y configuración. Por otro, el formado por snapshot manager y el conjunto de clases que utilizan como interfaz storage manager, que forman la ruta de gestión de snapshots.
Ruta de comunicación con el usuario
Gran parte de los casos de uso son desencadenados por el usuario y por tanto requieren la comunicación con HD Lorean. Para ello existen las clases pertenecientes al frontend. En general, el comportamiento de esta ruta es el siguiente.
- Frontend (alguna de sus clases: el diálogo de preferencias, el asistente de configuración, el visor de snapshots…).
- D-Bus Manager (recibe un mensaje con la tarea requerida por el usuario).
- Ruta de gestión de planificación y configuración
La sencillez de la ruta se apoya en la necesidad de mantener lo más separado posible la interfaz de usuario del backend.
Por último, existe también una ruta inversa (puede denominarse Ruta de comunicación con el usuario inversa) que permite que resultados internos de HD Lorean lleguen en forma de mensajes al frontend y este pueda exponerlos al usuario de alguna forma. Ésta es:
Ruta de comunicación con el usuario inversa
- Ruta de gestión de planificación y configuración (desde aquí se emite algún resultado que debe mostrarse al usuario).
- D-Bus Manager (dbus recibe el resultado y transmite un mensaje al frontend; alternativamente el frontend escucha mensajes del backend y presenta la información según sea necesario).
- Frontend.
Ruta de planificación y configuración
Como se dijo anteriormente, la ruta de planificación engloba las colaboraciones entre config-file-manager, watcher, scheduler, inotify-handler y cron-handler. Config file manager se encarga de la gestión del archivo de configuración, tanto de su versión física escrita en disco como de su versión virtual a la que el resto de módulos puede acceder para conocer diversos aspectos de la configuración. Los inotify handler y cron handler disparan eventos de inotify y cron que permiten monitorización de cambios en tiempo real y bajo planificación respectivamente. También disponen de acceso, a través de la clase clases, a una base de datos rápida o journal donde anotan las operaciones que han de realizarse próximamente, para poder planificarlas y reiniciarlas (a modo de transacciones semiatómicas) a fin de poder recuperarse de caídas del sistema o del programa, planificadas o no.
El scheduler por otro lado se encarga de gestionar y priorizar las órdenes que le llegan desde los disparadores o directamente desde el módulo de dbus, en función de la carga del sistema recogida de diversos monitores. También se comunica con la ruta de gestión de snapshots y atiende a sus resultados como veremos en breve.
La ruta de colaboraciones típica se muestra a continuación:
- D-Bus Manager (dbus tiene algún mensaje que convertir en órdenes)
- Config file manager (desde dbus se indica si ha de modificarse alguna configuración)
- Scheduler (desde dbus se informa al scheduler de alguna orden recibida desde el frontend)
- Ruta de gestión de snapshots
Desde aquí, dependiendo de la orden, el planificador accedería a la ruta de gestión de snapshots bien para ordenar la creación de un nuevo snapshot, bien para recuperar la información de alguno de los existentes, bien para eliminar algunos de ellos. A esta ruta la llamaremos ruta de usuario.
Como HD Lorean actúa en su mayor parte del tiempo sin necesidad de interacción por parte del usuario, incitado por inotify o cron, otra ruta alternativa probablemente más frecuente que la anterior es la siguiente:
- Cron handler o inotify handler (se ha producido algun cambio en un fichero o directorio que debe ser guardado, o se ha producido una señal planificada).
- Watcher (escritura al journal y tratamiento del suceso en función de si es cron o inotify)
- Scheduler (prioriza las señales recibidas de los módulos anteriores)
- Ruta de gestión de snapshots
A esta última ruta la llamaremos ruta de monitorización.
Igual que en el caso anterior, existe una ruta inversa que parte de los resultados de la ruta de gestión hasta llegar a dbus.
Ruta de monitorización inversa
- Ruta de gestión de snapshots (la ruta emite algún resultado en forma de objeto Snapshot)
- Snapshot manager (objeto con los resultados de la ruta de gestión)
- Scheduler (recibe el resultado de una orden)
- D-Bus Manager (recibe, si procede, los resultados un mensaje con los resultados de la operación).
Ruta de gestión de snapshots
Esta última ruta está formada por las clases snapshot manager, y el conjunto de storage manager. La primera, snapshot-manager, ofrece toda la funcionalidad relativa a la gestión de snapshots como la creación, eliminación o lectura de los mismos. Esta clase hace uso del conjunto storage manager que ofrece el nivel más bajo de funcionalidad a través de una API común. Los integrantes del módulo codifican esta API dependiendo de si el soporte de snapshots es un sistema de archivos (como LVM o ZFS), una aplicación externa (como xdelta3) o un modelo propio (como snapshot-core), para tratar de permitir el uso del sistema más eficiente según dónde se desplegase la aplicación, así como para obligarnos a separar ese componente crítico del resto de funcionalidad de la aplicación.
La clase Snapshot sirve de puente de comunicación entre Scheduler y la ruta de gestión que nos ocupa. La clase representa un Snapshot como resultado con capacidad para autoarchivarse dentro de una posible base de datos y con toda la información útil que fuese necesaria. Es el resultado de las operaciones de lectura, escritura o eliminación de la ruta de gestión.
La ruta de colaboraciones típica es la siguiente:
- Snapshot manager (la orden llega desde el scheduler)
- Storage manager (entre ellos, el más adecuado al medio)
- Snapshot manager (recibe la terminación del módulo que corresponda)
- Snapshot (se crea un objeto snapshot con información relevante asociada a la operación)
- Ruta de planificación y configuración
NOTA: En esta última se ha incluido el retorno inverso hasta la comunicación con la ruta de planificación. Hay que notar, que gran parte de estos retornos son implícitos debido al retorno de llamadas a función.
Rutas por casos de uso
Con todas las rutas especificadas, la elaboración de las colaboraciones por casos de uso es mucho más sencilla y clara.
Añadir una nueva carpeta a indexar
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y órdenes)
3. ruta de gestión de snapshots (creación del snapshot)
Borrar todas las versiones de un archivo
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y órdenes)
3. ruta de gestión de snapshots (Cambios a disco, bases de datos)
Borrar una versión de un archivo
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y órdenes)
3. ruta de gestión de snapshots (cambios a disco, bases de datos)
Configurar exclusión
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y órdenes para borrar el patrón; posible feedback al usuario)
3. ruta de gestión de snapshots (consultas a bases de datos, posiblemente borrar, devolver el feedback que sea necesario)
Configuración inicial
1. Ruta de comunicación con el usuario (mediante el asistente)
2. Ruta de planificación y configuración (cambio en la configuración y actualizar estado actual)
3. ruta de gestión de snapshots (si es necesario realizar trabajo o añadir algo)
Copiar al lado
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y órdenes)
3. ruta de gestión de snapshots (lectura y posible reconstrucción del snapshot)
Eliminar una carpeta a indexar
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (cambio en la configuración y actualizar estado actual)
3. ruta de gestión de snapshots (escrituras a disco y base de datos)
Sincronizar
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (registro en base de datos)
Exportar a un dispositivo externo
1. Ruta de comunicación con el usuario, posiblemente colaborando con HAL (en el backend, para detectar dispositivo)
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (registro en base de datos de dónde se encuentra la información; posible eliminación local para ahorrar espacio).
Importar de un dispositivo externo
1. Ruta de comunicación con el usuario, posiblemente colaborando con HAL (en el backend, para detectar dispositivo)
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (añadido a base de datos de la nueva información, comprobando inconsistencias; ver el caso de uso).
Guardar un backup
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (escrituras a disco y base de datos).
Guardar versiones automáticamente
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (posible actualización del estado).
Backup inicial
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (creación de estructuras de datos pertinentes; primer backup).
Sobreescribir última versión
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (lectura del snapshot, reconstrucción del mismo).
Buscar contenidos en backup
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (búsqueda en base de datos).
3.a Alternativamente, además usar clases.
Almacenamiento extra
No cubierto inicialmente por no ser en absoluto crítico.
Interrupción del backup
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes)
3. ruta de gestión de snapshots (según queden o no tareas pendientes)
Aplicaciones de terceros
No cubierta inicialmente al depender de un estado de desarrollo bastante más avanzado de la aplicación y no ser crítico. En cualquier caso el componente dbus ofrece un api de cara a otras interfaces de usuario para la aplicación.
Ver versiones de carpetas
1. Ruta de comunicación con el usuario
2. Ruta de planificación y configuración (órdenes, recibir información)
3. ruta de gestión de snapshots (lectura de los listados de base de datos)
UML
Definición
Lenguaje Unificado de Modelado (UML2, por sus siglas en inglés, Unified Modeling Language) es el lenguaje de modelado de sistemas de software más conocido y utilizado en la actualidad. Es un lenguaje gráfico para visualizar, especificar, construir y documentar un sistema de software. UML ofrece un estándar para describir un "plano" del sistema (modelo), incluyendo aspectos conceptuales tales como procesos de negocios y funciones del sistema, y aspectos concretos como expresiones de lenguajes de programación, esquemas de bases de datos y componentes de software reutilizables.
Lista de diagramas de clase
Diagrama de clases general
En este diagrama aparecen representadas todas las clases de la aplicación, incluso algunas que no han sido desarrolladas por estar fuera del alcance.
Diagrama de clases de GUI
En este diagrama aparecen representadas todas las clases de la interfaz gráfica del usuario (GUI).
Diagrama de clases del backend
En este diagrama aparecen representadas todas las clases que forman parte del backend (que incluye a los módulos Watcher, SnapshotManager, Logger y Database).
Diagrama de componentes
En él se muestran los componentes que forman la aplicación.
Diagrama de estado
Diagrama de estados del demonio HDLorean. En él se muestran los distintos estados en que se puede encontrar la aplicación.
Diagrama de despliegue
Diagrama de despliegue de la aplicación. Se muestran los distintos equipos que estarían implicados en el proceso, los clientes y el servidor.
Lista de diagramas de actividad
Diagrama de actividad de añadir carpeta a indexar.
El usuario elige una carpeta para añadir a las ya vigiladas. El caso para un archivo sería similar.
Diagrama de actividad de eliminar una carpeta indexada
El usuario elige una dejar de vigilar una carpeta previamente añadida. El caso para un archivo sería similar.
Diagrama de actividad de excluir una carpeta a indexar.
El usuario elige una carpeta para excluir de las vigiladas. El caso para un archivo sería similar.
Es útil para el caso en que se ha añadido una carpeta de la cual se quiere vigilar casi todo su contenido excepto una parte, que sería lo excuído.
Diagrama de actividad de borrar una versión.
El usuario elige borrar una versión.
Diagrama de actividad de restaurar una versión sin sobreescribir.
El usuario elige restaurar una versión sin borrar la actual.
Diagrama de actividad de crear una versión.
El usuario, cron o inotify crean una versión en ese momento.
Diagrama de actividad de preferencias.
El usuario decide cambiar una preferencia. Este es el caso general.
Lista de diagramas de secuencia
Diagrama de secuencia de makeSnapshot cuando lo llevan a cabo cron o inotify.
Cron o inotify detectan un evento que les indica que deben crear una versión.
Diagrama de secuencia de makeSnapshot cuando lo lleva a cabo el usuario.
El usuario elige crear una nueva versión.
Diagrama de secuencia de getPeriodically.
El usuario da al botón preferencias. La aplicación crea está ventana, para lo cual necesita recuperar los datos almacenados en el fichero de configuración. Este es un caso genérico.
Diagrama de secuencia de setPeriodically.
El usuario elige cambiar la periodicidad con que se harán las copias de seguridad. Ha de modificarse, por tanto, el fichero de configuración. En este caso, también habrá que actualizar el crontab.
Diagrama de secuencia de setEveryChange.
El usuario elige crear una nueva versión cada vez que se produzcan cambios (activar inotify). Es el caso genérico de cambiar una preferencia.
Diagrama de secuencia de restWithoutOverwrite.
El usuario elige recuperar una versión sin borrar la actual.
Diagrama de secuencia de scheduler.
Scheduler es el planificador del programa. Atendiendo a varios aspectos de la configuración elige el momento idóneo para llevar a cabo los distintos procesos del sistema, como puede ser crear nuevas versiones.
Patrones de diseño
Definición
En Ingeniería del Software, un patrón de diseño3 es una solución a un problema de diseño. Para que una solución sea considerada un patrón debe poseer ciertas características. Una de ellas es que debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. Otra es que debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.
Lista de patrones de diseño
Base de datos como Adapter
Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se pretendía usar pySqlite para gestionar las bases de datos, para lo cual se ha tenido que crear un adaptador que se adecue a las necesidades del programa.
Aplicabilidad: Este patrón se usa cuando:
- Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
- Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.
Así, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.
Estructura:
Participantes:
Target: Journal y History. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target.
Adaptee: PySqlite. Define una interfaz existente que necesita adaptarse.
Adapter: DatabaseWrapper. Adapta la interfaz de pySqlite a Journal y History.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Se ha creado una nueva clase que será el Adaptador (DatabaseWrapper), que extienda del componente existente (pySqlite) e implemente la interfaz obligatoria. De este modo, se tiene la funcionalidad que deseada y se cumple la condición de implementar la interfaz.
Del mismo modo se puede decir que Journal y History adaptan DatabaseWrapper para que un cliente, ya sea Watcher, Scheduler, o SnapshotManager, puedan hacer uso de él.
SnapshotManager como Abstract Factory
Nombre del patrón: Abstract Factory.
Clasificación del patrón: Creacional.
Intención: Crear diferentes familias de objetos.
Motivación: El patrón de diseño Abstract Factory aborda el problema de la creación de familias de objetos que comparten toda una serie de características comunes en los objetos que componen dichas familias.
Desde un principio, el equipo de desarrollo supo que se centraría en una factoría concreta, xDelta3, pero la intención de incluir nuevas familias, por ejemplo ZFS y LVM motivó a desarrollar este diseño para facilitar este futuro acoplamiento.
Aplicabilidad:
- El uso de este patrón está recomendado para situaciones en las que se tiene una familia de productos concretos y se preveé la inclusión de distintas familias de productos en un futuro.
- Un sistema debe ser independiente de cómo se crean, componen y representan sus productos.
- Un sistema debe ser configurado con una familia de productos entre varias.
- Una familia de objetos producto relacionados está diseñada para ser usada conjuntamente y es necesario hacer cumplir esa restricción.
- Se quiere proporcionar una biblioteca de clases producto y sólo se quiere revelar sus interfaces y no sus implementaciones.
Participantes: La estructura del patrón Abstract Factory es la siguiente:
Client: SnapshotManager. Sólo conoce la clases abstracta, IstorageWrapper, de los componentes.
AbstractFactory: Define métodos abstractos para crear instancias de clases Producto concretas.(IStorageWrapper)
ConcreteFactory: Implementan los métodos definidos por la superclase AbstractFactory para crear instancias de clases Producto concretas.
Métodos de creación de los productos genéricos en la interfaz de la fábrica (makeSnapshot, recoverSnapshot, recoverBackups…) que retornan una versión en un momento dado.
Son cada uno de los distintos wrappers (xDelta3Wrapper, LVMWrapper, ZFSWrapper) para crear el objeto de la tecnología pertinente.
Colaboraciones: Normalmente, una instancia de la clase ConcreteFactory es creada en tiempo de ejecución. Esta fábrica crea objetos de Producto concretos teniendo en cuenta una implementación particular. Para crear objetos de Producto diferentes, los clientes deberían usar una fábrica concreta distinta.
Al instanciar SnapshotManager se elige por parámetro la factoría a utilizar.
La clase abstracta AbstractFactory (IstorageWrapper) difiere la creación de objetos Producto a su subclase ConcreteFactory (los distintos wrappers).
Consecuencias:
- Aísla clases concretas: Este patrón ayuda a controlar los productos que una aplicación crea porque encapsula la responsabilidad y el proceso de creación de objetos y aísla a los clientes de las implementaciones.
- Se puede cambiar de familia de productos : Para cambiar de productos se debe cambiar de fábrica concreta.
- Promueve la consistencia entre productos: Cuando los productos son diseñados para trabajar en conjunto, es importante que en una aplicación se utilicen objetos de una familia a la vez.
- Desventaja: es difícil dar cabida a nuevos tipos de productos. Para crear nuevos tipos de productos es necesario crear una nueva fábrica concreta e implementar todas las operaciones que ofrece la superclase AbstractFactory.
Como conclusión se puede decir que este patrón está aconsejado cuando se prevé la inclusión de nuevas familias de productos, pero puede resultar contraproducente cuando se añaden nuevos productos o cambian los existentes.
Usos conocidos: Creación de familias de interfaces gráficos en las cuales los elementos (productos) del interfaz se mantienen constantes (por ejemplo labels, botones, cajas de texto …) pero el dibujado de dichos elementos puede delegarse en distintas familias (por ejemplo QT, GTK, etc) de forma que, en función de la fábrica seleccionada obtenemos unos botones u otros.
Patrones relacionados: Cuando se usa en conjunción con Singleton se crea una única fábrica, de modo que no habrá usos inconsistentes de los productos en el programa.
En este caso se usará el patrón Monostate en lugar del Singleton.
SnapshotManager como Façade
Nombre del patrón: Façade.
Clasificación del patrón: Estructural.
Intención: El patrón de diseño façade sirve para proveer de una interfaz unificada sencilla que haga de intermediaria entre un cliente y una interfaz o grupo de interfaces más complejas.
Motivación:
- Crear un intermediario y realizar llamadas a la biblioteca sólo o, sobre todo, a través de él.
- Crear una API intermedia, bien diseñada, que permita acceder a la funcionalidad de las demás.
- Un objetivo de diseño general es minimizar la comunicación y dependencias entre subsistemas. Un modo de lograrlo es introducir un objeto fachada que proporciona una interfaz unificada a la funcionalidad del subsistema.
Aplicabilidad: Úsese el patrón Façade cuando se desee:
- Proporcionar una interfaz simple para un subsistema complejo, evitando así que la mayoría de clientes tengan que conocer todas las clases internas del subsistema.
- Desacoplar un subsistema de sus clientes y otros subsistemas, promoviendo así la independencia entre subsistemas (y, por tanto, la portabilidad).
Participantes:
Façade: IstorageWrapper, sabe qué clases del subsistema son las responsables de llevar a cabo cada petición. Delega las peticiones de los clientes a los objetos apropiados del subsistema.
Clases del subsistema: Los distintos wrapper, que implementan la funcionalidad del subsistema.
Colaboraciones: IstorageWrapper es un interfaz que hace que los wrappers tengan una fachada común.
Consecuencias:
- Reduce el número de objetos con el que tienen que tratar los clientes, haciendo que el subsistema sea más fácil de usar.
- Promueve un bajo acoplamiento entre el subsistema y los clientes.
- Permite variar sus componentes sin que los clientes se vean afectados.
- Ayuda a estructurar en capas un sistema.
Implementación: Reducir el acoplamiento entre cliente y subsistema: Haciendo que el Façade sea una clase abstracta o una interfaz.
O configurándolo con diferentes objetos del subsistema.
Clases del subsistema públicas o privadas: Sería útil hacer que determinadas clases del subsistema fueran privadas, aunque pocos lenguajes lo permiten.
Patrones relacionados: Adapter.
SnapshotManager como Adapter
Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se quería usar xDelta3, ZFS y LVM para crear las versiones, para lo cual se ha tenido que crear un adaptador para cada una de ellas, de forma que cumplan la funcionalidad requerida.
Aplicabilidad: Este patrón se usa cuando:
- Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
- Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.
De esta forma, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.
Participantes:
Target: IStorageWrapper. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target. (SnapshotManager)
Adaptee: xDelta3, ZFS y LVM. Definen las interfaces existentes que necesitan adaptarse.
Adapter: xDelta3Wrapper, ZFSWrapper, LVMWrapper. Adaptan la interfaz de xDelta3, ZFS y LVM respectivamente.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo se tiene la funcionalidad deseada y se cumple la condición de implementar la interfaz.
Patrones relacionados: Façade.
SnapshotManager como Monostate
Nombre del patrón: Monostate.
Clasificación del patrón: Creacional.
Intención: Asegura que todas las instancias tengan un estado común.
Motivación: Se accede a las versiones desde distintos puntos, y el estado ha de ser el mismo para todas.
Aplicabilidad: Se utiliza cuando se debe tener el mismo estado independientemente del acceso.
Participantes:
Monostate: SnapshotManager.
Colaboraciones:
Consecuencias:
Implementación:
Patrones relacionados: Abstract Factory, Singleton.
Estructura del módulo SnapshotManager:
ConfigFileManager como Singleton
Nombre del patrón: Singleton.
Clasificación del patrón: Creacional.
Intención: Garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella
Motivación: Se accede a la configuración del programa desde distintos puntos, y siempre hemos de referirnos a la misma instancia.
Aplicabilidad: Se utiliza cuando deba haber exactamente una instancia de una clase y deba ser accesible a los clientes desde un punto de acceso conocido.
Las situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.
Estructura: Código que implementa el patrón, controlando una única instancia:
def __new__(self,watcher=None): # if the class has not been instanciated before do it # else return instance. if self.__instance is None: self.__configFilePath = os.getenv("HOME")+"/.hdlorean/config.cfg" self.__instance = object.__new__(self) if watcher is not None: self.__watcher = watcher return self.__instance
Participantes:
Singleton: ConfigFileManager, define un método instancia que permite que los clientes accedan a su única instancia. Instancia es un método de clase estático.
Colaboraciones: Los clientes acceden a una instancia de un Singleton exclusivamente a través de un método instancia de éste.
Consecuencias:
- Acceso controlado a la única instancia.
- Espacio de nombres reducido: no hay variables globales.
- Puede adaptarse para permitir más de una instancia.
Implementación: El patrón Singleton se implementa creando en una clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
Patrones relacionados: Abstract Factory, Monostate.
Demonio hdloreand como Singleton
Nombre del patrón: Singleton.
Clasificación del patrón: Creacional.
Intención: Garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella
Motivación: Se accede a la configuración del programa desde distintos puntos, y siempre hemos de referirnos a la misma instancia.
Aplicabilidad: Se utiliza cuando deba haber exactamente una instancia de una clase y deba ser accesible a los clientes desde un punto de acceso conocido.
Las situaciones más habituales de aplicación de este patrón son aquellas en las que dicha clase controla el acceso a un recurso físico único o cuando cierto tipo de datos debe estar disponible para todos los demás objetos de la aplicación.
Estructura: Código que implementa el patrón, controlando una única instancia:
def __new__(self): if self.__instance is None: self.__instance = object.__new__(self) db = Journal.Journal() db.createTable() self.__watcher = Watcher.Watcher() self.__scheduler = Scheduler.Scheduler() bp = BackendProxy.BackendProxy(self.__watcher,self.__scheduler,self.__instance) self.__cfm = ConfigFileManager.ConfigFileManager() return self.__instance
Participantes:
Singleton: hdloreand es el demonio de la aplicación, define un método instancia que permite que los clientes accedan a su única instancia. Instancia es un método de clase estático.
Colaboraciones: Los clientes acceden a una instancia de un Singleton exclusivamente a través de un método instancia de éste.
Consecuencias:
- Acceso controlado a la única instancia.
- Espacio de nombres reducido: no hay variables globales.
- Puede adaptarse para permitir más de una instancia.
Implementación: El patrón Singleton se implementa creando en una clase un método que crea una instancia del objeto sólo si todavía no existe alguna. Para asegurar que la clase no puede ser instanciada nuevamente se regula el alcance del constructor (con atributos como protegido o privado).
Patrones relacionados: Abstract Factory, Monostate.
PyInotifyHandler como Adapter
Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: El equipo quería usar Inotify para gestionar los eventos que ocurren sobre un archivo vigilado. Se investigó su uso y se decidió utilizar el módulo pyInotify, incluído en python.
Aplicabilidad: Este patrón se usa cuando:
- Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
- Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.
Estructura:
Participantes:
Target: PyinotifyHandler. Define la interfaz específica del dominio que Client usa.
Client: Watcher. Colabora con la conformación de objetos para la interfaz Target.
Adaptee: PyInotify. Define una interfaz existente que necesita adaptarse.
Adapter: Pyinotifyhandler. Adapta la interfaz del pyInotify.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Python tiene el módulo pyInotify, el cual nos ofrece una manera genérica y abstracta para manipular las funcionalidades de inotify. Se ha creado una nueva clase, Pyinotifyhandler, que prepara las estructuras de datos y configura inotify para que la aplicación, (Watcher en particular) pueda gestionar los eventos de forma acorde al objetivo del programa.
El sistema de paso de mensajes DBUS como Mediator
Nombre del patrón: Mediator.
Clasificación del patrón: De comportamiento.
Intención: Definir un objeto que encapsule como interactúa un conjunto de objetos.
Motivación: Cuando muchos objetos interactúan con otros objetos, se puede formar una estructura muy compleja, con objetos con muchas conexiones con otros objetos. En un caso extremo cada objeto puede conocer a todos los demás objetos. Para evitar esto el patrón Mediator encapsula el comportamiento de todo un conjunto de objetos en un solo objeto.
Aplicabilidad: Usar el patrón Mediator cuando:
- Un conjunto grande de objetos se comunica de una forma bien definida, pero compleja.
- Reutilizar un objeto se hace difícil por que se relaciona con muchos objetos.
- El comportamiento de muchos objetos que esta distribuido entre varias clases, puede resumirse en una o varias por subclasificación.
Participantes:
Mediator (BackendProxy y FrontendProxy): Implementa el comportamiento cooperativo entre los colegas (como se comunican entre ellos). Además los conoce y mantiene. Debido a las peculiaridades de DBUS, FrontendProxy recibe las peticiones de GUI y UI y se las transmite a BackendProxy, que es el encargado de enviarla al colega destinatario.
Colleagues: Cada colega conoce su mediador, y usa a este para comunicarse con otros colegas.
Colaboraciones: Los colegas envían y reciben requerimientos (requests) de un objeto mediador. El mediador implementa como se comunican los colegas.
Consecuencias: El patrón Mediator tiene los siguientes beneficios y desventajas:
- Desacopla a los colegas: el patrón Mediator promueve bajar el acoplamiento entre colegas. Se puede variar y reutilizar colegas y mediadores independientemente .
- Simplifica la comunicación entre objetos: Los objetos que se comunican de la forma "muchos a muchos" puede ser remplazada por una forma "uno a muchos" que es menos compleja y más elegante. Además esta forma de comunicación es más fácil de entender.
- Abstrae como los objetos cooperan: Haciendo a la mediación un concepto independiente y encapsulándolo en un objeto permite enfocar como los objetos interactúan. Esto ayuda a clarificar como los objetos se relacionan en un sistema.
- Centraliza el control: El mediador es el que se encarga de comunicar a los colegas, este puede ser muy complejo, difícil de entender y modificar.
Implementación:
Omitir la clase abstracta Mediator. No es necesario crear una clase abstracta Mediador cuando los objetos solo trabajan con un mediador. El acoplamiento abstracto de dicha clase permite que los objetos trabajen con diferentes subclases Mediator y viceversa.
Comunicación Objeto y Mediador. Los objetos se comunican su mediador cuanto tiene lugar un evento. Las clases de objetos cada vez que cambian su estado envían notificaciones al mediador. El mediador responde propagando los efectos de dichos eventos a los otros objetos.
Otra forma define al Mediador una interfaz de notificación especializada que permite a los objetos ser mas directos en su comunicación.
Usos conocidos: La arquitectura de Smalltalk/V para Windows usan objetos parecidos a mediadores entre los útiles de los diálogos.
Patrones relacionados: Un patrón muy parecido a éste es el Façade que se diferencia en que abstrae un sistema de objetos proporcionado una interfaz mas conveniente, utilizando un protocolo unidireccional (Fachada realiza solo peticiones a las clases del subsistema pero no a la inversa), mientras que el Mediator usa un protocolo mutidireccional.
Con el patrón Observer los objetos pueden comunicarse con el mediador.
El sistema de paso de mensajes DBUS como Observer
Nombre del patrón: Observer.
Clasificación del patrón: De comportamiento.
Intención: Definir una dependencia entre un objeto y un conjunto de ellos, de modo que los cambios en el primero se vean reflejados en los otros.
También conocido como: Spider.
Motivación: Frontend ha de recibir señales desde el backend que nos informen de que ha habido un cambio en algún archivo vigilado y así refrescar el treeview de GUI, por ejemplo.
Aplicabilidad: Se usa en casos en que se desea desacoplar la clase de los objetos clientes del objeto, aumentando la modularidad del lenguaje, así como evitar bucles de actualización (espera activa o polling).
Participantes:
Sujeto: Mantiene una lista de observadores y proporciona una interfaz para su gestión.
Observador: Define una interfaz para actualizar los objetos que deben reflejar los cambios en el sujeto.
Observador concreto: Mantiene una referencia a una sujeto concreto, almacenando parte de su estado e implementado la interfaz de Observador.
Colaboraciones: El Sujeto notifica a sus observadores de los cambios que sufre. Los observadores concretos solicitan a su sujeto los datos necesarios para mantener la consistencia con su nuevo estado.
Consecuencias:
- Permite reutilizar sujetos y observadores por separado.
- Permite añadir nuevos observadores sin modificar al sujeto o a otros observadores.
- Que el sujeto no informe a sus observadores de qué cambio ha sufrido permite mantener el acoplamiento en un nivel bajo, puesto que el observador sólo pide los datos del estado del sujeto que le interesan.
- Aunque el observador no esté interesado en ciertos cambios del sujeto será notificado de ellos.
- Se pueden realizar implementaciones con observadores que coordinan información sobre varios sujetos.
- Los cambios en el sujeto pueden ser solicitados por objetos que no son observadores.
Implementación: El backend generará una señal que recibirá el frontend, que previamente se había suscrito a ella.
Usos conocidos: Este patrón suele observarse en los marcos de interfaces gráficas orientados a objetos, en los que la forma de capturar los eventos es suscribir 'listeners' a los objetos que pueden disparar eventos.
El sistema de paso de mensajes DBUS usando Proxys
Nombre del patrón: Proxy.
Clasificación del patrón: Estructural.
Intención: Proporciona un representante o sustituto de otro objeto para controlar el acceso a éste.
Motivación: La interfaz gráfica y la consola necesitan interaccionar con el demonio de la aplicación. Para ello se crea un sustituto de los distintos objetos a los que se ha de acceder.
Aplicabilidad:
- Un proxy remoto proporciona un representante local de un objeto remoto.
- Un proxy virtual crea objetos costosos sólo cuando es necesario.
- Un proxy de protección controla el acceso al objeto original.
- Una referencia inteligente es un sustituto de un simple puntero que realiza alguna acción adicional:
- Contar el número de referencias al objeto original.
- Cargar un objeto persistente en memoria cuando es referenciado por vez primera.
- Bloquea el acceso al objeto real para que no sea modificado por otro objeto.
Participantes:
Client: Elemento que desea acceder al objeto.
Proxy: Mantiene una referencia para acceder al objeto original.
* Proporciona una interfaz idéntica a la del Subject.
* Controla el acceso al objeto y puede encargarse de crearlo, borrarlo…
BackendProxy proporciona un representante de distintos objetos reales.
Subject: Define el objeto real representado por el Proxy. Watcher, Scheduler, SnapshotManager.
Colaboraciones: Client accede a Subject a través de Proxy.
Patrones relacionados: Singleton.
BackendProxy y FrontendProxy como Singleton
Las clases BackendProxy y FrontendProxy están implementadas con el patrón Singleton para que se use siempre la misma instancia.
Estructura del sistema de paso de mensajes entre backend y frontend:
HDLogger como Adapter
Nombre del patrón: Adapter.
Clasificación del patrón: Estructural.
Intención: Se utiliza para transformar una interfaz en otra, de tal modo que una clase que no pudiera utilizar la primera, haga uso de ella a través de la segunda.
Convierte la interfaz de una clase en otra interfaz que el cliente espera. Adapter permite a las clases trabajar juntas, lo que de otra manera no podrían hacerlo debido a sus interfaces incompatibles.
También conocido como: Wrapper.
Motivación: Se quería hacer un módulo de logger para centralizar la recogida de información relevante para la depuración de problemas. Para ello se ha decidido adaptar el módulo de logger de python.
Aplicabilidad: Este patrón se usa cuando:
- Se desea usar una clase existente, y su interfaz no se iguala con la necesitada.
- Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, las clases no tienen necesariamente interfaces compatibles.
De esta forma, se han podido usar las tecnologías antes mencionadas, adaptándolas para que fuese posible trabajar con ellas en la aplicación.
Estructura:
Participantes:
Target: HDLogger. Define la interfaz específica del dominio que Client usa.
Client: Colabora con la conformación de objetos para la interfaz Target. Son todas aquellas clases que hacen uso del logger.
Adaptee: librería logging de Python. Define la librería que ha de adaptarse.
Adapter: HDLogger. Adaptan el logger de python.
Colaboraciones: Client llama a las operaciones sobre una instancia Adapter. De hecho, el adaptador llama a las operaciones de Adaptee que llevan a cabo el pedido.
Implementación: Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo se tiene la funcionalidad deseada y se cumple la condición de implementar la interfaz.
Especificación del formato de snapshots
Este documento pretende explicar, de cara a nuestros propios desarrolladores o a terceros, cómo HD Lorean organiza la información de las copias de seguridad y cómo operan las distintas operaciones disponibles.
Glosario
- backup: copia de seguridad de un archivo o directorio, bien sea en forma de copia o en forma de incremental.
- sistema de copias de seguridad: un sistema de copias de seguridad permite restaurar parte de un sistema de archivos a un estado anterior denominado snapshot.
- snapshot: unidad mínima del sistema de copias de seguridad. Formado por los ficheros necesarios para la recuperación de archivos y directorios en el instante de la creación del mismo además de otros ficheros de mantenimiento.
- snapshot-incremental: snapshot en el que los backup necesarios para la recuperación de archivos son diferenciales sobre el original, optimizando así el uso del espacio.
- snapshot-íntegro: snapshot en el que los backup necesarios para la recuperación de archivos son versiones íntegras de esos archivos en ese instante.
- snapshot-core: módulo encargado de la creación y mantenimeinto de los snapshot de HD-Lorean.
- timestamp: o sello de tiempo es una cadena de caracteres que representa el instante actual. Se utiliza como una marca única para identificar un instante de tiempo dado y puede actuar a varias resoluciones. La resolución puede ser anual si sólo se determina el año; mensual, si se determina además el mes; diaria, si añadimos el dia o incluso mayor si contabilizamos horas, minutos y segundos.
- versión: versión de un fichero o directorio en un instante dado. La lista de las versiones de un fichero nos indica como ha ido variando el contenido del fichero. La lista de las versiones de un directorio comprende cada versión de los ficheros y directorios que estén contenidos en ella. De esta manera, si se produce una nueva versión de un fichero, se produce una nueva versión del directorio que lo contiene, y del que contiene a éste, y así de forma recursiva hasta '/', por lo tanto, '/' cambia cuando se modifica cualquiera de los ficheros del sistema.
Timestamps
Un snapshot ocurre en un determinado momento caracterizado por una marca de tiempo o timestamp de la forma AAAA-MM-DD@HH:mm:SS+/-D [DST] donde:
- AAAA es el año de cuatro dígitos.
- MM es el número de mes dentro del año, de dos cifras.
- DD es el día del mes.
- HH es la hora del día en formato 24H.
- mm es el minuto de esa hora.
- SS es el segundo del minuto anterior.
- +/-D es la diferencia al tiempo global o GMT.
- DST es opcional e indica si se aplica el horario de verano.
En HD Lorean los timestamp no sólo se limitan a registrar el momento en el que sucede un snapshot sino que también los clasifican como veremos en el próximo apartado.
Directorio de snapshots
El directorio de almacenamiento de snapshots o sencillamente, directorio de snapshots, es el lugar indicado por el usuario donde se almacenan los snapshots. Por defecto, se encuentra en el home del usuario
/home/usuario/.hdlorean/snapshots/
En su interior se crea una estructura arbórea de carpetas basada en el timestamp del snapshot de la forma
./snapshots/AAAA/MM/DD/HH-mm-SS+D/
Y en último término se reconstruyen las rutas desde la raíz hasta cada uno de los archivos parte del snapshot y se almacenan en esta ubicación. Así, un snapshot del directorio /home/salvador/pruebas/ ocurrido el día 16 de Enerro de 2007 en España a las seis y media de la tarde se almacenaría bajo la siguiente ruta.
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/archivoA.txt.diff
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/archivoB.txt.int
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/archivoC.txt.int
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/archivoD.txt.diff
Los archivos almacenados en cada snapshot no son copias de los archivos originales, sino backups integros o diferenciales generados tal y como se describe a continuación.
Ficheros del snapshot
Una versión se realiza sobre un conjunto de archivos y directorios ubicados en algún punto del sistema. Buscando en versiones anteriores, HD Lorean comprueba para cada archivo la existencia de una versión íntegra y de encontrarlo, realiza un diferencial de la versión anterior respecto de la última integral y guarda este diferencial añadiendo la extensión .diff al archivo. Si no existe una versión íntegra o el diferencial supera en tamaño la versión actual del archivo, entonces HD Lorean copia el archivo tal cual y le añade la extensión .int indicando así que se trata de un backup íntegro del archivo.
Resumiendo, las extensiones posibles son:
- .diff se trata de una versión diferencial respecto de la versión integral más cercana en el pasado.
- .int se trata de una versión integral, o lo que es lo mismo, una copia del archivo en ese momento.
De esta manera, en el ejemplo anterior, eran diferenciales los archivos
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/archivoA.txt.diff
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/archivoD.txt.diff
Mientras que integrales eran
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/archivoB.txt.int
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/archivoC.txt.int
Además, por cada carpeta parte del snapshot como podrían se en el ejemplo las carpetas
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/
/home/usuario/.hdlorean/snapshots/2008/01/16/18-30-01+1/home/salvador/pruebas/mas pruebas/
HD Lorean almacena en su interior un fichero nombrado this.content con un listado (no recursivo) de los archivos y directorios (además de sus atributos como permisos y demás) del directorio en el instante de realizar el snapshot. Este fichero cobrará verdadera importancia a la hora de implementar las opciones de recuperación de snapshots.
El resto de datos útiles asociados a los ficheros, como los atributos se almacenan en una estructura externa o tabla de la base de datos.
Interacción con base de datos
Para entender esta sección se requiere un dominio avanzado del flujo de ejecución de HD Lorean.
HD Lorean emplea un método basado en journal para garantizar snapshots monolíticos y permitir recomenzar un snapshot en caso de falla durante el proceso. Para ello, el planificador deja constancia del comienzo de un nuevo snapshot mediante la inserción de un testigo en el journal. El testigo indica que todos los ficheros y directorios no escritos presentes en el journal anteriores al resgistro testigo forman parte del snapshot actual. Es interesante observar que los archivos pertenecientes a un snapshot en particular se encuentran en el journal en las filas delimitadas por ese snapshot (por delante) y el anterior (por detrás). El journal usa un testigo fantasma como centinela al comienzo de la tabla y así mantiene la regularidad.
Conforme los archivos sean procesados, el constructor de snapshots los marcará como escritos. Una vez todos los archivos hayan sido procesados, el testigo será marcado como finalizado y se dará por finalizada la operación.
En caso de fallo, el estado del journal nos ayudará a recuperarnos del error. Estos son los posibles casos:
- Testigo NO TERMINADO y presencia de archivos NO ESCRITOS - ha habido una falla durante el proceso. El módulo de recuperación de snapshots (parte del planificador) decide qué hacer con el snapshot. Por ejemplo, continuar o recomenzar.
- Testigo NO TERMINADO y todos los archivos ESCRITOS - ha habido una falla justo al final del proceso. El planificador vuelve a hacerse cargo, sin embargo se recomienda que el testigo se marque como TERMINADO y no se haga más.
- Testigo TERMINADO y todos los archivos ESCRITOS - snapshot completado con éxito.
- Testigo TERMINADO y presencia de archivos NO ESCRITOS - error, puesto que el testigo sólo se marca como escrito sólo si todos los archivos precedentes ya han sido escritos.
Operaciones sobre snapshots
Crear un snapshot para un conjunto de ficheros y directorios
A la hora de crear un fichero, el planificador enviará una lista de tuplas con los siguientes campos extraídos directamente del journal:
[<identificador del fichero o directorio cambiado, timestamp, operación sobre la ruta, ruta1, ruta2>]
El identificador es necesario para ver qué archivo estamos tratando. El timestamp refleja el momento en el que ocurrió la operación dada por el campo operación. Esta operación puede ser del tipo creación, borrado o modificación4. La ruta1 es la ruta sobre la que tiene lugar la operación y ruta2 la ignoraremos por ahora.
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | si | no |
- Generar el timestamp del snapshot
- Generar el directorio oportuno atendiendo al timestamp
- Para cada elemento de la lista
- Extraer atributos del fichero o directorio
- Reconstruir, dentro del directorio del snapshot, la ruta hasta el archivo (o directorio, incluido este último)
- Si es un fichero
- Si la operación es modificar o crear
- Buscar ultimo integral en base de datos
- Si no se encuentra -> copiar fichero actual como integral.
- Si sí se encuentra -> crear diferencial respecto del fichero integral.
- Si el diferencial es superior en tamaño al archivo original -> copiar fichero actual como integral.
- Generar el fichero con el listado de archivos y atributos del directorio padre del fichero
- Si la operación es modificar o crear
- Si es un directorio
- Si la operación es modificar
- Generar el fichero con el listado de archivos del directorio y atributos
- Si la operación es borrar
- Generar el fichero con el listado de archivos y atributos del directorio padre del directorio
- Si la operación es crear
- Obtener todos los contenidos (de manera recursiva) del directorio
- Llamar a este algoritmo para esa lista
- Obtener todos los contenidos (de manera recursiva) del directorio
- Si la operación es modificar
- Escribir (en el journal) en la entrada correspondiente al identificador, si la versión fue integral o diferencial y sustituir su timestamp por el del snapshot.
- Escribir los atributos en base de datos
- Marcar (en el journal) el fichero (o directorio) como procesado.
Crear un snapshot forzando el hecho de que todos los backups sean integrales
Ver consideraciones iniciales del apartado anterior.
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | si | no |
- Generar el timestamp del snapshot
- Generar el directorio oportuno atendiendo al timestamp
- Para cada elemento de la lista
- Extraer atributos del fichero o directorio
- Reconstruir, dentro del directorio del snapshot, la ruta hasta el archivo (o directorio, incluido este último)
- Si es un fichero
- Si la operación es modificar o crear
- Copiar el archivo como integral
- Generar el fichero con el listado de archivos y atributos del directorio padre del fichero
- Si la operación es modificar o crear
- Si es un directorio
- Si la operación es modificar
- Generar el fichero con el listado de archivos del directorio y atributos
- Si la operación es borrar
- Generar el fichero con el listado de archivos y atributos del directorio padre del directorio
- Si la operación es crear
- Obtener todos los contenidos (de manera recursiva) del directorio
- Llamar a este algoritmo para esa lista
- Obtener todos los contenidos (de manera recursiva) del directorio
- Si la operación es modificar
- Escribir (en el journal) en la entrada correspondiente al identificador, si la versión fue integral o diferencial y sustituir su timestamp por el del snapshot.
- Escribir los atributos en base de datos
- Marcar (en el journal) el fichero (o directorio) como procesado.
Recuperar un snapshot a una carpeta dada
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | no | sí |
Inicializamos carpeta actual a la carpeta del snapshot
- Obtener el listado de la carpeta actual.
- Por cada elemento de la lista anterior
- Si el elemento no se trata de '.' (ella misma) o '..' (su carpeta padre)
- Si es un directorio
- Llamar recursivamente a este método haciendo que carpeta actual sea el directorio
- Si es un fichero
- Directorio del fichero = Regenerar la ruta completa del fichero dentro del directorio destino
- Si es integral
- Copiar en el directorio del fichero eliminando la extensión .int
- Si es diferencial
- Buscar en BD el timestamp del último integral para este archivo (anterior o igual al timestamp pasado como parámetro)
- Si no existe
- No restaurar // Quiere decir que jamás fue administrado por HD Lorean
- Si sí existe
- Aplicar diferencial sobre el integral y copiar el resultado dentro del directorio del fichero.
- Si no existe
- Buscar en BD el timestamp del último integral para este archivo (anterior o igual al timestamp pasado como parámetro)
- Si es un directorio
- Si el elemento no se trata de '.' (ella misma) o '..' (su carpeta padre)
Borrar un snapshot
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | no | sí |
Versión 1
- Se envia el timestamp del snapshot seleccionado para borrar a la base de datos, preguntando si es integral o no. Y se le pide el timestamp del siguiente integral si existe.
- En caso de ser un diferencial, simplemente se borra.
- En caso de ser un integral, y si hay al menos un diferencial antes del timestamp del siguiente integral, se procede a montar el siguiente snapshot, el del timestamp+1, para dejarlo como nuevo integral. Se le pide que este nuevo integral se cambie de diferencial a integral en la base de datos. Tambien hay que ir reconstruyendo cada versión posterior, para hacer el diferencial respecto al nuevo integral, para todas las versiones hasta llegar al siguiente integral.
- Se le pide a la base de datos que borre el snapshot pedido de la lista de snapshots.
Versión 2
- Marcar en DB como prohibidos todas las versiones integrales para el timestamp dado
- Recuperar un listado desde DB de todas las versiones diferenciales del timestamp dado
- Para cada elemento de la lista
- Borrar el diferencial de disco
- Borrar las entradas de DB
Justificación por qué es mejor la versión 2
Borrar toda la línea temporal de un archivo
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | no | sí |
- Seleccionar en BD todos los timestamp para la ruta en cuestión.
- Por cada timestamp
- Encontrar el archivo en el sistema de archivos
- Borrar el archivo
- Eliminar los archivos de la base de datos
Recuperar el histórico de un fichero o directorio
Implementado en | ¿Pasa por el scheduler? | Usa threads |
---|---|---|
xdeltawrapper | no | sí |
- Si es un directorio
- Crear una tabla hash con clave un timestamp y valor una lista de cadenas
- Recuperar un listado de todos los timestamp para el directorio dado
- Por cada timestamp de la lista
- Añadir a la tabla hash con clave el timestamp actual, el contenido del fichero de contenidos del directorio para el timestamp actual
- Si es un fichero
- Crear una tabla hash con clave un timestamp y valor un enumerado con las operaciones posibles sobre un fichero (a saber y por ahora: CREADO, BORRADO, MODIFICADO)
- Recuperar una tabla desde BD con campos timestamp y operacion para el fichero dado
- Convertir esta tabla en la tabla hash
- Devolver la tabla hash
Informes de Investigación
Informe de investigación de UI
Glosario
- GUI: Graphic User Interface o interfaz gráfica de usuario, es la parte visual y de interacción con el usuario y la mayor parte del Frontend.
- Frontend : Proceso visible para el usuario posiblemente iniciado por él. Internamente se envían unas señales al Backend y los resultados devueltos son mostrados al usuario.
- Backend: Proceso oculto al usuario, pero que suele contener el núcleo del programa que se está desarrollando.
- Python: Lenguaje de programación desarrollado en 1991. Está diseñado siguiendo la filosofía de la legibilidad y prima el esfuerzo del programador sobre el del computador para reducir tiempos de desarrollo. Es un lenguaje multiparadigmático (funcional, orientado a objetos e imperativo) y posee un completo sistema dinámico de tipos. Es similar a Perl, Ruby, Scheme y Tcl.
- Pygtk5: Referencia a la biblioteca gráfica GTK para el lenguaje de programación Python.
- Gtk6: Biblioteca gráfica que se utiliza para desarrollar el entorno gráfico GNOME.
- GNOME7: GNOME es un entorno de escritorio para sistemas operativos de tipo Unix.
- D-Bus8: Sistema software que proporciona comunicación entre aplicaciones / procesos.
- Objeto: Objeto básico que utiliza DBus en el intercambio de información entre dos procesos.
- Proceso: Unidad de ejecución independiente en un sistema operativo.
- XML9: Siglas en inglés de eXtensible Markup Language («lenguaje de marcas extensible»). Es un metalenguaje extensible de etiquetas. Es un estándar para el intercambio de información estructurada entre diferentes plataformas de una manera segura, fiable y fácil. Además existen parsers en la amplia mayoría de lenguajes de programación.
- Handler: o 'manejador'. Función que captura una determinada señal o evento de ventana que puede ser implementada después como queramos. Por ejemplo, pulsar un botón.
- Widget: Pequeña aplicación o programa, cuyo objetivo es el de dar fácil acceso a funciones frecuentemente usadas y proveer de información visual.
- KDE10: Entorno de escritorio gráfico e infraestructura de desarrollo para sistemas Unix y, en particular, Linux.
- Libglade11: Biblioteca que efectúa un trabajo similar a las rutinas de salida de código fuente en el diseñador de interfaces GLADE12. Mientras que las rutinas GLADE obtenidas con código fuente C deben ser compiladas, libglade construye la interfaz desde un archivo XML (que es como GLADE guarda el código) en tiempo de ejecución. Esto puede permitir modificar la interfaz de usuario sin recompilar.
Descripción:
Nuestro módulo se encarga de darle al usuario una interfaz que le permita el manejo del programa, tratando de hacer lo más intuitiva posible la configuración del funcionamiento de HD Lorean, y la búsqueda y recuperación de ficheros de las copias de seguridad.
Abstracción al problema:
Nuestro trabajo consiste en crear una capa de abstracción entre el funcionamiento real del programa, que dista de ser intuitivo, y el usuario, ya que éste necesita una o varias interfaces que le resulten lo más cómodas, intuitivas y rápidas de usar.
Encontramos cuatro partes bien diferenciadas en nuestra labor:
- Uno o varios interfaces donde el usuario pueda ajustar las preferencias de funcionamiento de HD Lorean (dónde se almacenan las copias de seguridad, qué directorios tienen que tener copias de seguridad, etc. )
- Uno o varios interfaces donde el usuario pueda buscar versiones anteriores de sus ficheros y "traerlos" al presente, ya sea sobrescribiendo la versión actual, o como un fichero distinto.
- Conviene que el usuario pueda buscar también las versiones de los ficheros por su contenido, y no solo por su ruta o localización en el sistema de archivos.
- Comunicación instantánea con el backend del sistema.
Por otro lado, nos interesa que el programa sea lo más genérico, extensible y portable posible, de forma que no queremos cerrarnos a un único entorno de escritorio.
Abstracción a la solución
Por un lado, necesitamos crear un interfaz de preferencias, y por otro lado, un interfaz que permita navegar por las versiones de los archivos.
- Para la interfaz de preferencias, buscamos que el usuario pueda seleccionar diferentes opciones, decidir qué carpetas se vigilan, etc. Estas preferencias las tenemos que pasar al resto de módulos para que empiecen a comportarse según lo que el usuario decida. De forma básica, por ejemplo, podría servir un archivo de configuración que el usuario edite y agregue la ruta de las carpetas, o ponga los parámetros de las diferentes opciones. También podemos hacer una interfaz, donde nos bastaría con los típicos widgets de cualquier interfaz gráfica de usuario: botones, radiobutton, check lists, etc.
- Para la interfaz de navegación de versiones, podemos pensar diferentes paradigmas: desde un interfaz en 3D parecido al de Time Machine, como una interfaz modo texto donde le pasamos las opciones de la carpeta que queremos ver y la fecha y nos liste los contenidos, o lo más típico, que podría ser una vista de iconos, donde elijamos la fecha que queremos ver y nos aparezcan los iconos de los archivos dentro de la carpeta. Otra opción recogida en el planteamiento inicial del programa es una "barra de tiempo" como metáfora visual de avanzar y retroceder la fecha deseada.
- En cuanto a la búsqueda de contenidos en las versiones, queremos que el usuario pueda poner un texto y se le muestren los diferentes archivos que lo contienen, y si es sólo en una versión, que el usuario lo sepa. Esto podríamos hacerlo con una interfaz de línea de comandos y también con una interfaz gráfica.
- Para conseguir una comunicación entre los procesos de interfaz de usuario y el funcionamiento del programa instantánea, necesitamos comunicar dos procesos diferentes usando paso de mensajes.
En GNU/Linux existen varias posibilidades que se nos ofrecen para solucionar estos problemas, donde algunas de las posibilidades más típicas son:
- Interfaz de usuario en JAVA: librerías Swing/AWT
- Interfaz de usuario en GNOME: librerías GTK
- Interfaz de usuario en KDE: librerías Qt
- Interfaz de usuario en consola: CLI
Al decidirnos por el entorno de escritorio GNOME para nuestra práctica, ya que viene por defecto en gran parte de las distribuciones de linux, reducimos la lista anterior a: Java, GNOME y consola.
Por otro lado, habiendo trabajado con las librerías Swing y AWT en el pasado, decidimos que cualquier otra solución debe ser mejor. Complicaría el arrastrar y soltar ficheros y otras integraciones con el escritorio. Por tanto queda descartada a priori.
Teniendo en cuenta que GNOME usa de forma nativa las librerías GTK, usar estas librerías haría que el interfaz de usuario corra más rápido en este entorno.
También consideramos interesante que la práctica se pueda utilizar desde la consola, pues suele ser un interfaz más rápido de manejar, y los usuarios avanzados prefieren en muchos casos utilizar las aplicaciones de ésta manera. Además facilitará notablemente la depuración, e incluso la creación de tests automatizados para el software, durante su desarrollo.
En cuanto al paso de mensajes, tanto GNOME como KDE tienen sus respectivos sistemas llamados ORBit13 y DCOP, así como D-BUS, que sirve también para comunicarse con el sistema operativo y es el estándar en boga entre ambos sistemas desde hace algunos años.
Tecnologías investigadas:
Interfaz de preferencias:
La idea de tener un archivo de preferencias del que lean los otros módulos nos sirve tanto para el interfaz gráfico (que puede escribir en él), como para un interfaz modo texto (ya que el usuario únicamente tendría que editarlo, con cualquier editor de texto). El archivo de preferencias se ajustaría a los estándares de interoperabilidad presentes en http://freedesktop.org .
Por lo tanto pasamos a investigar cómo hacer el interfaz gráfico.
GTK+
Es un conjunto de bibliotecas o rutinas para desarrollar interfaces gráficas para el entorno de escritorio GNOME. Es software libre y multiplataforma, y este hecho se ajusta a las características de nuestro proyecto, aunque presumiblemente su capacidad multiplataforma no vamos a explotarla ya que HD Lorean es un software que utiliza características del núcleo de Linux y otros programas que no existen en otras plataformas. No obstante es posible que, en futuras fases de desarrollo, investiguemos la posibilidad de portarlo a otros unix como FreeBSD.
La herramienta gráfica que se usa para diseñar interfaces gráficas GTK se llama glade. Esta herramienta genera el código en C o en C++ que conecta los botones de la interfaz con las señales que tienen que generar en GTK. Sin embargo, investigando acerca de ella, encontramos un proyecto que nos abre aún más las puertas: Libglade.
Pygtk
PyGTK es un binding (referencias) de la biblioteca gráfica GTK para Python. PyGTK nos permite crear de un modo rápido y sencillo la GUI de la aplicación ya que se dispone de las librerías GTK para programar directamente para el entorno de escritorio GNOME.
PyGTK dispone de una API que resulta muy útil, ya que describe todas las funciones y los parámetros utilizados para éstas, de modo que resulta bastante fácil programar PyGTK partiendo con unos conocimientos bastante limitados de GTK, simplemente programando sobre Python y llamando a las funciones de las que se dispone. API de PyGTK
Libglade:
Es una librería que carga directamente el XML generado por glade, y conecta los botones del GUI con las señales adecuadas de GTK. La diferencia reside en lo siguiente:
- El código generado por glade en C o en C++ es un código que hay que compilar e integrar con nuestra práctica. Cuando cambiamos algo de nuestra práctica o la disposición de los botones del interfaz gráfico, hay que volver a compilar e integrar.
- Sin embargo, usando libglade, podemos cambiar el interfaz gráfico, mientras mantengamos las señales que generan, pues libglade se encarga de conectar estas señales. Por otro lado, el código del UI lo podemos escribir tanto en C/C++ como en Python (pues libglade está disponible para ambos), y lo único que hacemos es conectar las señales con los métodos que le correspondan.
Con esto tenemos lo que necesitamos para hacer la interfaz de preferencias. Podemos hacerla tanto en C como en Python, habiéndonos decantado por empezar las pruebas con Python, que nos permite hacerlo de una forma más rápida y dinámica.
Interfaz de navegación de versiones
Aquí también queremos mantener la misma idea que en la otra interfaz, por ello nos interesa conseguir un "interfaz primario" que sea capaz de transformarnos los queries a la base de datos y los snapshots en algo legible e interpretable tanto por un interfaz gráfico como por un interfaz modo texto. Esto facilitaría portar la "interfaz secundaria" a otra librería, a otro entorno de escritorio, pues la haría más extensible.
A priori encontramos dos posibilidades:
- Programar nosotros mismos un interfaz primario. Donde, por ejemplo, dando una fecha y una ruta de un archivo, devuelva la versión del archivo en esa fecha. Ésto permitiría luego hacer la versión modo texto, y crear la interfaz gráfica que permita moverse por el sistema de archivos y por la línea de tiempo para encontrar las versiones del archivo.
- Adaptar el interfaz primario a un paradigma ya existente, y para el que ya existan navegadores, es decir, un sistema de ficheros virtual. Se podría navegar por el directorio 2006, dentro de éste estarían los directorios de todos sus meses, dentro de éstos sus días… y en el último de estos directorios se encontrarían las carpetas indexadas en ese momento, con las copias respectivas de cada uno.
Hacemos comparaciones entre cada solución:
- Más o menos código: La primera solución obligaría a programar más, pues hay que programar tanto la "UI primaria" como la "UI secundaria" así como los "conectores" o plugins con el navegador de archivos de GNOME (nautilus), o crear nuestro propio navegador de versiones. La segunda opción permitiría programar menos, pues sólo se tendría que programar la UI primaria, ya existen navegadores de archivos tanto en modo texto como en GNOME, como en el resto de entornos de escritorio.
- Mejor o peor usabilidad: La primera solución permitiría crear un interfaz de usuario más usable y más intuitivo, pues podríamos definirlo y diseñarlo en relación a los objetivos y añadir las opciones que necesitemos.
Así mismo existen diferentes tecnologías que permiten transformar casi cualquier cosa en un sistema de ficheros virtual:
- GnomeVFS: Provee de una capa de abstracción para la lectura, escritura y ejecución de ficheros. Lo utilizan principalmente el navegador de ficheros Nautilus y otras aplicaciones GNOME. Actualmente se está reescribiendo entre otras cosas para que permita montar particiones de FUSE.
- FUSE: Módulo del kernel de unix que permite a los usuarios sin privilegios crear sus propios sistemas de ficheros sin necesidad de escribir un módulo de kernel. FUSE es particularmente útil para escribir sistemas de ficheros virtuales, cualquier recurso disponible para la implementación de FUSE puede ser exportado como un sistema de ficheros.
Interfaz de búsqueda por contenidos
Como en el caso anterior, se puede escribir un nuevo buscador de contenidos, lo cual obligaría a realizar también un indexador de contenidos, o utilizar uno que ya exista.
En el caso de utilizar uno que ya exista, habría que ampliarlo indicándole cómo tiene que indexar las copias de seguridad de los archivos, pues estos buscadores indexan ficheros, pero HD Lorean no trata las copias de seguridad como copias íntegras de los ficheros.
Entre los existentes, en GNU/Linux nos encontramos con la posibilidad de usar Tracker14 o Beagle15:
- Tracker: Escrito en C, muy rápido. A parte de permitirnos buscar los contenidos de los ficheros, permite etiquetar los ficheros. No tiene definida una api, y no encontramos fácil la posibilidad de hacer plugins para describirle cómo indexar nuestros datos, pues no tiene una buena documentación.
- Beagle: Escrito en C#, algo más lento y pesado que tracker. Tiene un sistema desarrollado de plugins a través del cual podríamos indicarle como indexar nuestros datos, y tiene una buena documentación.
Por otro lado, si se opta por hacer un sistema de archivos virtual, se podría hacer que estos buscadores indexaran este sistema de archivos, y por lo tanto ahorraría el trabajo de hacer plugins para ellos. Tampoco tendríamos que elegir entre ellos, porque los dos servirían.
Comunicación entre procesos (Frontend y Backend)
Para la comunicación entre el Frontend y el Backend interesa un sistema que ya esté desarrollado, pues es una parte bastante difícil, que tiene que estar bien diseñada, y que puede llevar mucho tiempo. Actualmente existen en GNU/Linux varios sistemas dedicados a ésto que funcionan perfectamente. Por otro lado interesa utilizar uno que esté bastante extendido, pues estos sistemas permiten no sólo comunicaciones dentro de nuestra aplicación, sino también con otras aplicaciones.
- D-BUS16: El sistema de comunicación entre procesos más extendido. Tiene wrappers tanto paraC/C++ y Python, con lo que no nos obliga a cambiar los lenguajes de programación.
- ORBit (CORBA17): Aplicación de comunicación interprocesos actualmente en desuso. Fue un proyecto muy ambicioso. Atilizado antes que Dbus para la comunicación interprocesos en GNOME. Es un software muy complejo y demasiado difícil de usar, tanto es así que GNOME lo sustituyó en su día por D-BUS.
- DCOP18: Aplicación de comunicación interprocesos extensamente utilizada en KDE, otro de los principales entornos de escritorio de Linux. Actualmente también está dejando de utilizarse en favor de D-BUS.
Se descarta ORBit (CORBA) y DCOP por tanto. Aunque son tecnologías que podrían suplir perfectamente a DBus, actualmente están dejando de utilizarse, perdiéndose compatibilidad con el resto de aplicaciones de escritorio de Linux al usarlas.
Así mismo, si se decide por utilizar un sistema de archivos virtual, puede servir como forma de pasar archivos "completos" al frontend desde el backend, lo cual simplificaría la comunicación pues basta con pasar una ruta y usar operaciones de copia estándar.
Ejemplos de las tecnologías
Glade + Python
Fragmento de código XML de un archivo .glade:
<glade-interface>
<widget class="GtkAboutDialog" id="About">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">About HD Lorean</property>
<property name="resizable">False</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="has_separator">False</property>
<property name="program_name">HD Lorean</property>
<property name="version">0.01</property>
<property name="comments" translatable="yes">
Ejemplo de código Python y libglade:
self.gladefile="dbusgui.glade"
self.wTree = gtk.glade.XML (self.gladefile)
self.wTree = gtk.glade.XML (self.gladefile)
self.texto = self.wTree.get_widget('textview1')
En éste ejemplo podemos observar como se asocia un archivo glade XML a un atributo de un objeto de una clase Python.
Glade es una herramienta gráfica que permite la creación de interfaces gráficos simplemente arrastrando botones, paneles de texto, y demás elementos sobre la ventana en la que estamos trabajando.
Es una herramienta muy útil ya que además permite asociar eventos de los diferentes elementos gráficos de la ventana a métodos y funciones del código en Python.
Ejemplo de código Python:
dic = { "on_BSalir_clicked" : self.Salir,
"on_BMostrar_clicked" : self.Mostrar
}
Este ejemplo de código Python nos muestra la forma de conectar los eventos creados en Glade asociados a un elemento gráfico con funciones del código generado en Python.
FUSE
Extracto de un ejemplo donde se lee un directorio usando fuse:
static int leer_directorio ( const char *path, void *buffer, fuse_fill_dir_t rellenar, off_t offset, struct fuse_file_info *info )
{
/* En caso de que no estemos haciendo referencia al directorio principal devolvemos -ENOENT,
esto provocará que la lectura de directorio devuelva -1 y errno se establezca en ENOENT. */
if ( strcmp ( path, "/" ) )
return -ENOENT;
/* Rellenamos el buffer conteniendo el listado de directorio, las entradas obligadas son . y ..
Como notarán a archivo1 y a archivo2 le sumamos 1, esto es para saltarse la primer / */
rellenar ( buffer, ".", NULL, 0 );
rellenar ( buffer, "..", NULL, 0 );
rellenar ( buffer, archivo1 + 1, NULL, 0 );
rellenar ( buffer, archivo2 + 1, NULL, 0 );
return 0; /* Todo salió bien :) */
}
Fuente
Ejemplos de primitivas de la librería FUSE extraídas de su página de documentación:
#define fuse_main ( argc, argv, op, user_data ) fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
#define FUSE_REGISTER_MODULE ( name, factory_ )
#Donde se define name_:
static __attribute__((constructor)) void name_ ## _register(void) \
{ \
static struct fuse_module mod = { #name_, factory_, NULL, NULL, 0 }; \
fuse_register_module(&mod); \
}
Dbus
Dbus es una aplicación que se utiliza para comunicar varios procesos entre sí. Para utilizarlo basta con importar la librería dbus (import dbus en python por ejemplo).
Se podría pensar en dbus como si fuera una aplicación cliente-servidor bidireccional. Una parte se programa con objetos/rutas que enlazan esa ruta con unos métodos del módulo en el que están presente. La otra parte permite conectar esos objetos/rutas para poder utilizarlos en el módulo destino.
Esto permite en nuestro caso comunicar la gui con el backend, que son procesos diferentes pero necesitan información uno del otro. Para ello tenemos que crear objetos dbus y funciones para la conexión con otros objetos en ambos módulos.
Ejemplo:
bus = dbus.SessionBus()
rb = bus.get_object('org.gnome.Rhythmbox','/org/gnome/Rhythmbox/Player')
player = dbus.Interface(rb,'org.gnome.Rhythmbox.Player')
playing = player.getPlaying()
Este ejemplo nos muestra como realizar una conexión desde un proceso cualquiera con Rhythmbox, que contiene varios objetos Dbus que podemos utilizar. Simplemente hay que indicar la interface y el objeto, que viene dado mediante el espacio de nombres /org/gnome/Rhythmbox/Player para poder empezar a utilizar funciones que nos ofrece ese objeto.
Aquí podemos ver el resultado final de una aplicación ejemplo creada para obtener información diversa de la música que esta tocando en un momento determinado la aplicación Rhythmbox.
DBus es una tecnología en auge en los últimos tiempos, quiere convertirse en un standard en la comunicación interprocesos.
Conclusión
Haremos la interfaz de preferencias basada en un fichero de texto configurable también a través de un interfaz en glade, usando libglade y python.
Asimismo, en cuanto al navegador de versiones y el buscador de contenidos, se solucionarán ambas usando un sistema de archivos virtual con FUSE. En caso de que estas interfaces quedaran pobres navegando directamente sobre el sistema de archivos virtual con los navegadores de ficheros habituales, se hará una interfaz más intuitiva modo texto y otra para GNOME.
En principio no se tocará para nada beagle ni tracker para que funcionen si hacemos el sistema de archivos virtual, por esto no hay ejemplo de éstas tecnologías, pero si no es posible hacer el sistema de ficheros virtual, tendremos que hacer un plugin para alguno de ellos al menos. En ese caso nos decantaríamos por Beagle.
En cuanto al sistema de comunicación entre procesos, vemos que DBus se está convirtiendo en un standard dentro de la comunicación interprocesos en GNU/Linux. Por lo tanto si queremos que HD Lorean pueda en un futuro comunicarse con otras aplicaciones necesitamos utilizarlo.
Comentarios:
Informe de investigación del Watcher
Glosario
Thread safe: Programa multihilo que cumple ciertas propiedades, como exclusión mutua, acceso compartido y consistencia de datos
Reentrante: Un programa o función es reentrante cuando puede ser ejecutado con seguridad de forma concurrente, es decir, puede ser llamado otra vez cuando está ejecutándose y funcionar correctamente en todas las llamadas
Evento de cambio: cualquier suceso de los notificados por inotify (
SGBD: Sistema de Gestión de Bases de Datos. En general, cualquier aplicación de bases de datos como por ejemplo mysql.
Descripción del módulo watcher
El módulo watcher se encarga de la monitorización de cambios de HD Lorean, así como de la especificación y control de los ficheros que se encuentran bajo monitorización.
Las funcionalidades más representativas de watcher son:
- Informar de los cambios ocurridos en un fichero/directorio monitorizado.
- Extraer de la configuración las reglas que el usuario especifica sobre los ficheros que quiere vigilar y localizarlos en el sistema.
- Garantizar la concurrencia en las notificaciones de cambios y en el acceso a las estructuras que mantienen los ficheros vigilados.
- Garantizar checkpoints a partir de los que el sistema puede recuperarse ante un imprevisto.
Abstracción al problema
El objetivo de watcher es obtener de la configuración los archivos a monitorizar, crear estructuras thread safe para consultar y modificar dichos archivos vigilados, recopilar los cambios que suceden en los ficheros vigilados y mantenerlos a salvo de una caída del sistema, así como notificar a snapshot-core para que se escriban a disco.
Abstracción a la solución
Una vez definidas las reglas con las que el usuario introducirá los archivos que desea vigilar, se deben encontrar métodos que resuelvan los siguientes problemas:
- Extraer de las reglas introducidas por el usuario un listado de archivos a vigilar.
- Conseguir monitorizar todos los cambios en dichos archivos sin sobrecargar el sistema.
- Garantizar la exclusión mutua de las distintas partes de la aplicación en el acceso a las estructuras de archivos vigilados y de eventos de cambio.
- Garantizar la recuperación de HD Lorean en caso de caída o corte.
Las soluciones ideales a los distintos problemas serían las siguientes:
- Extraer de las reglas introducidas por el usuario un listado de archivos a vigilar.
- A la entrada llega la ruta del fichero de configuración
- Localizar patrones en las reglas del usuario aplicables a los archivos reales del sistema.
- Generar una estructura dinámica que los almacene y permita las operaciones básicas sobre ella.
- Conseguir monitorizar todos los cambios en dichos archivos sin sobrecargar el sistema.
- A la entrada llega el listado de ficheros a vigilar.
- Esperar distintos eventos sobre el conjunto de ficheros vigilados.
- Notificar de los eventos.
- Garantizar la exclusión mutua de las distintas partes de la aplicación en el acceso a las estructuras de archivos vigilados y de eventos de cambio.
- Se solicita el acceso concurrente a las estructuras del módulo.
- Determinar quién solicitó antes el acceso y evitar que el resto de solicitudes progresen hasta que la actual finalice.
- Garantizar la recuperación de HD Lorean en caso de caída o corte.
- A la entrada llega la notificación de un evento de cambio.
- Escribir rápidamente los rasgos esenciales del cambio en estructuras de inserción eficiente y atómica para evitar corrupción o pérdida de información.
- Manejar las peticiones de acceso a la estructura de recuperación en caso de caída.
Búsqueda de patrones en archivos de configuración
Permitir al usuario una mayor flexibilidad y potencia a la hora de describir las reglas que designan los archivos a monitorizar (exclusión de tipos de fichero o patrones de nombres), complica la labor de obtener la información del fichero de configuración, localizando los archivos en el árbol de directorios del sistema. Para solventar este problema, la solución más escalable y completa es el uso de las bien conocidas expresiones regulares.
La inclusión de expresiones regulares en la aplicación, más allá del módulo watcher, permite validar la configuración y los parámetros introducidos por el usuario de manera sencilla.
Monitorización de cambios en archivos
Para la monitorización de cambios se deben tener en cuenta la lista de directorios y ficheros a monitorizar, así como la "lista negra"(ficheros que no deseamos vigilar).
Con esta información se prepararán las estructuras de datos pertinentes para poder saber si los eventos producidos en un determinado fichero o directorio son relevantes o no (nótese que solo con las listas anteriores saber esto no es trivial, ya que los directorios se monitorizarán de forma recursiva y ficheros de la lista negra pueden estar en directorios que si deseamos monitorizar -obviamente los eventos producidos en ficheros que estén en esta situación deben ser ignorados-)
Los eventos relevantes producidos por los elementos monitorizados serán encolados y se proporcionará una interfaz para que otros módulos puedan acceder a esta información garantizando la consistencia
Garantía de consistencia
Watcher debe garantizar el acceso concurrente a las estructuras que soportan los ficheros bajo monitorización, así como la recepción y tratamiento en el orden adecuado de eventos de cambio concurrentes. Abordaremos el problema mediante la creación de diferentes threads que manejen cada petición y el uso de métodos de bloqueo explícitos entre los distintos threads para asegurar la consistencia de las estructuras de datos.
Garantía de recuperación frente a imprevistos
Watcher debe asegurar que un corte inesperado del flujo eléctrico o el cierre de HD Lorean no provoque la pérdida de los cambios acontecidos inmediatamente antes de la interrupción. Debe proveer checkpoints a partir de los cuales el sistema pueda continuar trabajando justo donde lo dejó la vez anterior, permitiendo de este modo interrumpir HD Lorean cuando el usuario lo desee. Se abordará el problema mediante la creación de una pequeña base de datos que garantice atomicidad y eficiencia de escritura, de tal forma que los eventos de cambio puedan ser escritos temporalmente de manera rápida en este journal con la información necesaria para continuar desde él en caso de caída.
Tecnologías empleadas
A continuación se describe brevemente cada tecnología, se otorga un ejemplo de uso y se destacan sus aspectos positivos y negativos.
Expresiones Regulares
Se han investigado las diferentes opciones para manejar expresiones regulares dentro de la aplicación. Se ha descartado desde un primer momento el uso de Perl y su estándar de expresiones regulares por complicar el diseño de la aplicación y por introducir un nuevo lenguaje que aprender y manejar. Dentro de C/C++ se han investigado dos tecnologías:
POSIX.2 Regular Expressions (GNU C Library)
Esta fue la primera opción investigada. Compatibles con el estándar POSIX, la librería de C ofrece toda la potencia de las expresiones regulares que necesita HD Lorean. Sin embargo el trabajo con esta librería es farragoso y de bajo nivel. Como se ve en el siguiente ejemplo de Ben Tindale, transportar estas librerías a HD Lorean supondría la creación de una clase envoltorio para ocultar y encapsular al resto de la aplicación el manejo interno de las expresiones regulares. Debido a estos inconvenientes se optó por seguir investigando.
/* mygrep: A simple example to show how regular */ /* expressions are used in the Gnu C library. */ /* See the Gnu documentation for information about */ /* regular expressions: http://www.gnu.org */ /* Usage: ./mygrep -f <filename> -p <pattern> */ /* author: Ben Tindale <ben@bluesat.unsw.edu.au> */ /* (C) 2000 Ben Tindale */ #include <stdio.h> #include <stdlib.h> #include <regex.h> /* Provides regular expression matching */ #include <strings.h> /* String utillity functions */ #include <errno.h> /* Handle errors */ int match_patterns(regex_t *r, FILE *FH) { char line[1024]; int line_no=1; /* Count the line numbers for nice output */ size_t no_sub = r->re_nsub+1; /* How many matches are there in a line? */ regmatch_t *result; char *cp; /* Char pointer */ int start=0; /* The offset from the beginning of the line */ if((result = (regmatch_t *) malloc(sizeof(regmatch_t) * no_sub))==0) { perror("No more memory - aaaagh! (Die kicking and screaming.)"); exit(EXIT_FAILURE); } while((cp=fgets(line, 1023, FH))!=NULL) { while(regexec(r, line+start, no_sub, result, 0)==0) /* Found a match */ { printf("Line %d: %s", line_no, line); start +=result->rm_eo; /* Update the offset */ } line_no++; } return EXIT_SUCCESS; } int do_regex(regex_t *r, char *p, char *f) { int err_no=0; /* For regerror() */ FILE *FH=NULL; /* File handle */ if((err_no=regcomp(r, p, 0))!=0) /* Compile the regex */ { size_t length; char *buffer; length = regerror (err_no, r, NULL, 0); buffer = malloc(length); regerror (err_no, r, buffer, length); fprintf(stderr, "%s\n", buffer); /* Print the error */ free(buffer); regfree(r); return EXIT_FAILURE; } if((FH=fopen(f, "r"))==NULL) /* Open the file to scan */ { fprintf (stderr, "Couldn't open file %s; %s\n", f, strerror (errno)); exit(EXIT_FAILURE); } match_patterns(r, FH); /* Pass the pattern and the file to be scanned */ regfree(r); /* Free the regular expression data structure */ free(r); fclose(FH); return EXIT_SUCCESS; } void usage(void) { printf("\n\tmygrep: A simple example to show how regular \texpressions are used in the Gnu C library. \tSee the Gnu documentation for information about \tregular expressions: http://www.gnu.org\n \tUsage: ./mygrep -f <filename> -p <pattern>\n\n"); } int main(int argc, char **argv) { int c; char *filename=NULL; char *pattern=NULL; extern char *optarg; extern int optind, opterr, optopt; regex_t *regex; int err_no; /* Make space for the regular expression */ regex = (regex_t *) malloc(sizeof(regex_t)); memset(regex, 0, sizeof(regex_t)); if(argc==1) { usage(); return(EXIT_SUCCESS); } while((c=getopt(argc, argv, "f:p:"))!= EOF) { switch(c) { case 'f': filename=optarg; break; case 'p': pattern=optarg; break; case '?': fprintf (stderr, "Unknown option `-%c'.\n", optopt); usage(); return EXIT_FAILURE; default: usage(); return EXIT_SUCCESS; } } if((err_no=do_regex(regex, pattern, filename))!=EXIT_SUCCESS) { return EXIT_FAILURE; } return EXIT_SUCCESS; }
Librería Boost.Regexp19 (C++)
La ventaja inicial de la librería Boost.Regexp es su orientación a objetos. Se tuvo especial cuidado en que la librería ofreciera compatibilidad absoluta con el estándar POSIX de sintaxis en expresiones regulares. Como beneficio adicional, la librería es compatible con otras librerías de expresiones regulares como la de GNU, BSD4 y de manera algo limitada con Perl 5. Cubre con creces las necesidades de HD Lorean y facilita el manejo de las expresiones regulares con respecto a la librería en C. Otra funcionalidad destacable y que marca la diferencia con otras opciones es que Boost.Regexp es thread safe. Los algoritmos de encaje de patrones regex_match, regex_search, regex_grep, regex_format y regex_merge son todos reentrantes y thread safe. Es importante destacar también que la librería hace uso de excepciones, ofreciendo una mejor forma (más adaptada a C++) de control del flujo de programa y posibles errores en el uso de las expresiones regulares.
Se ha comprobado también que la librería pueda ser instalada en el sistema y/o compilada con el resto de la aplicación, a fin de ofrecer compatibilidad con los sistemas de los laboratorios.
En el siguiente ejemplo se muestra el uso a pequeña escala de esta librería:
1 #include <iostream> 2 #include <string> 3 #include <boost/regex.hpp> // Boost.Regex lib 4 5 using namespace std; 6 7 int main( ) { 8 9 std::string s, sre; 10 boost::regex re; 11 bool end = false; 12 while(!end){ 13 cout << "Expression: "; 14 cin >> sre; 15 if (sre == "quit"){ 16 end = true; 17 } 18 if (!end){ 19 cout << "String: "; 20 cin >> s; 21 try{ 22 // Set up the regular expression for case-insensitivity 23 re.assign(sre, boost::regex_constants::icase); 24 } 25 catch (boost::regex_error& e){ 26 cout << sre << " is not a valid regular expression: \""<< e.what() << "\"" << endl; 27 } 28 if (boost::regex_match(s, re)){ 29 cout << re << " matches " << s << endl; 30 } 31 } 32 } 33 }
Conclusiones: El uso de la librería Boost.RegExp ofrece toda la funcionalidad necesaria, con una simplicidad elevada. Pese a no estar incluida entre las librerías del lenguaje, el inconveniente de tener que añadirla a la aplicación pesa menos que las ventajas (thread safe, estándar POSIX, excepciones, encapsulamiento) que ofrece frente a la librería de C. Se ha decidido utilizar esta última por las razones ya enumeradas.
Monitorización en tiempo real
Para la implementación de esta funcionalidad usaremos inotify-cxx20, que ofrece una interfaz orientada a objetos para trabajar con inotify
Inotify
Inotify es un subsistema del kernel de Linux que permite conocer en tiempo real diversos eventos producidos en ficheros y directorios.
Inotify-cxx
Inotify-cxx es una interfaz para trabajar con inotify en C++ con las ventajas de la programación orientada a objetos y que elimina ciertos aspectos "oscuros" de trabajar directamente con la interfaz de C de inotify (como por ejemplo, tratar a inotify como un fichero).
Opciones investigadas
Inotify-cxx
Ejemplo de uso:
Vamos a monitorizar el borrado de un directorio. Para ello creamos un objeto InotifyWatch que contiene la información necesaria para controlar los eventos (la ruta del directorio y la máscara del evento a notificar).
Ese objeto se añade a un objeto Inotify que es quien se encarga de notificar los eventos, por medio de objetos del tipo InotifyEvent, en los que se almacena, entre otras cosas, quien provocó la notificación y por qué motivo
int main(){ InotifyWatch* watch; watch = new InotifyWatch("/home/user/prueba/",IN_DELETE); InotifyWatch* fichero; Inotify* n = new Inotify(); InotifyEvent* pEvt; pEvt = new InotifyEvent(); n->Add(watch); n->WaitForEvents(); n->GetEvent (pEvt); if(pEvt->IsType(IN_DELETE)) cout << "Borrado Directorio, saliendo" << '\n'; }
Conclusiones: Nos hemos limitado a mostrar la librería inotify-cxx ya que ofece la misma funcionalidad que la librería inotify(que era la primera opción que nos planteamos para resolver este problema) pero con la ventajas que ofrece la programación orientada a objetos y porque es una solución de más alto nivel (lo que en inotify-cxx son objetos, usando el API de C se tratarían como ficheros). En contraposición a estas ventajas, la velocidad de ejecución del algoritmo al usar esta librería probablemente será inferior a usar directamente inotify
Threads
Existe una gran variedad de librerías para el manejo de threads en C/C++. Se han considerado todas de manera superficial. La mayoría son wrappers de la libthread de C que buscan ocultar el funcionamiento de los threads a bajo nivel. Las opciones consideradas han sido:
En este campo se ha encontrado que todas las opciones orientadas a objetos expuestas muestran una curva de aprendizaje elevada, frente al uso conocido y sencillo de las libthread de C. Se descartó en primer lugar C++ Threads, por no disponer de ninguna documentación accesible que explicase la interfaz que ofrece y por requerir la instalación en el sistema con permisos de superusuario. OpenThreads son un wrapper de la librería libthread sin más, no ofrece ventaja adicional y fue descartada en segundo lugar.
Boost.Thread es a primera vista tan simple de usar como las librerías nativas libthread de C. Se muestran algunos ejemplos:
//Creation of a thread
void foo()
{
create_thread(&bar);
}
//Creation of multiple threads in a loop that are latter joined void foo() { for (int i=0; i<NUM_THREADS; ++i) threads[i] = create_thread(&bar); for (int i=0; i<NUM_THREADS; ++i) threads[i].join(); }
Se muestran ejemplos también de la librería estándar de C para comparar el uso. Este ejemplo es más completo y por tanto el más largo, no obstante la complejidad es idéntica:
1 #include <pthread.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 //Cada thread escribe una letra de esta cadena por la salida estandar 6 char* buf = "abcdefghijklmnopqrstuvwxyz"; 7 //Determina el numero de threads 8 int num_pthreads = 10; 9 //Numero de veces que se repetira la ejecucion 10 int count = 25; 11 //Salida estandar 12 int fd = 1; 13 14 /* 15 * Escribe por pantalla el caracter apuntado por el parametro 16 */ 17 void* new_thread(void* arg); 18 19 int main(void) 20 { 21 //Declaracion del thread 22 pthread_t thread; 23 int i; 24 for (i = 0; i < num_pthreads; i++) { 25 //Creacion del thread 26 if (pthread_create(&thread,NULL,new_thread,(void *)(buf + i)) > 0){ 27 fprintf(stderr, "error creating a new thread \n"); 28 exit(1); 29 } 30 // Coloca el thread en estado detach 31 pthread_detach(thread); 32 } 33 //Sale del thread 34 pthread_exit(NULL); 35 } 36 37 38 void* new_thread(void * arg) 39 { 40 int i; 41 for (i = 0; i < count; i++) { 42 write(fd, arg, 1); 43 sleep(1); 44 } 45 return(NULL); 46 }
Conclusiones: No se ha tomado una decisión sobre el uso de una de las dos librerías. Todas las partes implicadas del equipo deben valorar si compensa aprender a manejar Boost.Thread sólo por ser OO o usar las librerías built-in de threads de C.
Bases de Datos
Se ha buscado la forma más eficiente de estructurar la tabla con la información necesaria para iniciar una recuperación del estado anterior de la aplicación tras un corte inesperado. El diseño del pequeño journal se ha esbozado de la siguiente manera:
12 CREATE TABLE IF NOT EXISTS journal ( 13 id INT(5) UNSIGNED NOT NULL PRIMARY KEY AUTO _INCREMENT, 14 timestamp TIMESTAMP NOT NULL, 15 chtype VARCHAR(255) NOT NULL, 16 initpath VARCHAR(255) NOT NULL, 17 finalpath VARCHAR(255) NOT NULL, 18 wrote CHAR(1) NOT NULL DEFAULT "0", 19 INDEX(timestamp)) 20 MAX_ROWS=300;
Se ha controlado el tamaño del journal como medida para garantizar la rápidez de escritura en la base de datos en cuanto los cambios son notificados por el sistema de ficheros. La tecnología de base de datos utilizada es el resultado de la investigación de http://hdlorean.wikidot.com/bases-de-datos
Conclusiones: La atomicidad y los mecanismos de exclusión del sgbd sqlite, junto al diseño del journal, garantizan que los cambios se escribirán de manera temporal suficientemente rápido como para que el sistema pueda recuperarse a través del journal de una caída inesperada.
Conclusión
Se han estudiado tecnologías para cubrir todas las funcionalidades que debería ofrecer Watcher y se han encontrado candidatos plausibles para cumplir con todos los requisitos. Se ha tenido en cuenta principalmente la compatibilidad, la facilidad de uso y la abstracción de las soluciones elegidas. En esta situación podemos comenzar el desarrollo del Watcher con la garantía de cumplir con los requisitos del módulo.
Opinión personal
Vistas las opciones de implementación de las tecnologías y considerando que la mayor complicación viene de la programación de funciones reentrantes y del manejo de los threads, podemos obtener un prototipo funcional sin threads en un tiempo corto, dejando abierta la puerta al uso de threads si hubiese tiempo para implementarlo.
Comentarios:
Informe de investigación de Bases de Datos
Descripción del módulo de bases de datos.
El módulo de bases de datos se encargará de centralizar la gestión de la información que necesita internamente el programa, y de abstraer el tratamiento de la misma para evitar complejidad y dependencias al resto de módulos del sistema.
Las funcionalidades más representativas del módulo son:
- Proporcionar una API a los demás módulos para que accedan a las bases de datos de manera segura y eficiente.
- Ocultar la base de datos que utilice el programa para poder cambiarla si fuera necesario.
- Gestionar otros problemas posibles que esto generaría (versiones diferentes de base de datos en versiones actualizadas del programa, por ejemplo).
Abstracción al problema
HD Lorean se encarga de gestionar un importante volumen de información: cuántas instantáneas existen, a qué archivo pertenecen, la fecha en que fueron creadas, u otras informaciones como su tamaño o un checksum para validar que la restauración ha sido bien hecha y no hay posibles corrupciones de datos. También almacena los cambios que se fueron realizando en orden, para poder deshacer mediante ese orden si se usa la "barra de tiempo" comentada en los casos e historias de uso.
Abstracción a la solución
Para poder tratar eficientemente toda esa información se opta por la tecnología establecida de bases de datos, a fin de reutilizar soluciones y de no tener que preocuparnos en exceso por problemas de integridad de esos datos (fundamental), o de concurrencia en los accesos. Utilizar el lenguaje SQL nos permitirá realizar consultas relativamente complejas de un modo entendible (por ejemplo, "cambios en los archivos de determinada subcarpeta entre tal y tal fecha").
Además se necesitará bastante eficiencia (pues potencialmente estamos escribiendo una entrada por cada cambio que se realice, que pueden ser muchísimos en caso de una operación importante de archivos).
Tecnologías empleadas
Ante todo, hemos tratado de evitar depender de servidores externos (como una instalación completa de mysql o postgresql) porque se consideran dependencias demasiado importantes para una aplicación "de usuario", además de que no tienen por qué estar instaladas por defecto y suponen bastante overhead para nuestras necesidades al estar diseñadas para usos más "grandes". Además, depender de una base de datos standalone supone depender de un control de accesos (nombre de usuario y contraseña, base de datos bien configurada) que hace a nuestra aplicación más vulnerable.
Por tanto, se ha decidido utilizar una librería que proporcione la funcionalidad de "base de datos en un archivo" para poder realizar consultas SQL pero solo depender de una librería externa y no de ningún demonio adicional corriendo. El requisito de enlazar contra esta librería, posiblemente de modo estático, nos obliga a buscar entre licencias GPL-compatibles, y ello nos ha dejado como opción sqlite3, que ofrece gran cantidad de funcionalidades para la gestión de bases de datos tanto en C como en C++, como nosotros estamos trabajando en python usaremos un conector llamado pysqlite2. Además, sqlite está sobradamente probado en el mundo del software libre por proyectos que hacen importante uso de él como rhythmbox o amarok.
He aquí unos ejemplos de como funciona esta librería a modo de tutorial.
Conclusión
Un envoltorio sobre sqlite3 es una buena opción para implementar este módulo ya que es similar a las tecnologías que ya conocemos (MySQL, ó SQL en general) y tiene una API online bastante clara.
Para realizar este módulo necesitaremos una buena comunicación con los responsables del resto de módulos, que nos tendrán que definir con claridad la información que requieren del sistema a fin de diseñar correctamente las bases de datos y crear las funciones que encapsulen las llamadas SQL.
Comentarios:
Informe de investigación de Snapshot Manager
Glosario
- backup: copia de seguridad de un archivo o directorio, bien sea en forma de copia o en forma de incremental.
- sistema de copias de seguridad: un sistema de copias de seguridad permite restaurar parte de un sistema de archivos a un estado anterior denominado snapshot.
- snapshot: unidad mínima del sistema de copias de seguridad. Formado por los ficheros necesarios para la recuperación de archivos y directorios en el instante de la creación del mismo además de otros ficheros de mantenimiento.
- snapshot-incremental: snapshot en el que los backup necesarios para la recuperación de archivos son diferenciales sobre el original, optimizando así el uso del espacio.
- snapshot-íntegro: snapshot en el que los backup necesarios para la recuperación de archivos son versiones íntegras de esos archivos en ese instante.
- snapshot-core: módulo encargado de la creación y mantenimeinto de los snapshot de HD-Lorean.
- timestamp: o sello de tiempo es una cadena de caracteres que representa el instante actual. Se utiliza como una marca única para identificar un instante de tiempo dado y puede actuar a varias resoluciones. La resolución puede ser anual si sólo se determina el año; mensual, si se determina además el mes; diaria, si añadimos el dia o incluso mayor si contabilizamos horas, minutos y segundos.
Descripción del módulo snapshot-core
El módulo snapshot-core se encarga de la gestión del sistema de snapshots de HD-Lorean.
Las funcionalidades más representativas de snapshot-core son:
- Realizar una copia de seguridad de un archivo o directorio.
- Restaurar una copia de seguridad previa.
- Gestionar el espacio en disco eliminando ciertos intervalos de snapshots.
Abstracción al problema
El objetivo de snapshot-core es definir una estructura para copias de seguridad. Esta estructura debe incluir la localización dónde se almacenarán las copias de seguridad,el formato de los archivos e informes, sumarios y archivos de configuración necesarios.
Abstracción a la solución
Una primera aproximación a la solución del problema consiste en identificar el proceso de copia de seguridad e intentar resolver las partes no triviales del mismo. Se describe su algoritmia en las siguientes líneas:
- A la entrada llega una lista de los ficheros (o directorios) de los que se desea realizar la snapshot.
- Crear un directorio para el snapshot
- Leer fichero de la lista de rutas de ficheros
- Identificar si existe un snapshot anterior
- Si existe:
- Almacenar tan sólo una diferencia con alguna versión anterior
- Si no existe:
- Copiar el archivo tal como está.
- Marcar dicho directorio como origen para el fichero.
- Volver a 3 hasta agotar la lista
- Fin del snapshot
Los puntos marcados en negrita requieren especial atención puesto que plantean nuevas dudas a cerca del sistema que se intenta definir:
El punto 3 lleva a la cuestión sobre qué formato tiene la lista que alimenta al método de creación de snapshots.
El punto 5.1 induce a plantearnos la manera de establecer los incrementales
Diferencias entre tipos de ficheros
La lista de rutas de ficheros contiene, además de las rutas a cada fichero (directorio) del que queramos un nuevo snapshot, alguna información extra que permite optimizar el tratamiento del archivo o directorio.
Al menos, provee un indicador del tipo de archivo al que se refiere la ruta pues a primera vista, existe una diferenciación entre ficheros y directorios. Mientras que en los primeros se realizan diferencias a nivel de byte, en los directorios los cambios se realizan a nivel de entrada de directorio. Es decir, en un archivo de texto pueden cambiar una palabra, en un archivo binario pueden cambiar algunos bytes, pero en un directorio lo que cambia es el conjunto de archivos y otros directorios en su interior.
En relación a puntos posteriores, utilizaremos dos tecnologías de copia incremental, una para archivos y otra para directorios. Luego concluimos que debemos hacer una primera diferenciación entre archivos y directorios.
Cómo se almacenan los ficheros incrementales
Para gestionar eficientemente el espacio de la unidad donde se encuentran almacenados los snapshot es necesario almacenar tan sólo las modificaciones ocurridas a un fichero en lugar del fichero completo. La duda existe a la hora de si definir estas diferencias respecto del archivo original o respecto del último conjunto de diferencias.
Como una de las características de HD-Lorean permite al usuario la eliminación de snapshots intermedios sin riesgo de perder la información, es conveniente optar por la primera opción, donde los conjuntos de diferencias se establecen en relación al primer archivo.
Conclusiones
El hecho de haber dividido el problema en pequeños subproblemas nos lleva a la necesidad de investigar nuevas tecnologías que permitan resolver eficientemente cada una de las tareas implicadas en el algoritmo.
Este documento versa sobre las tecnologías de compresión delta, indispensables para la creación de archivos diferenciales y su posterior reconstrucción.
Tecnologías empleadas
A continuación se establecen las bases teóricas para comprender la terminología utilizada a lo largo del documento. Luego se describe brevemente cada tecnología, se otorga un ejemplo de uso y se destacan sus aspectos positivos y negativos.
Codificación delta
También conocida como compresión delta, la codificación delta es un modo de almacenar un archivo en forma de variaciones secuenciales sobre una versión anterior del mismo. Estas diferencias son almacenadas de manera independiente en ficheros llamados deltas o diffs.
En general, las diferencias entre versiones son pequeñas por lo que el conjunto de deltas suele ocupar menos que el archivo equivalente no codificado.
Desde otro punto de vista, mucho más interesante para nuestra aplicación, un delta entre dos archivos A y B es la información que debe ser aplicada a A para lograr B.
Existen codificaciones direccionales o bidireccionales dependiendo de si se pretende transformar exclusivamente de A a B o de B a A; o si por el contrario se necesita poder transformar indistintamente A en B y B en A.
Normalmente la codificación delta proporcionada por alguna aplicación incluye también un protocolo para la sincronización de archivos en distintos puntos de una red a través de la transmisión de los deltas únicamente.
Este tipo de codificaciones fue concebido para archivos que presenten cierta regularidad en su formato, donde un cambio no alteré más que una región pequeña del total. Si se usa para codificar otro tipo de archivos en los que un cambio puede afectar a la estructura completa del archivo, su rendimiento se degrada considerablemente.
Estándar VCDIFF23
VCDIFF es un estándar de codificación de archivos delta. Es necesario atender a que VCDIFF no atiende a cómo se deben obtener las diferencias entre dos archivos sino a cómo han de escribirse estas diferencias en el archivo de diferencias. Esto es, el formato VCDIFF es independiente del algoritmo de extracción de datos y por tanto, un decodificador compatible con VCDIFF podrá actuar sobre cualquier archivo de diferencias en ese formato, sin conocer los detalles del algoritmo de codificación.
Aplicaciones de codificación delta
diff
No es estrictamente un programa de compresión delta pues opera únicamente sobre ficheros de texto. Sin embargo permite comparar dos directorios rápidamente. Si bien no distingue entre los archivos modificados, si es capaz de determinar qué archivos han sido añadidos y cuales eliminados.
Ejemplo de uso:
Contenido de prueba.txt
int main(int argc, char** argv){
int i = 5;
return i;
}
Contenido de prueba2.txt
void main(int argc, char** argv){
int i = 5;
i++;
return;
}
Salida producida por diff prueba.txt prueba2.txt
1c1
< int main(int argc, char** argv){
---
> void main(int argc, char** argv){
3c3,4
< return i;
---
> i++;
> return;
Ejemplo de uso con directorios:
Contenido en el directorio ~/carpeta1
- A
- B
- C
Contenido en el directorio ~/carpeta2
- B
- C
- D
- E
Salida producida por diff diff carpeta1 carpeta2
Sólo en carpeta1: A
Sólo en carpeta2: D
Sólo en carpeta2: E
Conclusiones:
La consecuencia de estas pruebas descartan a diff como una aplicación para la creación de deltas binarios aunque puede resultar una buena opción de cara a la simple comparación de ficheros o a la comparación de directorios.
Además, la mayoría de aplicaciones usa su algoritmo de comparación (descrito en E.Meyers24) o una optimización sobre del mismo y para casos especiales en archivos de texto cuenta con herramientas muy interesantes para la manipulación de deltas.
xdelta (v2.x)
Esta aplicación permite la creación de deltas para archivos binarios. Si no hay coincidencias entre la versiones entonces el parche se prepara para poder aplicarse sin necesidad del original.
Salida para xdelta delta dibujo.bmp dibujo2.bmp to-dibujo2.patch
NADA
Salida para xdelta patch to-dibujo2.patch dibujo.bmp dibujo2-2.bmp
NADA
Salida para diff dibujo2.bmp dibujo2-2.bmp
NADA
La salida nula del último comando indica que ambos ficheros son iguales, de no ser así, el comando diff emitiría un mensaje indicando lo contrario como puede comprobarse ejecutando:
Salida para diff dibujo.bmp dibujo2.bmp
Los ficheros binarios dibujo.bmp y dibujo2.bmp son distintos
El tamaño del parche en la ocasión anterior es de 192,6KiB, el parche ocupa un poco más del 50% del tamaño original de la imagen. Si bien, este resultado es fruto de la codificación de imágenes BMP y no resulta tan eficiente utilizamos formatos ya comprimidos.
Salida para xdelta delta dibujo.png dibujo2.png to-dibujo2.patch
NADA
Salida para xdelta patch to-dibujo2.patch dibujo.png dibujo2-2.png
NADA
Salida para diff dibujo2.png dibujo2-2.png
NADA
El resultado es un archivo parche de 205,6Kib, incluso mayor que el del original debido a algunos campos extra que el propio xdelta añade al crear el archivo de diferencias.
Conclusiones:
Pese a todo, HD-Lorean está enfocado al usuario doméstico que mantiene una colección de fotografías normalmente inalterable o modificada muy de vez en cuando. El módulo snapshot-core podría detectar esta situación y no crear un archivo de diferencias sino copiar directamente el nuevo archivo.
xdelta (v3.x)
Se trata de la siguiente versión de xdelta. Posee una interfaz drásticamente distinta y produce un delta codificado en el estándar VCDIFF.
El mismo ejemplo que en su versión anterior produce un peor archivo en el primer caso y un resultado ajustado en el segundo, siendo el parche del mismo tamaño que el archivo original.
A continuación se ilustra tan sólo su uso:
xdelta3 encode -s fromFile toFile patchFile
xdelta3 decode -s fromFila patchFile toFile
La primera sentencia codifica, mientras que la segunda decodifica.
Conclusiones:
Las conclusiones son prácticamente las mismas que en el caso anterior aunque el hecho de que se utilice VCDIFF a la hora de crear los archivos de diferencia permite en un futuro portar a otros sistemas potencialmente mejores sin perder la compatibilidad.
bsdiff / bspatch
Su autor afirma que consigue una compresión un 50% - 80% mejor que xdelta. A costa de un mayor tiempo de procesamiento, usa muy poca memoria y ofrece una interfaz extremadamente sencilla.
Ejemplo de uso:
dibujo1.png (368KiB)
Salida para bsdiff dibujo.bmp dibujo2.bmp to-dibujo2.patch
NADA
Salida para bspatch dibujo.bmp to-dibujo2.patch dibujo2-2.bmp
NADA
Salida para diff dibujo2.bmp dibujo2-2.bmp
NADA
En este caso el parche ha resultado en 180,1KiB, algo menos que el parche de xdelta pero la ejecución ha tardado unas 10 veces más.
El segundo resultado, sobre archivos PNG, produce resultados peores que xdelta en mayor tiempo.
Conclusiones:
En conclusión, bsdiff ofrece un mejor rendimiento a costa de un gran coste en tiempo lo que puede ir en detrimento de la funcionalidad de HD-Lorean pero es una opción a tener en cuenta en situaciones dónde el tiempo no sea crítico y sí la optimización des espacio en disco. Sin embargo, mezclar alternativas que no siguen ningún estándar podría ser incompatible.
KDiff325
Se trata de una herramienta de comparación de archivos y carpetas con una agradable interfaz gráfica. También permite mezclar ficheros y editar los resultados y la posibilidad de hacer estas operaciones con 2 ó 3 entradas.
Ejemplo de ejecución de la herramienta:
Comparamos los directorios Temp1 y Temp2 y obtenemos como resultado:
Como resultado obtenemos que el archivo “file1.txt” (notar los dos cuadrados verdes) se encuentra en los dos directorios y son idénticos, mientras que el archivo “file2.txt” es diferente (notar el cuadrado rojo), y por último el archivo “file3.txt” se encuentra en el directorio A pero no en el directorio B (el cuadrado es gris en la segunda columna).
La herramienta también aporta información adicional sobre los archivos que podría ser de gran ayuda a la hora de relacionar los snapshot de los directorios con los snapshots de los archivos.
Conclusiones:
Como veremos a continuación, KDiff3 pertenece a un nuevo grupo de tecnologías caracterizadas por ser aplicación, más que herramienta. Estudiar herramientas con interfaces gráficas implementadas sirve para conocer formas de representar resultados de manera óptima al usuario, acogiendo las ideas interesantes y desechando las menos relevantes, aunque esta tarea no sea el objetivo de este módulo.
xxdiff26
En este caso encontramos al igual que la herramienta anterior, una aplicación que nos permite comparar dos o tres archivos y dos directorios. La característica interesante de esta aplicación es que permite comparar dos directorios de forma recursiva, es decir, si en algún momento existiese un directorio interno a los directorios a comparar, éste también sería incluido en la comparación.
Esta funcionalidad sería interesante en nuestro programa ya que será muy común que algún usuario use la aplicación sobre múltiples directorios.
Ejemplo de comparación de directorios:
Conclusiones:
La funcionalidad de la aplicación es básicamente idéntica y no hay nada que remarcar de su investigación. Tan sólo se considera otra alternativa y será necesario un estudio de grano fino para poder elegir entre alguna de las dos.
rdiff-backup27
Se trata de un completísimo script escrito en python con licencia GPL que permite realizar una copia de seguridad de un directorio en otro. El directorio que contiene la copia de seguridad contiene también un conjunto de archivos diferenciales que permite la recuperación de cualquier estado intermedio.
Su interfaz es sencilla pero versátil y resulta la mejor opción de todas las puesto que podría cubrir todos los casos de uso de snapshot-core de manera automática.
Ejemplo de backup de la carpeta /home/salvador de 15,4MiB.
La primera operación crea el snapshot del directorio /home/salvador en /home/salva-back haciendo de este un clon del primero.
Salida para time rdiff-backup /home/salvador /home/salva-back
6.26user 2.77system 0:43.50elapsed 20%CPU
Después de algunas modificaciones (borrado, adición y edición de algunos archivos), el segundo comando, aunque en apariencia idéntico, tan sólo guarda las modificaciones acaecidas al directorio original. El incremento del tiempo se debe al hecho de que es necesario revisar cada archivo en busca de cambios aunque se intuye que para snapshots de directorios más grandes, las operaciones de comparación requerirían menos tiempo que las de creación de la estructura.
Salida para time rdiff-backup /home/salvador /home/salva-back
19.07user 0.35system 0:21.06elapsed 94%CPU
El tercer comando lista los incrementales ocurridos desde la primera copia.
Salida para rdiff-backup -l /home/salva-back/
Found 1 increments:
increments.2007-11-15T22:46:47+01:00.dir Thu Nov 15 22:46:47 2007
Current mirror: Thu Nov 15 22:52:39 2007
Por último, tras nuevos cambios (borrado de casi toda la estructura), el cuarto comando restaura el directorio tal y como estaba en el momento del primer incremental.
Salida para time rdiff-backup -r 2007-11-15T22:46:47+01:00 /home/salva-back/ /home/salva-restored/
5.49user 2.56system 0:17.03elapsed 47%CPU
En el ejemplo se ha incluido la salida del comando time que devuelve los tiempos de usuario y sistema para un proceso argumento.
Puede encontrarse la documentación de rdiff-backup en esta dirección:
//www.nongnu.org/rdiff-backup/docs.html
La documentación incluye ejemplos de uso y las páginas del manual.
Conclusiones:
Como conclusión, usando esta aplicación snapshot-core actuaría a modo de envoltorio para las funciones propias de rdiff-backup y proporcionaría una interfaz focalizada y sencilla. Además podría atender múltiples peticiones mediante el uso de threads.
Se trata de la forma más rápida de implementar snapshot-core pero presenta un inconveniente: HD-Lorean desconocería los detalles de implementación del sistema de snapshots.
La solución existente es investigar el código fuente de la aplicación.
Comparación
Se han estudiado dos grupos diferentes de tecnologías. El primero, formado por diff, xdelta (v2), xdelta (v3) y bsdiff pretenden ser una base para el desarrollo del gestor de snapshots de HD-Lorean. El segundo grupo formado por KDiff3, xxdiff y rdiff-backup pretende que HD-Lorean delegue la responsabilidad de mantener las snapshots haciendo uso de tal software. Como pequeño inciso decir que KDiff y xxdiff se encuentran muy limitados en comparación con rdiff-backup e incluso podrían resultar más útiles incluyéndolos en el primer grupo, por lo que, de considerar el segundo grupo de aplicaciones, la mejor opción con diferencia es rdiff-backup.
Conclusión
La implementación más rápida proviene del uso de rdiff-backup, sin embargo, desde el punto de la investigación y desarrollo, la opción más interesante es la gestión propia apoyada en el uso de herramientas menores como xdelta o diff. Si bien se puede lograr un compromiso estudiando rdiff-backup al tiempo que se desarrolla y compara con un administrador propio.
El estado del proyecto y el tiempo límite de entrega deberían influir en la toma de una decisión.
Opinión personal
Como responsable del módulo snapshot-core considero más interesante el desarrollo propio del sistema de snapshots pero atendiendo a las condiciones del proyecto recomiendo el uso de rdiff-backup teniendo en cuenta los nuevos riesgos que esto supone.
Nuevos desarrollos
Gracias a la investigación llevada a cabo se pudo desarrollar un módulo de pruebas que simulaba un sistema de archivos primitivo pero funcional. A continuación se detalla su funcionamiento exponiéndolo a una situación real.
Configuración
La aplicación de prueba toma una entrada como una lista de rutas caracterizadas por ser archivo o directorio que debe comprobar. En este momento, el procesamiento de carpetas no se lleva a cabo pero sí el de archivos. El de directorios, sin embargo, sólo es simulado.
Contenido del archivo de configuración
d#/home/salvador/pruebas-hd/+inotify
d#/home/salvador/pruebas-hd/+inotify
f#/home/salvador/pruebas-hd/+inotify/inotify-test.py
f#/home/salvador/pruebas-hd/+inotify/inotify threaded test.py
Como puede observarse claramente, cada ruta es de la forma
<tipo de ruta>#<ruta>
El tipo de ruta puede ser 'd', 'D', 'f' o 'F' refiriéndose los dos primeros a directorios y los últimos a ficheros. Es importante advertir que snapshot-core no realiza copias de seguridad recursivas y por tanto, el archivo de configuración debe incluuir toda la estructura del directorio si así lo disponemos.
De cara a la integración en HD Lorean este archivo será reemplazado por una lista de rutas acompañadas de información útil sobre las mismas y el proceso de recursión sobre directorios será llevado a cabo por otro módulo, específicamente por watcher.
Forma de uso
Es necesario indicar el archivo de configuración como primer argumento. De esta manera:
salvador@lodr:~$ ./hdl-snapshot-core ~/hdlorean-config
Estructura del directorio de copias de seguridad.
El resultado para una ejecución inicial como la anterior es:
snapshot-core started:
Monitorized files file (/home/salvador/.hdlorean/monitorized-files) is ready. That's good!
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
Executing: mkdir -p "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/"
Executing: cp -a "/home/salvador/pruebas-hd/+inotify/inotify-test.py" "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/"
/home/salvador/pruebas-hd/+inotify/inotify-test.py=backup in [/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/]
Executing: mkdir -p "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/"
Executing: cp -a "/home/salvador/pruebas-hd/+inotify/inotify threaded test.py" "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/"
/home/salvador/pruebas-hd/+inotify/inotify threaded test.py=backup in [/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/]
Nothing more!
Monitorized files file (/home/salvador/.hdlorean/monitorized-files) is ready for writing. That's good!
snapshot-core finished ok. See you!
Tras ella, en la carpeta personal de la sesión existirá un nuevo directorio llamado '.hd-lorean' cuyo contenido es:
salvador@lodr:~$ cd .hdlorean/
salvador@lodr:~/.hdlorean$ ls -a
. .. backups monitorized-files
El contenido del archivo 'monitorized-files' es un listado de parejas de la forma
<ruta del archivo monitorizado>
<ruta de la copia de seguridad del archivo monitorizado
...
En especial, el contenido de este será:
/home/salvador/pruebas-hd/+inotify/inotify threaded test.py
/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/inotify threaded test.py
/home/salvador/pruebas-hd/+inotify/inotify-test.py
/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/inotify-test.py
Es importante notar que la copia de seguridad original del archivo preserva la ruta original del mismo pero dentro del directorio de copias de seguridad.
Si exploramos el contenido del directorio 'backups' encontramos:
salvador@lodr:~/.hdlorean$ cd backups/
salvador@lodr:~/.hdlorean/backups$ ls -a
. .. 20071128-142422
salvador@lodr:~/.hdlorean/backups$
Esos números son un timestamp generado en el instante en el que da comienzo la copia de seguridad. También son el nombre de la carpeta de backup para ese instante. En su interior encontraremos los archivos (originales en este caso) salvados y un archivo llamado 'briefing' con los resultados de la copia de seguridad.
salvador@lodr:~/.hdlorean/backups$ cd 20071128-142422/
salvador@lodr:~/.hdlorean/backups/20071128-142422$ ls -a
. .. briefing home
Queda patente que la copia de seguridad preserva la ruta original. Si, desde aquí, exploramos la ruta del directorio 'home' encontraremos copias idénticas de los archivos originales.
salvador@lodr:~/.hdlorean/backups/20071128-142422$ cd ./home/salvador/pruebas-hd/+inotify/
salvador@lodr:~/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify$ ls
inotify-test.py inotify threaded test.py
salvador@lodr:~/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify$
Resultados de la copia de seguridad
Los resultados de la copia de seguridad se encuentran en el archivo 'briefing'
Contenido del archivo briefing
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify/inotify-test.py=backup in [/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/]
/home/salvador/pruebas-hd/+inotify/inotify threaded test.py=backup in [/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/]
En él se aprecian las operaciones realizadas para cada archivo. En el caso de las carpetas sólo se simulo su procesamiento pero en el caso de los archivos, tal y como se indica, estos fueron copiados a las rutas indicadas. Tal y como vimos anteriormente.
Una segunda ejecución.
Si modificamos los archivos originales, y realizamos una segunda ejecución obtendremos para el mismo comando, la siguiente salida.
salvador@lodr:~$ ./hdl-snapshot-core ~/hdlorean-config
snapshot-core started:
HD-Lorean directory (/home/salvador/.hdlorean) already exists. That's good!
Backup directory (/home/salvador/.hdlorean/backups) already exists. That's good!
Monitorized files file (/home/salvador/.hdlorean/monitorized-files) is ready. That's good!
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
Executing: mkdir -p "/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/"
Executing: xdelta delta "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/inotify-test.py" "/home/salvador/pruebas-hd/+inotify/inotify-test.py" "/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/inotify-test.py.diff"
/home/salvador/pruebas-hd/+inotify/inotify-test.py=incremental diff in [/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/]
Executing: mkdir -p "/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/"
Executing: xdelta delta "/home/salvador/.hdlorean/backups/20071128-142422/home/salvador/pruebas-hd/+inotify/inotify threaded test.py" "/home/salvador/pruebas-hd/+inotify/inotify threaded test.py" "/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/inotify threaded test.py.diff"
/home/salvador/pruebas-hd/+inotify/inotify threaded test.py=incremental diff in [/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/]
Nothing more!
Monitorized files file (/home/salvador/.hdlorean/monitorized-files) is ready for writing. That's good!
snapshot-core finished ok. See you!
Si ahora accedemos al directorio de copias de seguridad encontraremo una carpeta más con el timestamp actual.
salvador@lodr:~$ cd .hdlorean/backups/
salvador@lodr:~/.hdlorean/backups$ ls -a
. .. 20071128-142422 20071128-145209
salvador@lodr:~/.hdlorean/backups$
El directorio 20071128-145209 es nuevo.
Veamos qué contiene su archivo de briefing:
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify=process performed for /home/salvador/pruebas-hd/+inotify
/home/salvador/pruebas-hd/+inotify/inotify-test.py=incremental diff in [/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/]
/home/salvador/pruebas-hd/+inotify/inotify threaded test.py=incremental diff in [/home/salvador/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify/]
El resultado es muy similar puesto que se han tratado los mismos archivos pero esta vez nótese que el resultado del procesamiento de archivos no es backup sino diff.
Podemos explorar el directorio de la copia de seguridad en busca de estos archivos y tener de esta manera:
salvador@lodr:~/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify$ ls
inotify-test.py.diff inotify threaded test.py.diff
salvador@lodr:~/.hdlorean/backups/20071128-145209/home/salvador/pruebas-hd/+inotify$
Esta vez, los archivos son parches generados con la aplicación xdelta de la que hablamos previamente.
Conclusiones finales
Aunque precario, este módulo es fácilmente ampliable a cualquiera de los casos de uso contemplados para HD Lorean y permite el control total de los contenidos y estructura del snapshot. Sin embargo, debido a su estado de desarrollo no se asegura que esta sea la solución más eficiente aunque haga uso de algoritmos realmente fiables.
El manual con la estructura de snapshot de rdiff-backup indica serias semejanzas entre esta organización y la presentada por rdiff-backup lo que supone una migración relativamente rápida de una a otra. De todas formas el objetivo de esta aplicación siempre fue familiarizar al grupo de desarrollo con el tipo de aplicación que iban a desarrollar. Además ha servido para identificar nuevos riesgos descritos detalladamente en el informe de final de iteración.
Apéndice A (Dic-07)
Sobre rdiff-backup
El término de las investigaciones sobre la utilidad rdiff-backup ha llevado a la valoración en profundidad de sus características de cara al desarrollo de HD Lorean.
Para empezar, rdiff-backup es una aplicación de backups28 preparada para resoluciones de tiempo grandes, como las copias cada x minutos, cada hora, día, semana… De hecho, su resolución mínima es el segundo lo que imposibilita el hecho de que notificadores en tiempo real como inotify o cron ordenen más de un backup en el mismo segundo. Por otra parte, rdiff utiliza un sistema de diferencias reversas independientes lo que implica que siempre se almacene el último estado de los ficheros salvados y una serie de archivos parche para la recuperación independiente de versiones anterirores.
Independiente quiere decir que, en caso de que algunos de los archivos de diferencias se pierdan, siempre será posible hacer uso del resto para recuperar otras versiones ya sean posteriores o anteriores al eliminado.
Problemas encontrados y soluciones propuestas
Rendimiento de rdiff-backup
Al ordenar un backup en un instante dado, rdiff comprueba las fechas de modificación de todos los archivos a la hora de generar los parches de diferencia por lo que, en principio, no realiza más trabajo del que es necesario. Sin embargo, el hecho de tener que acceder a todos los i-nodos de los archivos en busca de una posible modificación degrada el rendimiento de la aplicación en directorios con gran cantidad de archivos de pequeño tamaño. Esto, sumado al hecho de que rdiff-backup carece totalmente de una opción añadir al backup que permita únicamente agregar un archivo al backup existente sin tener que para ello acceder al resto de los ficheros del directorio produce una limitación de rendimiento importante y a tener en cuenta.
No existe solución inmediata puesto que rdiff-actua de esta manera y sería necesario modificar el código fuente para incluir esta optimización. La solución breve para simular el comportamiento deseado es hacer uso de las opciones —include y —exclude de rdiff-backup para seleccionar sólo aquellos ficheros deseados en cada instante y excluir todo lo demás. Si se desea añadir un fichero B a un directorio anteriormente salvado que tuviera ya los archivos A y C, se debería construir una lista A,B,C a rdiff-backup. Sin embargo si los archivos A y C hubieran sido modificados desde la última vez, no estaríamos añadiendo un nuevo archivo sino realizando un backup de nuevo. De todas formas, la adopción de esta solución puede llevarnos a violar el diagrama de colaboraciones entre clases diseñado para HD Lorean.
Otra solución es investigar otras aplicaciones de backup como rsnapshot o bien desarrollar nuestro propio gestor como encaminaba el módulo discontinuado llamado snapshot-core.
Eliminación de backups
rdiff-backup limita su gestión de espacio a poder eliminar del backup los ficheros con más de X tiempo sin haber sido modificados. HD Lorean no establece una gestión ni siquiera similar.
HD Lorean debe eliminar backups completos al término de cada hora, día, semana o mes y a voluntad del usuario de manera que ese instante de tiempo se habrá perdido para siempre.
La única manera de solucionar este problema es manipular los archivos de backup convenientemente, de manera que conserven la compatibilidad con rdiff-backup. Los riesgos de esta solución incluyen el hecho de que la manipulación externa a rdiff corrompa los archivos de backup inutilizando la copia de seguridad.
Dudas sobre rdiff-backup
He aquí la correspondencia mantenida por algunos desarrolladores de HD Lorean y los desarrolladores de snapshot-manager a cerca del comportamiento comentado sobre estas líneas.
De Salvador de la Puente a Ben Escoto, creador del documento titulado rdiff-backup file formar
Hi Ben!
I started to use rdiff-backup some days ago for an universitary project. I have a question about remove backups.
In man, you explain that remove-older-than deletes backups older than given time. That's ok, but… if I want to delete just one backup, not those older than time, only that that matches with time? How can i do it?
Thanks for all
PD: Excuse my english please. XD
Respuesta
Hi, I don't really work on rdiff-backup anymore, so you may have more
luck posting to the mailing list.
But I don't think there is a great answer to your question. If you
know that you have 12 backups, I think it may work to say
"—remove-older-than 11B", and if you know the last increment was a
bit more than 2 weeks old, maybe you could say "2W".
But in general I don't think there is a solution. If you wanted to
create one I think I would list the increments, find the time of the
second oldest, and delete older than that.
De Salvador de la Puente a la lista de correos de rdiff-backup
Hi everybody.
I'm developing a backup application that wraps rdiff-backup and it's triggered by inotify.
Supose I have following folder:
myFolder:
FileA.txt
FileB.txt
FileC..txt
If I execute rdiff-backup —exclude ~myFolder/FileB myFolder backup then I have a backup at time T.
Then, I execute rdiff-backup —include ~myFolder/FileB —exclude-regexp '.' myFolder backup to "add" B to the backup and I have a new backup at time T' containing only FileB.
The, If I list backup content at time T', then It's shown:
myFolder:
FileB
My question is, is possible to add FileB to the last backup?
I mean, is possible some like rdiff-backup —update —include ~myFolder/FileB —exclude-regexp '.' myFolder backup
Then, If i list buckup content at last backup time, It should show:
myFolder
FilaA
FileB (added)
FileC
—
Now another question.
Anybody can explain me how rdiff-backup make its reverse diff files and what is the structure and mean of each file inside rdiff backup folder?
That's all.
Thanks a lot.
P:D: Excuse my English, please and thx again. x)
Respuesta
Hi Salvador,
My question is, is possible to add FileB to the last backup?
I mean, is possible some like rdiff-backup —update —include
~myFolder/FileB —exclude-regexp '.' myFolder backup
Then, If i list buckup content at last backup time, It should show:
myFolder
FilaA
FileB (added)
FileC
Well, one thing to remember is that if you do several backups of the
same directory to the same rdiff-backup repository, then the backup
repository always shows the state of the source directory at the time
of the most recent backup. So in your example, all you would need to
do to add in FileB is not to exclude it, i.e. to run rdiff-backup
with no —exclude options at all. Then FileA and FileC would stay
there (since they are still in the source directory), and FileB would
be added (since this time you haven't told rdiff-backup to exclude
it). So all you would need to do is
rdiff-backup myFolder backup
No explicit includes or excludes are needed, if all you want is for
the backup repository to exactly mirror the source filesystem. This
doesn't cause rdiff-backup to do any extra work to keep FileA or
FileC, since they were already there. (It will check their
modification times to make sure they haven't changed, but if they are
the same, it won't re-copy those files.)
Hope this helps,
Eric
Conclusiones
Jamás recomendaría modificar los fuentes de rdiff.backup debido a que perderíamos la independencia respecto de la aplicación estando obligados a modificar cada release para adecuarla al comportamiento que necesitamos. Por tanto, adoptaría cualquiera de las otras soluciones para las cuales es necesario realizar una reunión con el fin de permitir o no la expresión de nuevas colaboraciones entre clases que puedan modificar la estandarización de la ruta de colaboración.
Debido a las particularidades de nuestro sistema de snapshots, recomiendo encarecidamente la investigación de un formato propio aunque esto retrasase algunas de las funcionalidades críticas en pos de un mejor control sobre nuestra aplicación.
Gestión
Introducción
En esta página centralizamos todo lo referente a gestión del proyecto: estándares, planes, entregas, reparto de tareas, etc. Los contenidos se incluyen a fin de poder incluir esta página directamente en printable; van en páginas independientes por comodidad (a sabiendas de que los includes de cada página son más o menos reducidos).
Estándares
Introducción
- De la formación del personal se encargan los tutoriales, que no solo tratan de tecnologías específicas de cada grupo de trabajo sino también de todo lo necesario como el control de versiones. Todo el mundo documentará sus tecnologías, así minimizamos el riesgo de personal de que, en ausencia de alguien, nadie supiera cómo seguir su trabajo.
- El modelo de desarrollo a seguir para el código queda establecido como propuesta-modelo-desarrollo la propuesta inicial, disponible en los tutoriales.
- La evaluación de la calidad queda repartida entre todo el personal. Se repartirá a cada uno código a leer de otros grupos para revisar la legibilidad y concordancia a estándares del mismo. En cuanto a la documentación, Ezequiel queda como gestor último de la calidad de la misma, y se ruega a todo aquel que encuentre problemas en la misma que los solucione o al menos notifique.
- El estándar de documentación en wiki es sencillo: Todo aquello que vaya a ser incluido a posteriori debe empezar con el header de tamaño 2: ++, para que con el de tamaño 1 se pueda categorizar al incluirlo. A partir de ahí, se ruega la máxima legibilidad y corrección, así como la estructura que se considere adecuada mediante headers. Se ruega a cada equipo que documente en el wiki todo lo posible para tener constancia al final.
- Por favor, para mantener el nivel de calidad en la documentación usad el corrector ortográfico de firefox. Ahorraréis trabajo a control de calidad ;).
- Todo fragmento de documentación exigido por Gervás debe tener como padre (o abuelo, vaya) doc, como categoría doc: y debe comprobarse que queda incluido correctamente en printable (que no se rompe la anidación de headers, generalmente). Si no está allí, no se entrega al final…
- Para poner fragmentos de código se *debe* usar la etiqueta [code].
- Respecto a los comentarios, ya lo he mencionado en lista de correo: No dejéis comentarios entre la documentación, usad las páginas de comentarios de cada página y así los podemos ver juntos… Si echáis en falta la sección comentarios, añadidla con :
[[div class="comentarios" ]]
+++ Comentarios: [!--anidamiento según la página--]
[[module Comments title="" hide="true"]]
[[/div]]
Con esto solucionaremos el tema de flujo de información interna en el proyecto sin riesgos a la calidad de la documentación final (ya que al imprimir en PDF no se verá).
- El estándar de código seguirá estandar-codigo. Se escribirá lo más posible en inglés, para facilitar salidas posteriores a nuestro proyecto.
Modelo de desarrollo de código
Introducción
Tras estudiar un poco el funcionamiento de http://launchpad.net (no tan intuitivo como pretenden), he aquí una propuesta de modo de trabajo "con-código" para cuando tengamos que tirar líneas.
Los tutoriales concretos de bazaar siguiendo este modelo están aquí.
Ejemplo
Para resumir muy mucho, como algunos sabréis bazaar es un sistema de control de versiones que sirve igual que la historia de la wiki: lleva todas las versiones de tus archivos de código (en realidad de cualquiera), te enseña las diferencias entre versiones y te permite hacer otro millón de cosas interesantes como trabajar mucha gente a la vez (como subversion, pero sin necesidad de un server central), o mezclar bien los cambios entre el trabajo de mucha gente (lo más automático posible: si dos escribimos distinto una línea obviamente hay que revisar a mano, esto no es IA). Bazaar puede trabajar en modo "checkout", donde es básicamente "subversion" (el server centralizado, cuando cambias algo detecta tus cambios y tienes que mandarlos al repositorio remoto con "commit", y bajarte los cambios de otros con "update" antes de trabajar), pero también puede hacer "branch" (o "ramas", que son como "variantes" de una base de código con tus modificaciones por entendernos) con lo que todo se almacena en local, y para juntar tu código con otros branches hay un comando "merge" entre branches separados (parecido, supongo, al svn merge).
ojo que los comandos no son exactos, sino cogidos de los equivalentes en subversion.
Basamos el modelo de desarrollo en la propuesta de separarnos en grupitos de desarrollo con los que organizamos un poco.
Modelo de desarrollo
INDIVIDUO
- Absolutamente opcional. Para que la gente que no se aclare con el bazaar no tenga que liarse más de lo estrictamente necesario. Esto sirve solo para facilitar al trabajo al que se quiera complicar un poquito la vida al principio, es útil cuando eres desorganizado como yo.
- Trabajar en local con bazaar, y descentralizado.
- Puedes hacer commits locales (esto es, *sin* conexión a internete). Pero también puedes subir tu código a tu espacio de launchpad con bzr push, para bajarte el código desde la facu, sincronizar con tu portátil, tener un cierto backup o lo que sea. Sin embargo al no necesitar conexión para hacer commits puedes hacerlos frecuentemente (casi con cada cambio que hagas que ande a medias, vamos), y tienes "time machine" de tus archivos de código (de eso va el commit tb, puedes hacer "revert" y deshacer cambios).
- Puedes usarlo para otros proyectos tuyos, tener cienmil branches del código
- Como contra, hay que *aprender* a usarlo.
- Aquí es donde tiras tus líneas de código.
EQUIPO
- Los cuatro equipos del apocalipsis XD.
- Separación de trabajo por bloques de funcionalidad, o como podamos o queramos repartírnoslo.
- Cada equipo agrupa features del código, probablemente inestables y rotas, mientras se desarrollan.
- Trabajamos con el modelo "checkout" que es trabajar *igual* que en subversion, los commits son *solo* remotos.
- Dos opciones de trabajo:
- Si trabajas con bazaar en local, tus branches locales llevan tu código y su historia, y por tanto tienes que hacer merge de tu código personal con el branch del equipo (lógicamente, hay que sincronizarlo). En principio no debe ser mucho lío (nada que ver con subversion al respecto), pero esto es lo que habría que aprender realmente. Pero a cambio solo te hace falta conexión para sincronizar tu trabajo con el equipo, y puedes ir sincronizando más a alto nivel (cuando algo te medio funciona como para que el resto puedan usarlo, no una-vez-por-cada-cambio-en-archivos).
- Si pasas de liarte con bazaar en local, pasas a trabajar totalmente como si fuera subversion. Pierdes los commits locales y necesitas conexión (constante) a internet para cada commit, y pierdes también la posibilidad de hacer tus branches del branch del equipo (maldad extrema). A cambio, no te lías con merge y es muy similar a usar subversion, con el que algunos ya hemos trabajado.
- Aquí centralizamos el curro de cada equipo.
- Comentario: no es necesario un equipo *por feature*, en realidad para eso están los branches… Si os dais cuenta todos los equipos suben al *proyecto* hdlorean (lo veréis enseguida!), y en la página del proyecto quedan tanto los branches personales como los branches de equipo registrados, que pueden ser varios (se ve quién los publica, el equipo, y los nombres de esos branches, que sí pueden ser por feature).
PROYECTO
- Donde tenemos el proyecto ya todo junto.
- El "trunk" que viene por defecto en launchpad.
- Probablemente con sus propias branches (p.e. entregas a tal y cual fecha -se puede hacer con un tag-, estable, inestable, etc. ).
- A diferencia de los de equipo, feature-complete.
- Sirve para *integrar* el curro de los equipos: Aquí aplicamos control de calidad, los responsables de equipo (o team leaders que suena como más pijo) nos encargamos de mergear lo que sea, Mario controla que funcione como deba. El caso es que solo entre el código funcionando y se mantenga así lo más posible.
- Sería como un branch "de integración".
- nuevo: Usamos dos niveles de integración: en testing nos dedicamos a control de calidad y estabilizar código, mientras que unstable es para mezclar código entre repositorios separados y poder probarlo integrado. Todos los repositorios de equipo, por tanto, heredan de unstable y son mergeables con él.
Justificación
Como digo todo esto es un poco teórico porque no sé seguro si bazaar nos dejará hacerlo todo, pero creo que al menos sí bastante de ello. Así todo junto parece un follón, pero es solo para aclararnos. A la hora de la verdad se podría trabajar contra el checkout del team como quien curra con subversion, y solo hay problemas a la hora de integrar cambios entre todos. La contrapartida es que los desarrollos son separados, no hay problemas de tu-cambio-ha-roto-nuestro-código-en-otra-parte, etc.
Para entendernos: a la hora de la verdad, puede quedar en que tú subes tu código al branch de tu equipo, y luego solo nos peleamos un poco más los responsables con bazaar para integrarlo. Que es, por otra parte, quienes han confirmado que están dispuestos a trabajar así (al fin y al cabo somos quienes sufrirán un poco más para integrarlo). Para mayores problemas, recurriremos a Adrián como director de integración, o a Ezequiel como persona más informada en la tecnología.
Las ventajas de tener todo en launchpad es que cuando hay bugs se pueden relacionar con *todas* las partes afectadas por un bug a la vez (p.e. tu branch personal si trabajas con bazaar, a la vez el branch del equipo, y el proyecto que es donde apareciese). Puedes arreglar en *un* sitio y propagar los cambios a *todos*, o arreglar diferente en "estable" (con un parche cerdo XD) y en "inestable" (cambiando en plan serio lo que hubiese que cambiar). IDEM para peticiones de features, o lo que sea. Y el bugtracking así es más sencillo.
Otras "historias" de esto pueden ser p.e. que un equipo necesite un feature de otro equipo y estén ocupados con alguna otra prioridad, o lleve mucho tiempo implementarlo. Puedes o bien pedírselo amablemente, o bien implementarlo tú lo mínimo posible para que funcione y luego en el merge quitar tu implementación (ya bien sea en el merge hacia-proyecto o pillando trozos del código del otro equipo cuando está funcionando ya), o incluso implementarlo tú entero y que luego sea el equipo "responsable" de ese código el que lo pille de tu branch y lo mergee con el suyo.
Estándar de código
Consideraciones generales sobre el código
- El código se escribirá íntegramente en inglés a fin de mejorar la distribución de nuestro proyecto como software libre.
- Los identificadores no deben contener más de 15 caracteres y deben ser lo más significativos posible.
- El código se sangrará adecuadamente y siempre mediante uso de tabuladores.
- El desarrollador debe perseguir la eficacia de su código, sometiendo esta a los criterios de legibilidad y eficiencia. En este orden. Es decir, que funcione bien, que cualquiera lo pueda entender y, por último, que funciones rápido.
- Los que uséis eclipse, al crear un nuevo proyecto, marcad la opción python 2.4 (la que hay en los laboratorios) o, si usáis otro editor, procurad no usar features de python 2.5
- Para el tema de licencias: hay que incluir en la cabecera de cada archivo nuevo:
#Copyright (C) 2008 autores-del-código
#This file is part of HDLorean.
#
#HDLorean is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, version 2 of the License.
#HDLorean is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#You should have received a copy of the GNU General Public License
#along with HDLorean. If not, see <http://www.gnu.org/licenses/>.
Clases
- Los nombres de las clases siguen la convención UpperCamelCase.
- Las clases deben incluir comentarios Doxygen indicando su función, autores y responsables de mantenimiento.
- Se declararán en primer lugar los miembros privados, y en segundo lugar los públicos.
- De la misma manera, se declararán previamente los atributos y posteriormente los métodos.
- Se aconseja declarar los constructores y destructores antes que cualquier otro método público.
Miembros de clase
- Todos los miembros de clase, tanto públicos como privados siguen la convención lowerCamelCase. precedidos de guión bajo "_". (Por ejemplo, _privateMethod() o _privateVar)
- Todo miembro debe incluir comentarios Doxygen. Los siguientes campos son obligatorios:
- Descripción breve. Se seguirá la convención propia de Javadoc, por la cual se considera descripción todo aquello que se encuentre antes del primer punto.
- Descripción detallada.
- Autor/es.
- Parámetros de entrada (si procede).
- Parámetros de retorno (si procede).
- Excepciones lanzadas (si procede)
- Referencias a otros métodos involucrados (si procede).
Comentarios
- Los comentarios que conforman la documentación del código, se escribirán íntegramente en Inglés. Quedan exentos de esta regla aquellos con carácter temporal.
- Los comentarios deben otorgar una descripción clara y concisa sobre la entidad descrita.
- El código sin comentarios no será aceptado y se devolverá al autor para que lo comente adecuadamente.
Convenios adicionales sobre comentarios
Algunos grupos de desarrolladores, como KDE, utilizan algunos convenios para marcar partes del código que necesitan ser revisadas más adelante.
1.- Fixme
Indica que el código debe ser arreglado, puesto que el actual o bien no funciona correctamente, o bien no es legible, o bien no cumple el estándar de código establecido.
// FIXME: breve descripción de por qué hay que arreglarlo
2.- Remember
Indica algo que debe recordarse acerca de un fragmento del código.
// REMEMBER: breve descripción del recordatorio
3.- TODO
Indica alguna tarea pendiente de implementación.
// TODO: Breve descripción de la tarea por hacer
Convenios adicionales para comentarios C++
Para comentarios en línea, se hará uso de la forma:
// Comentario de linea
Para comentarios de bloque se hará uso de la forma:
/* Comentario de
bloque
*/
Para comentarios Doxygen se hará uso de la forma:
/**
Comentario de
documentación Doxygen
*/
Excepciones
- Las excepciones suponen un deterioro del rendimiento, pero son necesarias en proyectos grandes como HD Lorean para gestionar de manera controlada situaciones excepcionales o errores.
- Todas las funciones que lo precisen deberán usar excepciones
- El desarrollador del método creará las excepciones que sean necesarias para el buen funcionamiento de su código.
- Se desaconseja el uso de métodos cuyo valor de retorno sea el estado de éxito o fracaso de la operación. Para este tipo de situaciones es preferible hacer uso de excepciones.
Optimizaciones (Regla de Oro)
- No optimices…
- …todavía. (sólo expertos)
Estructura del wiki
- doc (categoría, pero no página): documentación relativa al proyecto concreto HD Lorean (arquitectura, casos de uso, etc).
- doc:printable: Página que incluye todo. Conforma la entrega final de Junio, así que incluye incluso las entregas parciales (para dejar constancia de nustro trabajo). Para ello, hace includes de varios niveles (por ejemplo incluyendo gestion solamente, que a su vez incluye las planificaciones y demás), lo que simplifica su complejidad y reduce su tamaño.
- doc:printable-MES: Hay un printable por entrega desde Noviembre. Como mínimo, incluyen la planificación de la iteración siguiente, y el seguimiento de la de ese mes; también incluyen las páginas nuevas creadas durante esa iteración. No van incluidas en la entrega final (porque sería duplicar trabajo); no obstante, podemos entregarlas aparte como complemento a esa documentación "integrada".
- gestion: documentación relativa a la gestión del proyecto, que sería reutilizable para futuros proyectos del grupo de desarrollo. Estándares de código, dónde está todo en el wiki, criterios de calidad, planificación seguida, etc.
- gestion:estandares: Centralización de los principales estándares seguidos.
- gestion:planificacion-fase: Quién hace qué y cuándo, ideas a grosso modo de cómo trabajaremos durante el mes. Con enlaces (pero no includes) a las iteraciones.
- gestion:planificacion-iteracion-MES: Planificaciones concretas para cada mes.
- gestion:seguimiento: Seguimiento general del proyecto (del plan de fase).
- gestion:seguimiento-mes: seguimiento de cada iteración individual.
- tutoriales: documentación interna para la formación del personal en las distintas tecnologías.
- template (categoría): Plantillas útiles para crear paginas que se quiera consistentes entre sí (cada doc:printable, cada planificacion-iteracion-mes, etc).
[]
Software Capability Maturity Model
Introducción
El Capability Maturity Model es un modelo de la madurez de los procesos de una organización, para evaluar las capacidades efectivas de desarrollo que tendrá dicha organización y poder predecir con mayor precisión sus éxitos en futuros desarrollos, mejorando al tiempo los puntos débiles de dichos procesos. Aunque ha sido sustituido recientemente por el Capability Maturity Model Integration, por estar muy extendido y sernos requerido haremos el estudio de nuestra organización respecto al original.
Referencia: apuntes de la asignatura, y wikipedia.
Nivel 1
Objetivos
Los procesos en el nivel 1, el punto de partida, están generalmente indocumentados y son implícitos, o bien no se siguen por parte del personal por desconocimiento u otras razones. Aunque es posible el desarrollo exitoso de proyectos, nada garantiza futuros éxitos.
Nivel 2: repetible
Objetivos
La base del nivel 2 del Software Capability Maturity Model, el cual debemos alcanzar necesariamente como requisito del curso, es que el proceso sea repetible, esto es: que el proceso seguido de creación del producto o proyecto permita generar futuros productos de un modo similar, convirtiendo su resultado en algo repetible y no fruto de la casualidad.
Aunque en el nivel 2 la disciplina de procesos pueda no ser rigurosa, se intenta seguir los procesos existentes siempre, incluso en situaciones de presión (entregas, exámenes, etc).
Es importante reseñar que en este nivel aún hay un importante riesgo de exceder las estimaciones de coste y de tiempo en futuros proyectos, al no existir revisiones de los procesos que los mejoren (y a las estimaciones).
Áreas clave de proceso
Gestión de requisitos
- Tenemos requisitos y especificación de lo que queremos, para saber hacia dónde orientamos el desarrollo y el trabajo que queda.
- Los planes, productos y actividades se mantienen consistente con esa especificación, aunque nos falta un proceso más definido de revisión (que no se requiere para nivel 2).
Planificación de proyecto
- Las estimaciones están documentadas y son reales. Se basan en alcanzar un compromiso entre estimaciones bottom-up (lo que los desarrolladores estiman que van a poder hacer, dados sus compromisos) y top-down (lo que consideramos imprescindible de la aplicación que debe estar en cualquier caso), y de momento funcionan con bastante exactitud, habiéndonos mantenido fieles al plan de fase y a la estimación de alcance durante las últimas iteraciones.
- Las planificaciones donde se detallan los compromisos del personal están documentadas en los planes de iteración y fase.
- El personal se lee los planes y está al corriente de los mismos. Es debido a que la planificación la realizamos siempre con el máximo número posible de miembros del personal, avisando además por lista de correos cuando se actualiza para que la gente sea consciente de sus obligaciones y planificaciones para el siguiente mes, por ejemplo si no pudieron estar presentes en la planificación.
Seguimiento de proyecto
- El seguimiento se contrasta con las planificaciones anteriores al realizar la siguiente, imprescindible para saber qué queda por hacer de lo que debiera estar hecho, además de para permitirnos estimar mejor los tiempos de desarrollo.
- Se toman acciones correctivas; al hacer los nuevos planes de iteración se tiene en cuenta qué ha fallado y por qué, y de ser necesario (complejidad inesperada, problemas de personal, etc) se replanifica.
- Si hay cambios en las responsabilidades, son de mutuo acuerdo por todo el mundo y por las partes. Es debido a que somos todos conscientes de que somos un grupo reducido de personal, y no hay otro modo de sacar el proyecto adelante.
Subcontratas
No aplicable para nuestro caso.
- El contratista elige subcontratas cualificadas.
- Ambos están de acuerdo con sus compromisos.
- Mantienen comunicación.
- El contratista comprueba si la subcontrata cumple los compromisos adquiridos.
Garantías de calidad
- Hay planificadas actividades de control de calidad desde las últimas iteraciones, así como procesos automáticos de revisión de la misma mediante pylint.
- Se verifica objetivamente que todo cumple los estándares, procedimientos y requisitos desde las últimas iteraciones (centradas en esto mismo).
- Los individuos afectados son informados de las actividades de calidad y los resultados. Cuando se detectan problemas de calidad se advierten al responsable, y además hay responsables definidos de cada área.
- Cuando se falla algo en calidad y no se sabe resolver se decide desde arriba qué hacer. Contamos con cierta jerarquía y proceso de decisión, aunque algo horizontal, que nos funciona por el escaso número de jefes que tenemos.
SCM (Gestión de configuración de software)
Se entiende por configuración de proyecto al conjunto de documentos y material relativo al proyecto en un momento (especificación, diseño, código y pruebas); la gestión de dicha configuración se refiere por tanto al mecanismo de control de cambios (sea de requisitos, de documentación, de código, etc).
- Hay. Existe control de código y de su migración entre versiones más o menos inestables (parecido a los baselines). Hay baselines, responsable de releases y de su mantenimiento, y un proceso de testeo manual para decidir cuándo establecemos un nuevo baseline (generalmente, tras la entrega de un baseline y los últimos bugfixes para dejarlo realmente estable).
- Existen versiones del software más o menos establecidas, una por release, que pueden obtenerse individualmente.
- Los cambios al software están controlados. En nuestro caso, solo están controlados los de código y documentación con control de versiones, no los de arquitectura (pero estos últimos no han sido necesarios, y pueden considerarse como parte de la documentación).
- Los grupos afectados están informados del estado y el contenido de los baselines. Antes de cada release se deja claro qué pretendemos que esté, y mientras trabajamos sobre ella mantenemos información sobre el estado de la misma para saber qué problemas son responsabilidad de cada quién.
Nivel 3: definido
Objetivos
En este nivel el proceso de desarrollo no solo es repetible sino que está claramente definido y establecido, y es susceptible de mejorar. Los procesos existentes se usan para conseguir consistencia, y se personalizan para cada proyecto (en nuestro caso, el modelo de desarrollo seguido sería válido para cualquier otro proyecto solo cambiando temas de grupos concretos encargados de subsistemas).
Áreas clave de proceso
Foco del proceso
- El desarrollo del proceso y sus mejoras subsiguientes están coordinadas a través del grupo. Aunque el proceso de mejora de procesos sea algo informal y que responda a cómo observamos, algo intuitivamente y poco cuantitativamente, que se comporta el mismo. Los procesos se discuten entre varias personas siempre, y se descartan cuando no son efectivos para el proyecto para poder agilizar nuestro desarrollo.
- Identificar ventajas / inconvenientes de cada proceso es algo que ya hacemos por tanto.
- Si bien gozamos de poco tiempo, se planifican mejoras del proceso a cada iteración conforme se detectan aspectos que pueden optimizarse en el mismo, o nuevas necesidades que cubra un nuevo proceso.
Definición de procesos
- Existe un proceso de desarrollo y se mantiene según detectamos problemas en el mismo (por ejemplo, la decisión de un repositorio donde estabilizar las releases sin aceptar features nuevas).
- Pendiente Se obtiene y distribuye información sobre el uso de este proceso (solo informalmente).
Formación
- Hay planificadas actividades de formación del personal, centralizadas en los tutoriales.
- Justificadas por el uso de tecnologías nuevas para todo el grupo (como el propio control de revisiones o el lenguaje de programación usado), que, investigadas por un grupo o individuo, son luego explicadas al resto del personal.
- Justificadas asimismo por la incorporación de personal al grupo.
- Se provee de materiales de educación para la formación del personal relativo a la gestión del software (por ejemplo bazaar para el control de versiones).
- Los individuos en el grupo de ingeniería del software también reciben formación adecuada (mediante otros tutoriales como sqlite, así como formación horizontal entre compañeros, y las clases propiamente dichas de la asignatura).
Gestión integrada de software
- El proceso de desarrollo de software es una versión a medida del estándar de desarrollo (debido a que el estándar ha surgido en paralelo al proceso concreto).
- Pendiente el proceso relativo al proyecto se planifica y gestiona sobre el estándar. No es posible dado que no hemos contado con un estándar predefinido del que partir antes de definir nuestros procesos, si bien teníamos ideas sobre "mejores prácticas" a seguir como el control de versiones en todas partes, o la gestión de releases.
Coordinación entre grupos
- Pendiente (parcial) Los requisitos del cliente son aceptados por todos los grupos. Si bien los requisitos se discutieron al inicio, los requisitos del cliente pueden estar algo olvidados por parte de los grupos de trabajo, y necesitar nuevo consenso.
- Los compromisos de los distintos grupos están acordados entre todos (ya que se planifica también entre todos).
- Los propios grupos identifican, siguen y resuelven los problemas entre ellos.
Peer review ("revisión entre iguales").
- Hay planificadas revisiones por parte de otros grupos del trabajo de cada uno para la última iteración, como parte de la mejora de calidad.
- Los defectos en el software son identificados, seguidos en el bugtracker y eliminados.
Nivel 4: gestionado
Objetivos
En este nivel se controlan con diversas métricas los procesos seguidos, para conseguir adaptarlos a los proyectos concretos sin desviarse significativamente de los objetivos.
Áreas clave de proceso
Gestión cuantitativa de procesos
- Pendiente Hay planificadas actividades de gestión cuantitativa de procesos.
- Pendiente Se controla cuantitativamente el rendimiento de los determinados procesos de desarrollo.
- Pendiente se conocen cuantitativamente las capacidades de desarrollo del grupo.
Gestión de calidad del software
- Hay planificadas actividades de gestión de la calidad del software (orientadas hacia el mantenimiento).
- Pendiente Hay definidos objetivos medibles en la calidad, y también sus importancias relativas.
- Pendiente Se cuantifica el progreso seguido hacia esos objetivos.
Nivel 5: optimizado
Objetivos
Llegados al último nivel, el objetivo es encontrar mejoras aplicables a los procesos (que ya son medibles merced al nivel 4). En particular, es posible mediante adaptaciones de los procesos no desviarse de las planificaciones y costes estimados.
Áreas clave de proceso
Prevención de defectos
- Pendiente Hay planificadas actividades de prevención de defectos.
- Las causas más comunes de defectos son identificadas (aparte de mediante la experiencia del trabajo común, mediante herramientas que detectan causas comunes como copy-paste).
- Se eliminan sistemáticamente dichas causas.
Gestión de cambios tecnológicos
- Pendiente Se planifica la incorporación de cambios tecnológicos.
- Las nuevas tecnologías son evaluadas para determinar su efecto sobre calidad y productividad. En nuestro grupo de desarrolladores hay bastantes que siempre experimentan con últimas tecnologías de por sí, así que encontrar algunas que sean aplicables al proyecto es casi natural.
- Las tecnologías nuevas apropiadas se incorporan a lo largo de la organización. Para ello ayudan dichos "early-adopters", habiendo localizado ya los problemas más comunes con las mismas durante su uso de las tecnologías.
Gestión de cambios en los procesos
Nos es posible obtener alta puntuación en este campo por ser un grupo pequeño y flexible de desarrolladores.
- Se planifican cambios continuos a los procesos.
- Toda la organización participa en la mejora de los procesos.
- Se mejoran continuamente los procesos, tanto el estándar como los de los proyectos.
Riesgos
Gestión de riesgos del proyecto.
Tabla de riesgos
Resuelto | Nombre | Tipo | Descripción | Probabilidad | Consecuencias | Prioridad de solución |
---|---|---|---|---|---|---|
S | Capa de dispositivos heterogénea | Proyecto | Las APIs de almacenamiento de snapshots son muy heterogeneas | Muy alta | serias | Media |
N | Nadie contrata almacenamiento | Negocio | Nadie contrata la opción de guardar los backups en el almacenamiento extra | Muy alta | serias | Baja (actualmente nuestra prioridad es la aplicación, y no el modelo de negocio que pudiera desarrollarse alrededor) |
S | Parones temporales | Proyecto | Parones en el trabajo debido a puentes o exámenes | Alta (pero predecible) | serias | Alta |
D | Limites de Rdiff | Tecnológicos | Los límites que imponen en los path pueden causar problemas | Alta | serias | Alta |
S | Falta organización | Negocio | Falta de coordinación entre los miembros del equipo | Alta | muy serias | Alta, estamos en ello |
N | No dominar nautilus | Tecnológico | No conseguir integrar el programa en nautilus | Alta | tolerables | Media |
N | Costes almacenamiento | Negocio | No sale rentable mantener el servicio de almacenamiento extra | Alta | serias | Baja (a priori, consideramos el trabajo sobre las características del modelo de negocio secundario. Además es un problema que, si está resuelto a nivel usuario individual, facilitaría su resolución a nivel almacenamiento compartido) |
S | Falta de herramientas UML | Tecnológico | No hay herramientas de UML para python | Media | serias | Muy Alta |
S | El equipo no rinde | Proyecto | La gente pasa del proyecto y se retrasa por falta de trabajo | Media | muy serias | Muy alta |
S | El programa no funciona en los laboratorios | Proyecto | Los ordenadores del laboratorio no tienen las tecnologías o permisos necesarios | Media | catastróficas | Muy muy alta (surgirá en cuanto empecemos a desarrollar código) |
S | No nos aclaramos con launchpad | Tecnológico | El launchpad nos da problemas y no nos aclaramos con el(machacamos cosas útiles y rompemos repos). | Media | seria | Alta |
N | El profesor suspende una entrega | Proyecto | No gusta el desarrollo seguido | Media | serias | Alta |
D | Rdiff-backup no cubre los casos de uso | Tecnológico | Rdiff no nos proporciona la funcionalidad deseada | Media | criticas | Alta |
N | Programa con funcionalidad insuficiente | Producto | El programa se queda corto en cuanto a funcionalidad. | Media | tolerables a serias (según cuánta funcionalidad falte, y cómo de crítica resulte) | Alta |
N | Demasiado lento | Producto | El programa ralentiza en exceso la CPU o memoria, o es demasiado lento haciendo backups | Media (muchas escrituras) | serias (el programa no sería demasiado usable) | Media |
S | Nos llevamos mal | Negocio | Discusiones dentro del equipo, faltas a las reuniones… | Media | muy serias | Baja |
S | No hay conexión a internet | Proyecto | Se cae el servicio y nos quedamos sin forma de trabajar durante un periodo de tiempo | Media | tolerables | Baja (ajena a nuestro control) |
N | Se cae el servidor de almacenamiento | Negocio | El servidor de almacenamiento extra se cae y provoca el enfado de los usuarios | Media | muy serias a catastróficas (según consecuencias de la caída) | Baja |
N | Ocupa demasiado espacio | Producto | El programa o sus backups ocupan demasiado espacio en disco. | Media (a priori no lo sabemos pero tenemos el limite impuesto por el laboratorio) | tolerables | Baja |
S | Integración con bazaar | Tecnológico | Alta probabilidad de romper repositorios a la hora de usar bazaar. | Media | tolerables | Baja |
N | Problemas con FAT32 | Tecnológico | Posibles problemas con los limites que establece el sistema de archivos FAT32 | Media | serias | Media |
S | Arquitectura mal diseñada | Tecnológico | Hemos hecho mal la arquitectura y hay que realizar cambios. | Media | criticas | Media |
S | No dominar sqlite | Tecnológico | No conseguir dominar sqlite | Media | tolerables | Media |
N | No llegar a dominar Fuse | Tecnológico | No conseguir dominar Fuse | Media | tolerables | Baja |
N | Se corrompe un backup | Producto | Un backup del programa se corrompe | Baja | catastróficas | Esperemos tener el proyecto avanzado cuando pase |
S | El programa no es fiable | Producto | El programa tiene problemas al ejecutar y es inestable, posiblemente corrompe backups. | Baja | catastróficas | Muy alta |
N | Wiki se cae | Proyecto | El wiki se cae y no podemos acceder a lo guardado en él o utilizarlo para seguir documentando | Impredecible (Baja) | serias / muy serias (según el tipo de caída, temporal o permanente, y si se pierden datos) | Muy alta, lo primero que vamos a solucionar. |
S | Problemas de personal | Proyecto | Enfermedades, deserciones de la asignatura, etc. | Baja | tolerables | Baja (Siendo pocos una deserción es más crítica, ya que necesariamente estamos más especializados, lo que aumenta el riesgo) |
S | No dominar GTK | Tecnológico | Nadie domina GTK en el grupo de trabajo | Baja | Muy serias (una interfaz usable es crítica para el éxito del proyecto) | Alta |
N | Programa difícil de usar | Producto | El programa es demasiado complicado de utilizar para el usuario medio, o poco intuitivo, o no es predecible y las opciones no hacen lo que se esperaría. | Baja | serias | Media/Alta (si es demasiado complicado de utilizar el usuario no lo usará; si es impredecible el usuario achacará -con razón- el uso incorrecto a los desarrolladores) |
S | No llegar a dominar Python | Tecnológico | No llegamos a dominar Python | Baja | Serias | Alta |
N | No llegar a dominar beagle | Tecnológicos | Nadie domina beagle en el grupo de trabajo | Baja | tolerables (la integración con beagle no es crítica para el éxito del núcleo del proyecto, es funcionalidad adicional) | Media |
N | Incompatibilidad de horarios | Negocio | Los horarios nos impiden reunirnos todo lo que nos gustaría | Baja | tolerables (según el grado de incompatibilidad) | Media |
N | Falta de tiempo | Proyecto | El tiempo para realizar el proyecto se nos queda corto | Baja | tolerables a catastróficas (en función de en qué punto del desarrollo del proyecto nos quedásemos) | Media |
S | No dominar dbus | Tecnológico | No conseguir manejar el uso de dbus (sistema de comunicación interproceso) | Baja | serias (dificultaría la separación backend-frontend) | Media |
S | No dominar distutils | Tecnológico | No conseguir manejar el uso de distutils (tecnología de instalación de python) | Baja | serias | Media |
N | Problemas con inodos | Tecnológico | El número de inodos posibles en un sistema de ficheros está limitado, y si no se tiene cuidado podemos toparnos con él. | Baja | serias | Media |
N | No llegar a dominar HAL | Tecnológico | Nadie domina HAL en el grupo | Baja | poco serias | Baja |
N | El repositorio se cae | Proyecto | El servidor donde alojemos el código se cae | Baja | insignificante | insignificante |
S | No llegar a dominar inotify | Tecnológicos | Nadie domina inotify en el grupo de trabajo | Muy baja | muy serias (componente crítico para que el conocimiento de qué es necesario archivar sea eficiente) | Alta |
N | Falta de material | Proyecto | No hay suficiente material para entregar por falta de tiempo | Muy baja | serias | Baja |
Comentarios:
Tabla de planificación de riesgos
Nombre | Planificación |
---|---|
Capa de dispositivos heterogénea | Uso de una factoría para homogeneizar la API. |
No llegar a dominar HAL | Investigar y comprobar si nos permite usarla para alguna funcionalidad de nuestra aplicación |
No llegar a dominar Fuse | Investigación de esta herramienta y ver qué nos puede proporcionar |
Problemas con FAT32 | Informarse sobre los límites de los sistemas de archivos en general y ver en qué nos puede afectar |
Falta de herramientas UML | Localizar herramientas que cubran, en teoría, ambas funcionalidades. Queda comprobar hasta qué punto lo hacen y familiarizarse con ellas. |
Límites de Rdiff | Investigar el alcance de ese riesgo y actuar en consecuencia. Los desarrolladores de rdiff-backup parecen tenerlo solucionado |
Rdiff-backup no cubre los casos de uso | Profundizar en la investigación y averiguar con certeza máxima su utilidad para nuestra aplicación. Cambiar a otro software o hacer que su wrapper supla la falta de características del mismo. |
El wiki se cae | A. Utilizar un medio secundario para almacenar la documentación y realizar backups periódicos. Trabajar durante las caídas sobre medios alternativos que permitan edición concurrente como google docs. B. Migrar el contenido del wiki (perdiendo la historia y posiblemente el formato) a una solución albergada por el equipo. Conlleva coste de administración, pero podríamos replicarlo en varios servidores privados |
No llegar a dominar Beagle | Estudiar su funcionamiento a fondo desde ahora. Alternativamente, no integrar búsquedas con contenido con nuestro proyecto. |
Nos llevamos mal | Intentar cuidar las formas a la hora de relacionarnos. Realizar actividades comunes no académicas como ir de cañas. |
Falta organización | Coordinarnos en subgrupos más manejables. Reparto de tareas más granular para poder subdividirse entre el número de personas. Establecer calendarios de trabajo. |
El programa no funciona en los laboratorios | Tener en cuenta los recursos de los laboratorios a la hora de ir desarrollando; o bien se desarrolla contra esa base de código (nautilus, etc) ligeramente obsoleta, o bien será necesaria una fase de backporting de cambios y cierta planificación para evitar incompatibilidades severas. |
No llegar a dominar inotify | Estudiar a fondo el funcionamiento de esta funcionalidad del kernel; posiblemente seguir ejemplos de proyectos diferentes que lo utilicen, como Rhythmbox |
No llegar a dominar Glade | Estudiar a fondo el funcionamiento de esta utilidad. Alternativamente, codificar las interfaces a mano sin un editor de las mismas. Ralentizaría bastante el desarrollo de la interfaz. |
No hay conexión a internet | Utilizar control de versiones distribuido que permite trabajar sin conexión (Bazaar). Generar la documentación offline en un solo ordenador, o utilizar herramientas de edición en red concurrentes. Cuando se recupere la conectividad, volcar de nuevo el contenido. |
El repositorio se cae | Utilizar control de versiones distribuido que permite trabajo offline e intercambio de cambios sin depender de un servidor central. |
Falta de tiempo | Intentar optimizar el tiempo disponible; separar el desarrollo en componentes lo más independientes posibles e intentar priorizar de más a menos crítico |
Se corrompe un backup | Tener alguna copia actualizada en algún equipo |
Ocupa demasiado espacio | Mantener un estudio del espacio que ocupa e intentar mejorarlo en el caso de que sea necesario. Buscar mejores codificadores de diferencias binarias (deltas). |
Demasiado lento | Una vez funcione el programa, optimizarlo. Estudiar alternativas a nivel de sistema de ficheros como ZFS, y tenerlo en cuenta en el diseño de componentes para una posible futura adición. Buscar alternativas a rdiff-backup (o desarrollar nuestro gestor de snapshots). Minimizar la resolución de los disparadores como Inotify o Cron |
Programa difícil de usar | Una vez haya una interfaz, trabajar con usuarios ajenos al proyecto y estudiar usabilidad sobre ellos. |
Programa con funcionalidad insuficiente | Separar en componentes y priorizar el desarrollo de los mínimos y críticos para el éxito del proyecto, dejando la funcionalidad adicional a priori por implementar. |
El programa no es fiable | Buscar la fiabilidad máxima desde el principio del desarrollo, usar suites de pruebas. |
Nadie contrata almacenamiento | Prever que esta situación se puede dar, asumir los menos gastos de negocio posibles para reducir pérdidas. |
Costes almacenamiento | Buscar un almacenamiento de coste asumible (servidores RAID de discos económicos), minimizar en lo posible el almacenamiento necesario, externalizar a backups en cinta (menor coste / GB) los datos poco usados por el cliente informándole de que recuperaciones de más de un cierto tiempo requerirán un cierto tiempo adicional. |
Se cae el servidor de almacenamiento | Tener la máxima redundancia rentable y protocolos para evitarlo en lo posible, manteniendo la rentabilidad del modelo de negocio. |
El equipo no rinde | Motivar para que todo salga adelante lo mejor posible, intentar optimizar el trabajo lo máximo posible |
Parones temporales | Llevar el trabajo al día; prever entregas y parones y tener el trabajo preparado antes de exámenes. |
Falta de material | Asegurarnos de que traemos siempre lo necesario |
No nos aclaramos con launchpad | Estudiar a fondo el funcionamiento de este repositorio |
Incompatibilidad de horarios | Trabajar con el que mayor grado de compatibilidad tenga, separar el trabajo en subgrupos y limitar las reuniones a los jefes de subgrupo para integración. Utilizar medios alternativos de comunicación (wiki, correo electrónico, mensajería instantánea) para no necesitar tanto reuniones en persona. |
No dominar GTK | Estudiar a fondo esta tecnologia gráfica. Alternativamente, limitarnos a una interfaz de consola para el programa (lo que disminuiría su calidad notablemente). |
No dominar nautilus | Estudiar el funcionamiento del explorador de Linux y las posibilidades de integración con el mismo a partir de proyectos diferentes. Alternativamente, renunciar a la integración y limitarse a una interfaz independiente de programa. |
No dominar dbus | Estudiar el funcionamiento de dbus a partir de proyectos diferentes. Alternativamente, desarrollar otro método de comunicación entre el backend de almacenamiento y los diversos frontend gráficos posibles (nautilus, interfaz independiente, consola, etc). |
El profesor suspende una entrega | Estudiar causas del fracaso e intentar corregirlas para realizar el desarrollo de la forma pedida |
Problemas de personal | A priori se reparten las áreas de trabajo por competencias, pero intentando documentar lo máximo posible en el wiki sobre tecnologías concretas a fin de poder retomar el trabajo de un miembro que faltase si fuera necesario. Además, no se deja a nadie solo frente a un área concreta, y se adoptarán estándares de documentación de código para el mantenimiento que fuera necesario. |
Integración con bazaar | Nadie sube a ninguna parte fuera de su grupo de trabajo, y de integrar se encargan personas determinadas. A tal fin se desarrollarán tutoriales de integración y guidelines de desarrollo específicos en python para facilitar la integración. |
Problemas con inodos | Probar exhaustivamente y con casos extremos la aplicación. |
No dominar sqlite | Buscar una alternativa, como MySql. |
Arquitectura mal diseñada. | Revisar el proceso e insertar los cambios necesarios. |
No dominar distutils | Buscar alternativa a esta tecnología. |
Necesidades tecnológicas
Lista de Software Necesario para hacer funcionar y desarrollar HD Lorean en los laboratorios de la facultad.
Crítico
- sqlite3
- libsqlite3-dev
- libsqlite3-0
- python-pysqlite2
- glade (versión >=3)
- glade-gnome (versión >= 3.4.0.2)
- gnome >= 2.20
- python-pyinotify
- rdiff
- python-nautilus
- libnautilus-extension1
- python-fuse
- libfuse2
- python2.4-dbg
- beagle
- rdiff-backup
- xdelta
Deseable
- python 2.5
- python2.5-dbg
- sqlite3-doc
- bzr
- pydev plugin de eclipse para python
- plugin de eclipse para modelado UML
- Plugin de eclipse para generar código python desde el uml.
- mkisofs
- wodim
- genisoimage
- tracker
- xdelta3
Estimación de costes
Estimación aproximada
Una sola persona a tiempo completo tardaría 3 años
~ 36 * (1 persona 1 mes)
Estimación por líneas de código
Optimista: 11000
Exagerada: 25000
Estimación (caso medio): 15000
Fórmula = (optimista + 4*estimación + exagerada)/6
(11000+25000+15000*4)/6 = 25.806 ~ 26 persona mes
Estimación por líneas de código y módulos
Modulo | Optimista | Estimación | Exagerada | Fórmula |
---|---|---|---|---|
Intefaz | 3000 | 10000 | 20000 | 10500 |
Consola | 300 | 400 | 800 | 450 |
Watcher | 2500 | 3200 | 6000 | 3550 |
Snapshot-core | 500 | 1500 | 20000 | 4416,67 |
DB | 800 | 1400 | 2500 | 1483,33 |
Fórmula = (optimista + 4*estimación + exagerada)/6
Total estimación líneas de código = 20399
Total/620 => 20399/620 = 32,9 ~ 33 persona mes
Estimación por puntos de función
~ 46 persona mes
Planificación de fase
Planificación de fase
Hitos principales:
- Octubre: Definición del proyecto, requisitos, casos de uso, riesgos
Al terminar octubre tenemos una idea general de cómo será nuestra aplicación: funcionalidades básicas, planificación sobre cómo llevarla a cabo, límites de hardware, de dispositivos, etc. En definitiva, el ámbito general del proyecto.
- Noviembre: Investigación principal de tecnologías
Habremos decidido qué lenguaje de programación utilizaremos, al menos para el núcleo del programa, así como las tecnologías de cada uno de los módulos del proyecto, o al menos varias opciones de implementación, para poder elegir más tarde con cual quedarse. Las tecnologías más importantes a investigar son: entorno gráfico que usaremos, tecnologías para el núcleo de copia de seguridad, de base de datos, y de comunicación interna y externa.
- Diciembre: Prototipo Alpha (prueba de integración)
Se tendrá el núcleo de la aplicación, o al menos ciertos módulos para comenzar a integrar. De este modo tendremos el esqueleto de la arquitectura, con las principales tecnologías investigadas por completo e implementadas para más adelante continuar con funcionalidades menos críticas.
- Enero: Fase de investigación; procedimiento de integración cerrado.
Subsiguiente prototipo de investigación de tecnologías (comunicación frontend / backend, planificación de tareas), si bien carente de la crítica de backup, restore, eliminación de copias, etc. Finalización del proceso de integración de bases de código distintas, quedando preparadas las metodologias para las fases de desarrollo posteriores.
Los principales riesgos tecnológicos están ya localizados. La arquitectura se ha desarrollado hasta quedar prácticamente cerrada, a falta de algunas apis importantes.
- Febrero: Repaso de documentación e investigación sobre funcionalidades adicionales
Esta iteración se centrará en documentar los nuevos procesos desarrollados y completar la documentación existente, pero dada la falta de tiempo por los exámenes, se reduce la cantidad de tiempo para el proyecto, con lo que no se esperan grandes avances. Se dedica a la investigación también porque, en nuestra experiencia, los exámenes son época de trastear con las más extrañas tecnologías en los ratos muertos que se debieran aprovechar para estudiar.
- Marzo: Prototipo Beta (funcionalidad crítica). Replanificación y reevaluación de viabilidad. Reasignación de personal.
Eliminados los riesgos tecnológicos, es necesario replantearse la planificación y la viabilidad de los casos de uso menos importantes para el tiempo existente. Se deberá concluir la construcción de la aplicación y sus funcionalidades críticas, con vistas a poder comenzar cuanto antes el mantenimiento y testeo de esta funcionalidad, que se preve largo; en los tres meses desde Enero la arquitectura está más que fijada y desarrollar debería ser previsible en tiempo y esfuerzo, al contar con prototipos funcionales de todas las tecnologías. Se tratará de avanzar en funcionalidad menos importante (al menos estudiando su viabilidad).
La semana santa dificultará la planificación, en función del personal y su disponibilidad por viajes, prácticas, etc.
Además, se debe tratar de completar lo más posible la documentación, en particular todos los tipos de diagramas UML utilizables en nuestro proyecto, así como identificar patrones de diseño tanto preexistentes en nuestro código pero no explicitados, como susceptibles de ser aplicados.
- Abril: Beta 2 (funcionalidad decidida completa). Mantenimiento, pruebas de usabilidad con usuario real, optimización en general, pruebas de empaquetado para distribuir.
Completar la funcionalidad ausente en la anterior iteración. Asimismo, preparar el despliegue de la aplicación, y iniciar un proceso de prueba intensiva, lo más automatizada que sea posible y razonable; consumido el margen de tiempo, se debe tratar de testear lo más posible durante el desarrollo de la aplicación -y no exclusivamente en Abril- para conseguir la máxima fiabilidad del programa, lo que es importante para su éxito.
- Mayo: Release: Empaquetar, y preparar la entrega (diapositivas, vídeo, web, presentación…). Mejorar la calidad todo lo que de tiempo (que será poco por la proximidad de los exámenes).
Perfil de personal
Adri
Administrador de sistemas y hábil en general. Autogestionado. Encargado de la gestión de sistemas del infierno, si se lo propone. Si es fácil, no es para él… C++ -er. Analista en general. Entusiasta donde los haya. Sincero ;). Buen gestor de personal; manejo del látigo eficaz, en particular del de 9 colas, lo que le convierte en el jefe de release ideal.
Carlos
Programador por encargo. Viciado en general. Viajero incansable.
Daniel
Primera baja del proyecto. M.I.A.
David
Databaser. Autogestionado. Programador por encargo bastante rápido; trabaja bajo presión. Asiduo del copy-paste (algo dadaista).
Diana
Analiza tus frases y suelta verdades como puños. Gran consejera. Programadora por encargo.
Eze
Gestor de todo lo gestionable. Maestro en tecnologías varias habidas y por haber. Hijo del bleeding edge (si funciona, actualiza). Capitán diccionario. Analista en general. Arquitecto (le falta la barba blanca solo). Entusiasta pero muy limitado en tiempo.
Fede
Líder nato y relaciones públicas. GNU master. Analista en general. Mejora la moral de la tropa. Hospitalario ^^. Hermano de Eze (por aquello de que también es hijo del bleeding edge). Fuente incansable de ideas a añadir a la apretada agenda.
Jorge
Autogestionado. Programador altamente competente. Tú fast, tú furious.
Mario
Redacta diversos tipos de documentos, observando escrupulosamente las reglas de redacción y ortografía (teniente diccionario, digamos). Programador por encargo. Relajado (paz, hermano).
Rober
Programador por encargo. Mejora notablemente la moral de la tropa. Formateador de cerebros. Currante nato.
Salva
Analista en general. Lead developer estilo ninja (no hace ruido, nadie le ve, pero aparecen sus líneas de código de repente). Master (del universo, digamos). Competente como programador. Entusiasta del proyecto, pero limitado en tiempo. Altamente experimentado. En ocasiones desvaría y hay que meterle en cintura ;) (por ejemplo, con el citado látigo de 9 colas).
Tabas
Programador por encargo. Dbusman y showman en general. Caja de sorprrresas.
Carmen
El nuevo fichaje. Programadora por encargo. Escritora hipermaniática. Friki en sus ratos libres (el resto lo es a tiempo completo)
Planificación iteración Noviembre
Tipo de iteración
Elaboración
Objetivos generales
Investigación I
Investigaremos las tecnologías que puedan ser necesarias para el desarrollo de nuestro código, intentando reutilizar el máximo posible para evitar implementarlo. A fin de ello hicimos una arquitectura preliminar en cuatro módulos:
- ui, o investigación de interfaces con el usuario
- watcher, o vigilancia de cambios en archivos a fin de guardar las copias de seguridad
- bases de datos, por su previsible uso en el almacenamiento del programa
- snapshots, o almacenamiento de las instantáneas de archivos que archivamos.
Arquitectura preliminar
Necesaria como se ha dicho en investigación.
Revisión documentación
Revisión de la calidad de la documentación del proyecto, completarla, etc. También se pidieron estimaciones de requisitos no funcionales de tiempo y espacio del proyecto.
Prueba del modelo de organización y tecnologías asociadas
Familiarizar al personal con el modelo de desarrollo propuesto y las tecnologías necesarias como el control de versiones.
Reparto de trabajo
- ui: Fede, Carlos, Rober y Tabas
- watcher: Jorge, Diana y Adrián.
- bases de datos: David
- snapshots: Salva y Dani.
Al margen del código, se ha repartido:
- gestión de calidad: Mario
- gestión de proyecto / wiki: Ezequiel
- comunicación con profesor / representante: Fede
Estimaciones de tiempo
No ha habido (se escribe la iteración a posteriori)
Seguimiento
Planificación iteración Diciembre
Tipo de iteración
Elaboración
Objetivos generales
Conseguir un primer prototipo que implemente funcionalidad real minima, si bien no creemos que vaya a dar tiempo.
Arquitectura
Diseñar una arquitectura que se aproxime lo más posible a la estabilidad, a falta de cubrir con ella los casos de uso que relegaremos a posteriores iteraciones por ser menos críticos. Para ello necesitaremos definir un API, una estructura de clases que nos permita el reparto de trabajo a partir de la arquitectura preliminar con que contamos, y definir la comunicación front-end y back-end cuanto antes.
Investigación II
Concluir la fase de investigación que sea necesaria para el prototipo, relegando a fases posteriores las tecnologías que se requieran para la funcionalidad menos crítica (servidor de almacenamiento, grabar a CD, integración con nautilus y beagle, etc).
Integración primer prototipo
Partiendo de la arquitectura definida, una vez exista el código mínimo para probar las funcionalidades dedicar el resto de la iteración a integrar, ya que por ser la primera vez previsiblemente llevará más tiempo y obligará a revisar los estándares de proyecto.
Reparto de trabajo
Se mantiene el de noviembre. Los objetivos de cada grupo son:
- Control de calidad: Mario se encargará, colaborando con los responsables de grupo, de iniciar la integración desde el principio para que lleve menos tiempo una vez esté el código listo, además de sus responsabilidades habituales.
- Gestión : Asegurarse de que los procesos de control funcionan; refinar iteraciones, reparto de trabajo, etc. Se encarga Eze, con posibles asistencias de terceros.
- ui : configurar preferencias; manual de usuario inicial. Concluir investigación dbus, y resto de tecnologías necesarias. Tabas, Rober y Carlos.
- interfaz consola: se encarga Fede, separándose del grupo de ui. Una interfaz básica de consola que llame directamente a las funciones más críticas del software para poder probarlo, y para investigar sobre el API que necesitaremos.
- (nuevo!!) lógica de programa : recibir órdenes de usuario y repartirlas por los subsistemas. Colabora estrechamente con la interfaz de consola y el wrapper de rdiff, inicialmente. De momento va implícita en la interfaz de consola; es previsible que se añada más gente en cuanto concluyamos la arquitectura.
- snapshot: un wrapper alrededor de rdiff-backup orientado hacia los casos de uso. Salva (responsable) y Dani.
- watcher: un módulo que parsee la configuración y avise a los diversos subsistemas. Además, vigilar cambios en archivos con inotify. Adrián es el responsable.
- Del parsing de fichero de configuración se encarga Adrián.
- De la vigilancia de cambios en archivos se encarga Jorge.
- Del pegamento en general entre submódulos se encarga Diana.
- base de datos: reiniciar la investigación sobre sqlite, esta vez basado en python. Crear un journal para poder reiniciar en caso de parada el software.
- El sql del journal está creado. De su revisión y prueba se encarga Adrián.
Estimaciones de tiempo
- 11 de diciembre: fecha límite para tener el código dispuesto para integrar. Como hay un puente justo antes prevemos que la funcionalidad no estará completa para entonces; queremos probar la integración cuanto antes porque puede conllevar a cambios importantes en el código de los módulos que, de haber mucho volumen de código, podrían ser más dificultosas. Nos reuniremos para juntar el código ("dónde está cada cosa")
- 18 de diciembre: fecha tope para terminar la integración
- 20 de diciembre: entrega.
Seguimiento
Planificación iteración Enero
Tipo de iteración
Elaboración
Objetivos generales
Aprovechando que, pese a las fiestas, la iteración de Enero es la más larga (una semana extra) y que en vacaciones hay más tiempo en general, pretendemos llegar al primer prototipo funcional completo de la arquitectura y con ello cerrar la fase de elaboración. Este prototipo debe incluir las funcionalidades mínimas de guardar backups, recuperar backups y listar los presentes mediante un interfaz gráfica además de la de consola; posiblemente se incluya también borrar snapshots, importante para mitigar el impacto en uso de disco de nuestra aplicación.
Además pretendemos fijar con ello la arquitectura del sistema para poder desarrollar el resto de funcionalidades, así como poder repartir mejor el trabajo desde ese momento (ya que, fijadas las interfaces, es más sencillo repartir las clases).
Por último, y como parte del objetivo de desarrollar un interfaz útil, es necesario comenzar el manual de usuario.
Primer prototipo funcional
Para conseguir este objetivo concreto actuaremos en dos frentes: por un lado, concluir una interfaz de usuario funcional, y por el otro reducir al mínimo el riesgo del núcleo de la aplicación (los backups).
Solucionar el riesgo de rdiff-backup
En la iteración anterior se localizaron problemas en este sistema de almacenamiento que suponen un bloqueo para continuar completando la funcionalidad de la aplicación (ver Apéndice A del informe de investigación de snapshot core). Este riesgo es de máxima prioridad para nuestra aplicación y debe ser resuelto en esta iteración, bien completando de algún modo la funcionalidad que nos falta en rdiff-backup para usarla bajo la nuestra, o bien desarrollando nuestro propio sistema de snapshots (lo que aumentará el riesgo mientras se finaliza, así como el tiempo de desarrollo y de comprobación de errores, que debe ser exhaustiva).
Fijar la arquitectura del sistema
Con vistas a poder finalizar la fase de elaboración lo antes posible, intentaremos en esta iteración consensuar una arquitectura del sistema lo bastante sólida y flexible como para cubrir nuestros casos de uso, en base a las interacciones que describimos en el brainstorming y las consiguientes clases y sus interacciones. Será necesario actualizar los documentos de arquitectura existentes, así como describirla en UML. Contamos no obstante con que las necesidades del desarrollo obligarán probablemente a varias revisiones de la arquitectura, quizá prolongándose otra iteración más.
Además, crear un interfaz y probar su usabilidad nos obligará a definir con más detalle la estructura de clases del GUI, por ahora relegada a un segundo plano.
Como ejemplo de la necesidad de este trabajo, la funcionalidad deseada de la clase Watcher aún no está reunida, sino que está distribuida por otros módulos que aún no se ajustan a la arquitectura deseada (por facilidad del desarrollo del prototipo). Se busca en suma evitar este tipo de problemas, que a medio plazo nos pueden limitar mucho y dificultar el trabajo.
UML
Según lo explicado en clase se modelará la arquitectura de clases y sus interacciones mediante diagramas UML. Para ello es necesario familiarizarse con las herramientas, así como localizar aquellas que permitan un flujo de trabajo bidireccional entre código en python y diagramas, para poder reducir el tiempo invertido. Todo ello implicará crear nuevos documentos donde se aclare al equipo el funcionamiento de los programas, así como probablemente modificaciones a los procesos establecidos de trabajo y los estándares, para poder facilitar la integración de código posterior y mejorar el reparto de trabajo, uno de los problemas importantes que se detectaron en la anterior iteración.
Explicitar prioridades de casos de uso
Con vistas a conseguir el prototipo en el tiempo que tenemos, es necesario partir los casos de uso lo más posible en subtareas, y priorizarlas para buscar el camino crítico sin el cual no habrá prototipo alguno. Una vez se tenga explicitado, se debe priorizar el desarrollo de los componentes de ese camino crítico. La importancia de los casos de uso es algo medianamente consensuado en el equipo, pero que aún no ha sido explicitado. En una estimación previa, los componentes sin desarrollar y por investigar más importantes son:
Finalizar gestión de preferencias
La configuración del programa está en una fase avanzada de desarrollo, pero aún no es funcional y probablemente deberá sufrir rediseños en función de problemas de usabilidad que se detecten. Sin embargo, una interfaz mínima que funcione para configurar el programa es importante, y será lo primero que se termine por estar ya muy avanzado.
Tabla de historia
Es una tabla a donde se migra la información de los backups desde el journal (que a su vez es donde se anota qué operaciones hay que hacer cuanto antes, para poder planificarlas y reiniciar transacciones en caso de fallo). Esta tabla necesita información adicional, como dónde se encuentra un archivo (no necesariamente local), su propietario y otros atributos (tamaño, permisos, etc). Toda esa información adicional, que debemos aún concretar, no es crítica para el prototipo pero sí para la funcionalidad de exportar backups, sea a CD o a disco duro externo, por lo que el diseño debe tenerla en cuenta y merece la pena una implementación preliminar de la misma.
Comunicación frontend / backend
Por ahora backend y frontend han seguido desarrollos separados, solo integrándose parcialmente para la demostración de tecnologías de la iteración de diciembre. Es necesario desarrollar la comunicación entre los mismos y también el API, a fin de que ambos equipos de desarrollo puedan probar su código teniendo en mente las necesidades y posibilidades de la aplicación completa, además de que hace falta para completar el prototipo sobre la arquitectura deseada. Para esta parte se utilizará la tecnología dbus de comunicación interproceso, ya investigada parcialmente pero aún sin prototipo funcional; por tanto es también prioritario.
Interfaz de navegación de archivos
Dado que el GUI ya tiene una interfaz de preferencias casi funcional, el siguiente paso necesario para poder demostrar el programa es una interfaz que muestre los archivos con copia de seguridad y permita navegar entre ellos, así como restaurarlos. Ello requiere del anterior punto para usar el backend real y consensuar cómo comunicarse con él, así como de cierto tiempo de desarrollo para terminar de dominar los componentes del toolkit gráfico GTK.
Integración con nautilus
Una de los requisitos funcionales es que la aplicación sea usable para cualquiera, lo que requiere que esté integrada de modo transparente en el uso habitual del equipo. Para ello se decidió que integraríamos nuestro código con nautilus, el explorador de archivos de GNOME, mediante su API de plugins; no obstante la investigación preliminar ha demostrado que apenas hay documentación del mismo. Por ser menos prioritario, se relega el desarrollo de la integración a Febrero.
Integración con Beagle
Beagle permitiría buscar dentro del contenido almacenado en nuestros backups, facilitando mucho el uso del programa e integrándolo aún más. No obstante el riesgo de este desarrollo es mucho menor, requiere en potencia mucho más tiempo y además depende de finalizar el modelo de almacenamiento final de nuestra aplicación, por lo que también queda relegado indefinidamente hasta que se juzgue adecuado.
Tecnología HAL
La tecnología HAL permite detectar dispositivos conectados al equipo y podría ser potencialmente útil para facilitar el uso de un disco duro externo como almacenamiento. Su investigación también queda relegada a una fase posterior, una vez el prototipo permita esa funcionalidad de externalizar la copia de seguridad.
Estimar requisitos de tiempo y espacio de la aplicación
A petición del cliente, trataremos de realizar una estimación del espacio y tiempo que usará la aplicación, que posteriormente iremos refinando conforme se optimice y se concrete más el código.
Nueva documentación.
Algunos de los documentos por escribir que se consideran necesarios para el trabajo son:
- Guidelines de código en Python: de cara a la integración. Cómo probar el código, dónde colocar todo, etc.
- Manual de integración: una vez se termine de investigar el modo más eficaz de usar el control de versiones distribuido, se debe informar al equipo de cómo se usa para facilitar el trabajo y permitir mejor integración entre grupos separados de desarrolladores.
- Guidelines para errores: desde unas directrices sobre qué información generar para logs del programa, hasta una jerarquía de excepciones que usar consistentemente en todo el programa.
- Manual de uso de la aplicación.
Reparto de trabajo
Los objetivos de cada grupo son:
- Documentación: Actualizar la arquitectura preliminar que tenemos según las Interacciones entre clases. Concretar la arquitectura del GUI y documentarla. En general, mantener el wiki actualizado según las exigencias de entregas de Gervás, y concluir la documentación deseada como objetivos. Ezequiel se responsabiliza, y Adrián ayudará como responsable de la integración en la iteración pasada. Además, de sobrar tiempo Ezequiel comenzará la investigación y el desarrollo de manuales sobre la integración de nautilus.
- Manual de uso: Como depende del GUI lo escribirán ellos.
- Watcher: Desarrollo de la clase Watcher e inicio del Planner. Adrián es el responsable y reparte trabajo.
- Adrián: Concluir Watcher. Comienzos de Planner.
- Diana: Terminar la funcionalidad de crontab y gestionar las peticiones de anacron. Ayudar en D-Bus Manager.
- Jorge: Concluir funcionalidad de Inotify handler; refinar funcionalidad.
- GUI: Carlos, Rober y Tabas. Responsable: Rober. Se ocuparán de concluir un GUI con la funcionalidad crítica desarrollada.
- BBDD: David. Como previsiblemente habrá poco trabajo y es dinámico según le vayan necesitando, ayudará en documentación y en Snapshot manager.
- D-Bus Manager: Atender a las necesidades del GUI y distribuir trabajo por el backend (previsiblemente a planner). Diana se responsabiliza.
- Diana: representante de backend que conoce dónde está cada cosa, y esbozará la clase planner junto con Adrián para repartir trabajo por el backend (inicialmente sin lógica de planificación). Ayudada por Adrián en ello.
- Rober / Tabas: Una vez investigado el modo de uso de dbus, enviarán las peticiones necesarias y recibirán datos del backend para poder presentarlos al usuario.
- Snapshot: Salva, Fede, David y Mario hasta que se solucione el riesgo, el más importante actualmente. Responsable: Salva, quien asignará trabajo concreto.
- Realizar estimaciones de tiempo y espacio del almacenamiento para la documentación.
- Integración de código: Adrián realizó la integración pasada; una vez aclaremos los procesos Ezequiel y David ayudarán.
Estimaciones de tiempo
- 31 diciembre (+/- 2 días): Terminado preferencias. Guidelines de integración; resueltos los procesos de tirar código ordenado y útil. Tomarse las uvas.
- 7 enero: Dejar de jugar con los regalos de los reyes. Watcher. Investigación terminada de dbus con prototipos funcionales; clase dbus manager funcionando para poder hacerle peticiones. Prioridad de desarrollo de los casos de uso establecida (lo que condiciona y modifica el alcance); plan más detallado de desarrollo en el seguimiento.
- 14 enero: Watcher integrado con inotify, cron. UML. Estimaciones tiempo y espacio. Toda la documentación complementaria salvo posiblemente manual de usuario sujeta a revisión del equipo.
- 21 enero: Primera integración parcial para detectar problemas en el seguimiento de las guidelines y la arquitectura. Cierre parcial de código. GUI funcionando completo, a falta posiblemente de resolver errores puntuales. Finalizar los objetivos a falta de las previsibles correcciones de errores.
- 25 enero, 14:00: Cierre total de código, comienzo de integración. Cierre de API obligatorio; bugfix únicamente a través de los integradores.
- 31 enero: entrega.
Como condicionante importante, en Navidades no todo el mundo podrá trabajar: Salva no tiene ordenador y por tanto tiene dos semanas inhábiles, Ezequiel estará fuera una de las dos semanas y tiene bastante carga de trabajo de otras asignaturas, Mario estará fuera, y en general todo el mundo está ocupado con PLG y recuperándose de los excesos navideños, por lo que no serán dos semanas demasiado productivas. Por otra parte, al no tener horas lectivas ni laborales esto se compensará en gran medida y prevemos que cunda.
Seguimiento
Ver seguimiento-enero.
Planificación iteración Febrero
Tipo de iteración
Elaboración
Objetivos generales
La iteración de Febrero, como estaba previsto en los riesgos de proyecto, no permitirá generar demasiados resultados debido a la presencia de exámenes en las tres cuartas partes del mes. Por tanto se dedicará a cerrar flecos que, por falta de tiempo, hayan quedado cerca de completar en la de Enero. Relegaremos a Marzo el conseguir un prototipo de funcionalidad crítica, así como reasignar recursos de personal, y revisar la viabilidad de los casos de uso, en concreto externalizar backups a medios como CD o discos duros externos, y la integración y usabilidad del interfaz. Además otro objetivo para Marzo será identificar claramente los patrones presentes en nuestro diseño y explicitarlos, y desarrollar los distintos diagramas UML por completo.
Completar módulos Watcher y clase ConfigFileManager
Estas clases son ya funcionales y solo falta terminar de documentarlas, añadir detalles como la detección automática de cambios a mano en el archivo de configuración, y en el caso del gestor de configuración cambiar los accesores genéricos por específicos para poder estandarizar el nombre y valores posibles de las opciones del programa, a fin de reducir los riesgos derivados de la no estandarización y de cubrir del todo la responsabilidad asignada a esta clase.
Unificar la jerarquía de excepciones del programa
En la misma línea del anterior objetivo, se buscará unificar la jerarquía de excepciones usada en el programa y documentarla, a fin de hacer HD Lorean más robusto y legible.
Migrar la información de depuración a la clase HDLogger
A fin de poder tener la información sobre el programa unificada en un único archivo de log y evitar tener que parsear salida por consola, lo cual no es viable para un demonio que debe correr en background, será necesario migrar toda la información de depuración que generemos para que utilice la nueva clase de logging. Ello debería ser sencillo, pero por el volumen de la base de código es probable que no se llegue a finalizar para Febrero. Unificar el logging permitirá, junto con las excepciones, automatizar los tests sobre la aplicación más fácilmente.
Concluir la integración de las bases de código
Si bien la integración se realizó durante la pasada iteración, queda sencillamente avisar a los distintos equipos de desarrollo del nuevo modelo de trabajo y migrar los repositorios para que todo el mundo trabaje con la base común de código. Será necesario por tanto actualizar la documentación de los procesos de trabajo para reflejar este nuevo hecho. Además se ha considerado deseable -de cara a facilitar las pruebas y el análisis sobre la aplicación- que dicha base de código común sea funcional como un proyecto de pydev (el plugin de desarrollo python para el IDE eclipse), trabajo que aún está pendiente de hacer.
Revisión de calidad de la documentación
El grueso del trabajo de revisión está centrado en los documentos de clases y su interacción de la iteración de Diciembre, pero por falta de un módulo no fue posible tener esta revisión lista para Enero. Se tratará de actualizar para esta iteración.
Decisión de la licencia final del código
Dado que utilizamos código diverso del mundo del software libre, habrá que investigar la licencia definitiva que podemos usar, que probablemente será GPLv2. Sería también conveniente configurar el entorno de desarrollo para que genere los nuevos archivos con una cabecera de licencia, y añadirla a los existentes (algo fácilmente automatizable).
Investigación sobre integración con nautilus y unit tests de python
A fin de poder desarrollar cuanto antes el análisis de viabilidad de Marzo, se intentará investigar en la última semana de febrero sobre las posibilidades prácticas de la integración con el navegador de archivos de Gnome. Asímismo se comenzará la investigación y documentación sobre la funcionalidad de unit test que ofrece python, con vistas a automatizar esos tests cada noche del mismo modo que está automatizada la generación de documentación.
Reparto de trabajo
Al no haber objetivos nuevos se mantiene el reparto de trabajo de la anterior iteración, con vistas a renovarlo y realizar movimientos de personal en la siguiente iteración de Marzo, probablemente reasignando responsables de grupo. Es probable que sean necesarias ayudas de todo el equipo con la documentación, ya que forma el grueso de los objetivos para Febrero y es responsabilidad de una única persona.
Estimaciones de tiempo
- 12 de febrero: Proyecto pydev listo sobre la base común de código .
- 25 de febrero: Todos hemos concluido exámenes. Iniciar preparación de la entrega, que debe consistir sobre todo en documentación y la planificación para Marzo.
- 29 de febrero: Entrega
Seguimiento
Planificación iteración Marzo
Tipo de iteración
Construcción
Objetivos generales
Pasados los exámenes, la iteración de Marzo se centrará en conseguir de una vez por todas una beta funcional del programa. Dado el imprevisto de la entrega y testeo con usuario real antes de Semana Santa, estructuraremos la iteración en dos partes; la primera, concluir la solución de los problemas pendientes de la aplicación y desarrollar lo que queda del GUI para poder demostrar la aplicación, y la segunda, una vez realizada la prueba del programa, solventar lo que descubramos en dicha prueba (bugs, problemas de usabilidad, etc) y mejorar la calidad de la aplicación y de la documentación con ello.
Concluir el GUI
Actualmente el GUI tiene una gestión de preferencias extensiva, si bien puede recibir bastantes mejoras de usabilidad y calidad. Para poder demostrar la aplicación necesitaremos algún interfaz para mostrar toda la información que se tiene almacenada -junto con otros datos como cuándo se guardó, y cuánto ocupa- y poder extraer snapshots, borrarlos, etc. Ello implica, además del riesgo de desarrollo propio por no estar aún empezado, problemas adicionales en la comunicación con el backend, ya que necesitamos un método de refresco de dicha información para evitar hacer polling -costoso y poco elegante, tanto en código como de cara al usuario-, lo que requiere de una ruta de información adicional inversa a la que teníamos y que vaya desde backend a frontend.
Asimismo, será interesante explorar alguna posibilidad de presentar ese feedback al usuario sin tener la aplicación principal en ejecución, como un icono de la barra de tareas, o popups de información avisando de problemas, o de la conclusión de alguna operación larga, lo cual podría incluso requerir de un pequeño demonio de usuario adicional para evitar hacer dependiente el backend de ningún tipo de interfaz gráfica, o en su defecto de funcionalidad añadida en el GUI que permita minimizarse a la barra de tareas.
La interfaz plenamente usable de la barra de tiempo queda relegada al siguiente mes a sabiendas de la escasez de tiempo, ya que se está investigando actualmente sobre la integración con nautilus y para reutilizar trabajo sería conveniente que, tanto desde nautilus como desde la aplicación, el código de visualización fuera el mismo. En cualquier caso se juzga útil y sencillo de usar tener dos tipos de vista, una con "todos" los backups, y otra relacionándolos directamente con su ubicación en el sistema de ficheros, para que sea como explorar el disco del modo habitual. Se comenzará en cualquier caso su desarrollo durante la segunda mitad de esta iteración, para anticipar posibles problemas.
Concluir el backend de creación de backups
Concluido el desarrollo aceleradamente del mismo, queda integrarlo con la aplicación, definir del todo sus API, testearlo y documentarlo convenientemente. A sabiendas de su importancia, es la prioridad máxima, junto al interfaz que permita su demostración, en nuestro desarrollo.
Nueva organización de trabajo
El segundo cuatrimestre ha cambiado los horarios de todo el grupo, y por tanto debemos encontrar un nuevo horario de reunión.
Abstraer dbus en el backend y frontend.
Dado que la aplicación era meramente un prototipo y la comunicación entre procesos aún estaba en pruebas, el código tiene la funcionalidad referente a dicha comunicación repartido en todas las funciones que lo necesitan. Se abstraerá dicha funcionalidad a clases independientes que se encarguen de dicha comunicación y actúen como proxys, para facilitar la depuración, separar en responsabilidades las clases y reducir problemas de refactorización.
Consola de la aplicación
Inicialmente creada para un prototipo, se ha recuperado su desarrollo y se tendrá una versión ejecutable en consola de la aplicación de funcionalidad completa, que además de ayudar con la automatización de las pruebas permitirá cubrir historias de uso (ejemplo: restaurar la configuración de xorg).
API de las bases de datos
Actualmente, y por flexibilidad en el desarrollo, usamos unas funciones bastante genéricas para el acceso a las bases de datos de la aplicación. Una vez van estando concluidos los módulos que las usan, queda cerrar esos subsistemas concretando en funciones específicas esos accesos, para conseguir la independencia real de la base de datos.
Testing
Durante la segunda mitad del mes, se deberá decidir la política sobre unidades de pruebas que seguiremos, documentarla y en su caso implementarla.
Documentación
Se deberá concluir de documentar los cambios en los procesos (testing, integración, entorno de desarrollo pydev), así como el UML y todo lo referente a patrones de diseño. Se realizará durante la segunda mitad del mes, pasada la entrega, y para el UML y los patrones de diseño se intentará contar con el equipo entero por considerarse imposible de otro modo y ser además importante para el examen de la asignatura.
Codetón
Hemos establecido una fecha para reunirnos en casa de uno de los miembros del equipo durante todo un fin de semana y avanzar el desarrollo. Pese al riesgo de baja productividad de no estar programando solos, se considera que será provechoso por la presión de la fecha de entrega, de estar todo el grupo juntos (donde quien trabaje presionará a quien no lo haga), y sobre todo por la facilidad de intercomunicación entre distintos grupos de trabajo para solucionar problemas referentes a la comunicación entre partes distintas del código. A tal fin se deberá tener el código "interno a cada parte" listo para entonces, y se empleará la mayor parte del tiempo en integración.
Despliegue del software
Dado el importante handicap de última hora de que no se pueda instalar software en linux en los laboratorios para nuestro proyecto, hemos de buscar formas de despliegue alternativas. Varias posibilidades están en trámite, entre ellas utilizar nuestros portátiles para ello, y combinarlo con uso de las X en remoto a través de la red de la complutense hacia equipos situados en otra parte, permitiendo ejecutar la aplicación "en remoto" albergada en terceros sistemas - a los que Adrián y Ezequiel pueden conseguir acceso- lo bastante grandes como para permitir varios usuarios a la vez operando.
Reparto de trabajo
Dado que una parte de la aplicación está concluida (watcher y las bases de datos) se reasignará el personal de ese grupo para apoyar en el resto. El nuevo reparto de personal queda como sigue:
- Interfaz de usuario: Daniel Tabas, Rober y Carlos, a los que se unen en principio Adrián y Diana. Asume la responsabilidad del grupo Adrián.
- Tabas acaba la comunicación backend / frontend, por ser el más experimentado trabajando con dbus, y la ruta de feedback que está por desarrollar, incluyendo posiblemente la investigación sobre systray y popups con libnotify.
- Mario se encarga de la consola, ya está trabajando en ello.
- Backend : se une Jorge como mercenario y sale Mario. Responsable sigue siendo Salva.
- Bases de datos: sigue al mando David, que deberá implementar a petición, ayudar con el testeo del backend (en lo tocante a inicializar esas bases de datos para su prueba) y cerrar lo antes posible el API de las mismas, documentándolo en el proceso.
- Documentación: Adrián y Ezequiel, ayudados por Salva cuando proceda. El UML lo haremos entre todos, cada uno ocupándose de su parte.
- Preparación de la entrega: A priori, Adrián y Ezequiel, que intentarán preparar la entrega (el despliegue).
Estimaciones de tiempo
- 5 de marzo: cierre parcial de código de cara a la codetón. Solamente minimizar lo que queda por hacer interno a cada módulo, y solucionar los problemas de la última integración.
- 8 de marzo: decisión sobre la integración con Nautilus.
- 7 de marzo al 9 de marzo: Codetón. Para poder dedicarnos plenamente a solucionar problemas de la comunicación entre partes del código, así como dependencias entre las mismas.
- 11 de marzo: cierre parcial de código. Solo bugfixes críticos a trunk, el resto en cada rama de desarrollo.
- 13 de marzo: Entrega en laboratorio.
- 14 de marzo al 23 de marzo: Semana Santa (aprox). A falta de reunirnos, aún no está establecido quién podrá trabajar durante esa semana, y probablemente será complicado reunirnos durante ella. No obstante se planificará trabajo recién entregado.
- lunes 24 de marzo: Nuevo cierre parcial de código, depuración, integración de todas las ramas de desarrollo. Documento de clases actualizado y UML de todos los equipos entregado.
- 27 ó 28 de marzo: Entrega final.
Seguimiento
Planificación iteración Abril
Tipo de iteración
Construcción
Objetivos generales
En esta iteración buscamos alcanzar un nivel de features suficiente para congelar el desarrollo lo antes posible, y a partir de ahí nos dedicaremos a solucionar todos los errores que detectemos, a mejorar la calidad del código que tenemos para facilitar su mantenimiento, y a mejorar el proceso mismo de desarrollo para aumentar la calidad del código y su robustez. Además tenemos en mente el poco tiempo que queda de desarrollo, y por tanto comenzaremos la investigación final que queda sobre el empaquetado del producto y su distribución final. Sin embargo, también hemos detectado durante las entregas de código una multitud de pequeñas mejoras que iremos aplicando en función de su dificultad, y de cuánto estimemos que pudieran afectar a la robustez del resultado final.
Mejoras en el backend
Pretendemos aplicar numerosas mejoras y ampliaciones sobre el núcleo de la aplicación, ahora que tenemos una base funcionando de la que partir. Posiblemente no haya tiempo de implementarlas todas durante esta iteración por imprevistos del desarrollo, pero dejamos constancia de ellas y se indica su prioridad.
- Eficiencia: hemos detectado algunos problemas que hacen a la aplicación poco manejable (al margen de su eficiencia algorítmica) afectando a su usabilidad y que requieren solución prioritaria. Las causas que estimamos más probables para estos problemas de rendimiento son:
- Conexión frontend / backend bloqueante: Como el frontend usa llamadas síncronas, queda esperando para cualquier operación grande de E/S y el resultado "visible" es un bloqueo del GUI. Para solucionarlo pasaremos a usar threads moderadamente. Esto genera una nueva serie de problemas, al tener que considerar si son seguras todas las funciones que puedan estar ejecutándose concurrentemente. Sin embargo en la planificación inicial ya tuvimos en cuenta la posibilidad de que apareciese este problema, por lo que utilizamos bases de datos (inherentemente concurrentes, aunque hemos encontrado bugs en nuestra implementación del wrapper y posibles limitaciones de la tecnología usada que están en proceso de evaluación y solución) y un módulo de planificación de operaciones (scheduler) que será quien implemente inicialmente los bloqueos necesarios para seguir manteniendo el mínimo de operaciones en ejecución garantizadas (en principio una, hasta investigar más a fondo), mientras no mejoremos la implementación para conseguir más granularidad.
- Expresiones regulares: Por ahora deshabilitadas. El usar expresiones regulares para los patrones de inclusión/exclusión de archivos implica que hay que expandirlas y añadir watches a cada archivo, lo cual es un proceso costoso y lento - en especial para las de inclusión - que además se ejecuta en el arranque o en cada cambio de la configuración. Al margen de investigar su viabilidad para el beneficio que aporta, también procuraremos ejecutar este proceso en un hilo que no bloquee la aplicación, algo a priori perfectamente factible.
- Conexión frontend / backend bloqueante: Como el frontend usa llamadas síncronas, queda esperando para cualquier operación grande de E/S y el resultado "visible" es un bloqueo del GUI. Para solucionarlo pasaremos a usar threads moderadamente. Esto genera una nueva serie de problemas, al tener que considerar si son seguras todas las funciones que puedan estar ejecutándose concurrentemente. Sin embargo en la planificación inicial ya tuvimos en cuenta la posibilidad de que apareciese este problema, por lo que utilizamos bases de datos (inherentemente concurrentes, aunque hemos encontrado bugs en nuestra implementación del wrapper y posibles limitaciones de la tecnología usada que están en proceso de evaluación y solución) y un módulo de planificación de operaciones (scheduler) que será quien implemente inicialmente los bloqueos necesarios para seguir manteniendo el mínimo de operaciones en ejecución garantizadas (en principio una, hasta investigar más a fondo), mientras no mejoremos la implementación para conseguir más granularidad.
- Consola: Como se indicó en el seguimiento del mes anterior, la consola actualmente no funciona debido a los numerosos cambios en el código durante la primera entrega. Aparte de dejarla de nuevo funcionando, investigaremos formas alternativas de conectarla al backend, pues así evitaríamos depender de D-Bus y la haríamos más resistente a problemas en el sistema, que es precisamente en las ocasiones en que sería más útil.
- Informe de errores: Durante la anterior iteración ya pusimos en práctica el módulo hdlogger encargado de centralizar todos los logs de la aplicación, así como el informe automatizado para los cierres no esperados. Es necesario por tanto limpiar la aplicación de cualquier print que quede que se haya usado durante el desarrollo, así como completarla con las llamadas necesarias para completar una traza de la aplicación en cualquier punto, lo que nos permitiría depurar más eficientemente. Además queda pendiente la investigación de apport, un módulo de ubuntu que integra el informe de bugs y la recopilación automática de información (trazas, sistema operativo, versiones de software instalado, etc) con la gestión de bugs de launchpad, subiendo automáticamente los archivos a la web del proyecto.
- Borrado de snapshots: Planificado para esta iteración, es crítico para alcanzar eficiencia en espacio y cubrir el diseño inicial de la aplicación el poder borrar snapshots individuales de modo eficiente y seguro. Esto serviría en un posterior desarrollo, junto con la planificación con Cron de eventos periódicos, para poder "caducar" la multiplicidad de versiones no necesariamente relevantes de los archivos más usados, quedándonos por ejemplo solo con versiones semanales de los documentos cambiados hace un año. Esto requiere, además, de una investigación a nivel de usabilidad para no confundir al usuario, y además haría buen uso y al tiempo facilitaría la posibilidad de externalizar backups (ya que un CD está limitado en espacio también), todavía no desarrollada y que quizás nos quede fuera de alcance debido a la falta de tiempo. Por el momento, por tanto, implementaremos el borrado explícito y manual, dejando el implícito para más adelante si nos es posible.
- Borrado automático: Si bien no se preve implementarlo, sería interesante investigar las implicaciones de implementar dicho borrado automático en función de varios criterios (fecha, espacio -sugerido en las preferencias-, u otros alternativos como relevancia) en el backend, especialmente para valorar en su justa medida su viabilidad.
- Sincronización: Se planifica investigar la sincronización con (y exportar a) dispositivos externos: Exportar a CD/DVD y sincronizar con unidades de disco externas. Se investigará desde el momento en que haya versión estable, a partir de segunda quincena.
- Estimaciones: Aconsejado tanto por sentido común como por algunas pruebas preliminares de los usuarios, necesitamos un feedback más explícito hacia el usuario sobre las operaciones en curso y, especialmente, sobre su estado de terminación. Para ello podemos crear estimaciones, ya sea en tiempo o en porcentaje, a fin de no dar la imagen al usuario de "aplicación colgada" -lo cual, según múltiples estudios de usabilidad consultados, lleva al usuario a creer que su acción no está registrada y a pulsar más veces, con lo que el problema de la espera puede agravarse. Ello implica, además de la ruta de feedback ya creada, de modificaciones en el backend para crear esos porcentajes o estimaciones temporales (que a su vez tienen implicaciones en el caso de realizar varias operaciones a la vez con threads), y mandarlos hacia el GUI. Un posible algoritmo inicial muy ligero en procesamiento para las recuperaciones -el caso más crítico- sería contabilizar el tamaño de disco a recuperar (una simple consulta a la base de datos), y tras recuperar cada archivo informar de cuánto se ha avanzado, de cuánto queda, y del tiempo invertido para poder deducir la tasa de transferencia y con ello estimar el tiempo restante. Además, probablemente necesitemos reincorporar al diseño una de las clases de estadísticas, que apareció inicialmente para centralizar esa información.
- Refactorizaciones: Hemos localizado varios puntos susceptibles de refactorización para conseguir más limpieza del código, que se tratarán lo antes posible para no dificultar el mantenimiento. En concreto, planificaremos el del módulo XDelta3Wrapper, de los más críticos de la aplicación, así como probablemente los wrapper de la base de datos.
- Mover directorio de backups: Una de las posibilidades de las preferencias del GUI, de una relevancia media, es mover dónde se van a almacenar los backups. Esto es útil para escoger particiones con más espacio o incluso unidades remotas montadas en el sistema (sincronización con discos externos). Sin embargo requiere de ciertas operaciones aún no implementadas en el backend, ya que ese directorio está deliberadamente ignorado para no entrar en un bucle recursivo (cambio registrado en el soporte físico de la base de datos -> registrar cambio -> genera cambio): hay que pasar a ignorar el directorio destino, mover las bases de datos sin detener la aplicación y, a continuación, volver a añadir los watches a la carpeta origen, que volverá a estar vigilada según se indique en el archivo de configuración.
Mejoras del GUI
Buena parte de las mejoras en el GUI vienen sugeridas por las pruebas con usuarios reales, que obligan a ver los defectos de usabilidad en lugar de posponerlos y permiten evaluar su importancia relativa. Algunas de las mejoras a implementar son:
- Feedback: En general hay poca o nula información sobre los procesos en curso y es muy importante para que el usuario no piense que la aplicación está colgada o no responde a sus interacciones. Pretendemos implementar una barra de estado con información desde la que, al pincharle, se eleve una ventana con los porcentajes agregados e individuales de las operaciones en curso al estilo del nuevo diálogo de operaciones de archivo de Nautilus 2.22, que encontramos muy usable. Además, otros medios interesantes son tooltips y burbujas desde el icono en la bandeja del sistema, invocados con señales desde el backend, para informar de eventos puntuales como "finalizada recuperación".
- Recarga de la ventana principal (bugfix): La ventana principal ya se recarga sin polling ante cualquier evento porque se lanzan señales desde el backend. Sin embargo al recargarse se vuelve a contraer el árbol por donde íbamos navegando a través de los snapshots, lo cual hace muy molesto el uso de la aplicación (porque este refresco es, a priori, imprevisible). Solventar este bug es de prioridad máxima, y probablemente sea muy sencillo.
- Reconsolidar glosario y nomenclatura: Pese a contar ya con un glosario específico, se ha descubierto confusión con los usuarios entre snapshots (instantáneas del estado del sistema completo en un punto en el tiempo) y backups (cada una de las versiones de un archivo; varios backups forman parte de un snapshot). Además, la metáfora de snapshot se solapa parcialmente con la de backup, lo que no ayuda. Es necesario y de prioridad alta encontrar una nomenclatura más clara e incluso sencilla, que a su vez implicará cambios en el GUI para responder a las nuevas metáforas (por ejemplo: si se intenta restaurar "un archivo" sin haber elegido snapshot, algo detectado en las pruebas de usuario, no se hace nada y resulta confuso; conviene concretar el comportamiento lógico esperable en ese caso, incluso si no permitimos que haga nada).
- Mejorar usabilidad del panel de snapshots: En general hemos observado que queda bastante por hacer para clarificar el funcionamiento de la aplicación a los usuarios noveles, y probablemente sea necesario implementar varias opciones distintas y probarlas todas ante usuario real para observar su reacción y determinar su conveniencia (por ejemplo, si conviene mostrar todo el árbol de directorios del disco duro aunque no se pueda recuperar más que lo vigilado, separando visualmente ambas clases de archivos; o solo mostrar lo que almacenamos en el sistema).
- Textos: Por una parte, las columnas necesitan títulos y textos más claros: probablemente haya que convertir el timestamp dado a "horas locales" -ya que el timestamp incluye la información sobre configuración GMT y de horario de verano que dificultan su lectura-, así como las unidades de tamaño a algo más legible, e incluso las operaciones.
- Formato de columnas: Además, sería interesante cambiar el formato de las columnas (quizá en cursiva, quizá con un background diferente para resaltar) para, de un solo golpe de vista, entender el historial de los cambios. Opciones visuales como "verde == creado, amarillo == modificado, rojo == borrado" son de fácil entendimiento en cualquier cultura y permiten seguir más fácilmente los cambios a un archivo dado.
- Ordenación de columnas: Los componentes GTK usados tienen facilidades para la ordenación de las columnas pinchando en los títulos de las mismas, como es esperable en un GUI habitual. Es prioritario (por indicado repetidamente en las pruebas con usuarios) que esta ordenación funcione para poder clasificar la información mostrada. Además sería conveniente que la búsqueda escribiendo texto, como en el resto de componentes GTK similares en aplicaciones como Nautilus, funcionase para poder localizar un cambio concreto rápidamente.
- Menús contextuales: Actuando sobre los distintos elementos del panel principal, deben proporcionar información relacionada con los mismos y relevante (recuperar, información, dejar de monitorizar, volver a monitorizar para un archivo que se tuvo y del que se retienen copias pero que ya no se vigila, etc). Prioridad media.
- Arrastrar y soltar: Sería muy usable poder arrastrar elementos hacia fuera del programa para restaurarlos en el destino. Implica bastante complejidad por la no uniformidad del entorno Linux en este ámbito, pero la investigación ya ha comenzado y se tratará de conseguir para esta iteración.
- Rutas mostradas: por el diseño trivial del código que se usó inicialmente como prueba de concepto, la ruta mostrada solo contiene el último nivel de las carpetas y no es lo bastante informativa. Además, desaparece cuando pulsamos un snapshot en lugar de proporcionar información, posiblemente extendida (atributos, tamaño del cambio realizado…) sobre el mismo. Es necesario y muy importante solucionar esta carencia de usabilidad.
- Previsualización rápida: Ante la presencia de múltiples cambios para un mismo archivo distanciados muy poco en el tiempo, puede ser complicado concretar cuál es la versión exacta que buscamos al no saber el tiempo exacto. Sería útil implementar una previsualización, o en su defecto que pulsar intro sobre un snapshot lo descomprimiera al directorio temporal y tratase de abrirlo con la aplicación registrada por defecto, para poder mostrar rápidamente al usuario lo que intenta recuperar. Ello es delicado para archivos grandes que resulten lentos de recuperar o que no estén presentes físicamente en el sistema (caso que aún no está implementado pero se daría con la externalización a CDs), lo que debe tenerse en cuenta en el API. No obstante, por falta de desarrolladores se postpone a priori esta mejora.
- Textos: Por una parte, las columnas necesitan títulos y textos más claros: probablemente haya que convertir el timestamp dado a "horas locales" -ya que el timestamp incluye la información sobre configuración GMT y de horario de verano que dificultan su lectura-, así como las unidades de tamaño a algo más legible, e incluso las operaciones.
- Refactorización: Parte del código del GUI relacionado con el panel principal se escribió con prisas para la primera entrega y es susceptible de muchas mejoras en código para hacerlo más fácilmente modificable. Esto es importante, ya que es el GUI lo que más debiera cambiar de aquí a la entrega final. En concreto, es conveniente una clase Columna para los treeview que además cambie el uso de números mágicos (0,1,2…) por constantes como FILE_SIZE, TIMESTAMP, etc.
- Asistente inicial: Desarrollado en las investigaciones iniciales sobre Glade, convendría actualizar el asistente inicial y activarlo en el primer arranque de la aplicación para que el usuario esté informado de cómo va a funcionar, así como añadirlo a la ventana de preferencias para poder reconfigurar la aplicación en cualquier momento.
- Traducción al castellano: Indicado en las primeras pruebas de usuario como un problema, estudiaremos su relevancia real, y el proceso de realizar las traducciones, que en principio launchpad nos permite hacer desde el propio entorno web. Ello nos familiarizaría con el proceso de localización en un producto de carácter internacional.
- Opciones de cierre de la aplicación: Actualmente diferenciadas entre el tray o bandeja del sistema y los menús de la aplicación, convendría unificar todos los puntos de salida (incluida la casilla "cerrar" de la ventana principal) en una única ventana que pregunte si solo se desea cerrar el interfaz o también matar al demonio en ejecución. Quizá sería interesante también incluir una opción avanzada en las preferencias sobre la configuración por defecto al respecto; las pruebas con usuario nos darán más información sobre la opción idónea.
- Mejoras a la ventana de propiedades: A su vez, sobre la ventana de propiedades se han encontrado diversos problemas a solucionar:
- Problemas de redimensionamiento: La ventana no permite su redimensionamiento para hacerse muy pequeña y en general no escala bien con los textos, además de presentar algunos problemas con las ventanas desplegables de propiedades. Solucionarlo requerirá de un fuerte conocimiento del modelo de contenedores de GTK. Otra investigación útil sería una propiedad de GTK mencionada por un tester, que abrevia con puntos suspensivos automáticamente los textos para dimensionarlos al tamaño que tienen disponible para mostrarlos. Su prioridad es media/baja por no afectar, de momento, a la usabilidad en exceso.
- Checkboxes de activación y rango de valores admitidos y por defecto: No debieran admitirse valores especiales como "-1" para indicar valores automáticos o por defecto, sino usarse checkboxes para ello y activar o desactivar los campos. Además, los valores por defecto deben consultarse al backend (no tiene sentido, por ejemplo, permitir que los backups caduquen cada cero días, pero no es responsabilidad del GUI conocer esos valores óptimos o iniciales). Es un problema importante, sobre todo de calidad del código, y por tanto tiene prioridad media / alta.
- Desactivar opciones no utilizadas: Por ejemplo, maximum size. Supone un importante problema de calidad a la hora del testeo con usuario final ("no, esa opción no funciona"), existiendo soluciones tan sencillas como desactivar el campo de entrada.
- Mejorar feedback sobre el estado de las casillas: Para ceñirnos al convenio de GUI extendido y mejorar la familiaridad para el usuario, se deben cambiar las opciones "guardar / cancelar" por el estándar "aplicar / aceptar / cancelar", desactivando además la casilla aplicar cuando no queden cambios nuevos por aplicar respecto al estado actual de las propiedades.
- Problemas de redimensionamiento: La ventana no permite su redimensionamiento para hacerse muy pequeña y en general no escala bien con los textos, además de presentar algunos problemas con las ventanas desplegables de propiedades. Solucionarlo requerirá de un fuerte conocimiento del modelo de contenedores de GTK. Otra investigación útil sería una propiedad de GTK mencionada por un tester, que abrevia con puntos suspensivos automáticamente los textos para dimensionarlos al tamaño que tienen disponible para mostrarlos. Su prioridad es media/baja por no afectar, de momento, a la usabilidad en exceso.
- Integración con Nautilus: La investigación ha determinado que la integración deseada con Nautilus es muy difícil y está fuera de alcance para los medios de que disponemos. Esto es principalmente debido a los importantes cambios sucedidos en la última versión (2.22) de Nautilus, que ha cambiado el backend que utilizan para mostrar sistemas de ficheros de Gnome-vfs a gvfs. El nuevo backend conforma un api aún no estabilizada y sujeta a cambios y muy pobremente documentada, pero la opción de Gnome-vfs está deprecada en el código y por tanto no justificaría el esfuerzo de desarrollo. Sin embargo, integraciones más pequeñas sí son sencillas mediante las extensiones Nython de Nautilus, como añadidos a los menús contextuales y pestañas adicionales de propiedades, así que investigaremos al respecto su desarrollo si no supone demasiado esfuerzo y tiempo.
- Opciones de borrado de snapshots: Cuando la funcionalidad de borrar esté desarrollada en el backend habrá que exponerla al usuario del modo más usable posible (por ejemplo, con opciones sobre los snapshots concretos además de mediante las propiedades, que de por sí son menos accesibles). Haría falta marcar snapshots tanto para borrar como para conservarlos y que no se borren automáticamente, dar opciones y feedback sobre la caducidad de snapshots, etc. Todas estas features dependen ante todo de que el backend esté desarrollado, pero se pueden ir pensando y diseñando.
Proceso de release
Como a partir de ahora las entregas van a ser muy frecuentes y periódicas, debemos tomar decisiones sobre el proceso de generación de baselines que seguiremos para juzgar qué código se entrega y cuándo se considera listo para ello. Esto es necesario para alcanzar unos mínimos de calidad y evitar entregar sin haber realizado unas pruebas previas lo bastante extensivas, o con bugs conocidos y resueltos en otras versiones del código. Por el momento queda pendiente además cómo gestionaremos el backporting de parches de versiones inestables a los baselines, para lo que es necesario que investiguemos las posibilidades que nos da la herramienta antes de tomar decisiones al respecto.
Otras medidas a tomar al respecto son:
- Seguimiento de entregas: A fin de poder presentarlas juntas en junio, es necesario recopilar la información sobre qué se entregó en cada fecha, añadiendo esa información al wiki y centralizando también las encuestas a usuarios hechas durante las mismas, y demás información relevante. Además, es conveniente etiquetar las entregas mediante la herramienta de control de versiones para poder seguirlas.
- Modificaciones al proceso de desarrollo: Apenas modificado desde la propuesta de modelo de desarrollo inicial, para poder gestionar la calidad y los baselines más cómodamente, usaremos un repositorio adicional llamado testing, que esté dedicado exclusivamente a la estabilización del producto final, tal y como se indicó en el seguimiento del mes anterior. Además, evitaremos realizar planificaciones tan detalladas como esta: en adelante los bugs y features deseadas se añadirán directamente al gestor de launchpad, desde donde podemos realizar más fácilmente y centralizado el seguimiento del desarrollo de los mismos, así como asignar tareas.
- Mejoras de distribución del código: Varias son interesantes de investigar:
- Refactorización de paths: El script de instalación debe tener en cuenta los problemas de paths relativos en la aplicación para que pueda funcionar instalada en cualquier subconjunto de carpetas (según se elija en el instalador, que toma los valores por defecto de cada sistema donde se distribuye). Ello es una mejora investigada pero aún por aplicar, y prioritaria.
- Paquete de Ubuntu: A poco tiempo de la entrega final, es necesario terminar de desarrollar la tecnología de instalación y crear un paquete .deb que pueda instalarse directamente en la distribución objetivo: Ubuntu. Ello requerirá de una notable investigación al respecto, pero debería ser medianamente automatizable a partir del script que tenemos.
- Versionado: A la vez que establecemos una política de baselines, conviene incluir esas versiones en el código para seguir la pista de lo que distribuimos más fácilmente. Además, esto nos permitiría detectar versiones antiguas de los archivos que usamos en la aplicación, reduciendo el riesgo de utilizar configuraciones que ya no son funcionales en la versión actual, o que hayan sufrido diversas refactorizaciones que hicieran que no funcionase correctamente.
- Documentación interna del código: en lugar de distribuirla junto al código, sería interesante generarla con el script de instalación si la herramienta doxygen está presente. Así se distribuye un paquete mucho más pequeño, y no hay riesgo de distribuir documentación interna obsoleta. También convendría incluir parte del UML cuando esté listo.
- Testunits: la aparente dificultad de desarrollar unidades de prueba válidas, así como la reacción inicial negativa del equipo a las mismas, debe ser evaluada en función de los beneficios reales que nos aportaría. Probablemente sea necesario un desarrollador altruista que ponga en marcha el marco de funcionalidad común a todas, para facilitar el posterior desarrollo. Valoraremos la posibilidad de explicitar con una testunit cada bug encontrado durante la segunda mitad del desarrollo.
Formación nuevo personal y reasignación de tareas
La formación del nuevo miembro del personal para que sea lo más productiva posible cuanto antes supondrá de un esfuerzo extra que debemos repartirnos en la medida de lo posible. La estamos formando, por tanto, entre todo el equipo en todo lo relevante y crítico (modelo de documentación, procesos de desarrollo y toma de decisiones, control de versiones…), y estimamos que será productiva en breve tanto en calidad de la documentación como en testeo de la aplicación, dos tareas para las que el conocimiento del código necesario es menor.
Gestión de la calidad
Durante la pasada iteración hemos concluido que los actuales problemas de calidad son excesivos, y por tanto tenemos que poner en marcha -pese a la carencia de personal- un plan de calidad, e incluirlo en nuestros procesos de desarrollo. Una vez superemos la siguiente entrega, congelaremos temporalmente el desarrollo de nuevas funcionalidades y nos centraremos en mejorar lo máximo posible la calidad, tanto en código como en bugs, de la aplicación, mientras decidimos un proceso de control de calidad adecuado a nuestras posibilidades reales. También exploraremos el uso de herramientas de control de estilo de código específicas de Python como Pylint, capaces de detectar copy - paste y otros problemas potenciales.
Evaluación y mejora de Software Capability Model
El ejercicio de clase acerca del modelo de capacidades de software ha puesto de manifiesto ciertas carencias que debemos suplir para alcanzar el requerido nivel 2. Inicialmente es necesario formalizar las notas tomadas durante esa evaluación, y a continuación trabajaremos sobre los aspectos que aún nos faltan, intentando no solo superar ese nivel sino aproximarnos al siguiente, ya que nos faltarían pocas cosas para ello.
Iniciar revisión documentación
Junto con la parada de control de calidad a mitad de la iteración, iniciaremos una profunda revisión de la documentación para ponerla al día en aquellos aspectos en que esté obsoleta que sean más importantes, así como para añadir a la página que centraliza la entrega final aquellos documentos que aún falten. Con el UML en progreso, también revisaremos su exactitud al lado del código y ampliaremos la documentación relativa al mismo.
Investigar ERIC
Hemos encontrado un nuevo entorno de desarrollo integrado que permite depurar -a diferencia del que utilizamos, donde fallan varias cosas para ello- y que probablemente genere diagramas de herencia UML desde el código. Será necesario investigar su uso y conveniencia a estas alturas del desarrollo.
Reparto de trabajo
Probablemente debamos flexibilizar el reparto de trabajo actual, al haber demasiadas subtareas y poco personal. En principio mantenemos los grupos de trabajo de la anterior iteración, con la excepción de Salva que probablemente pase al grupo de GUI. Algunas responsabilidades específicas son:
- Tabas y Robs: Opciones para salir + investigación drag and drop. Mejoras varias al GUI (Tabas: redimensionamiento).
- Carlos: iconos treeview. Mejoras varias al GUI.
- David: mantenimiento de la base de datos. Traducciones aplicación. Investigación de uso de Pylint.
- Mario: arreglar la consola.
- Jorge: investigación sobre inotify para hacerlo compatible con gedit. Detener notificador. Bugfixing de esa zona en general.
- Adri: coordinación de release. Testing en general.
- Carmen: revisión entrega documentación. Testeo de la aplicación. Posiblemente testunits.
- Fede: borrar snapshots. Junto a Salva, refactorización de XDelta3Wrapper.
- Diana: UML
- Eze: puesta al día de documentación. Decisiones de proceso de desarrollo. Investigación deploy alternativo. Investigación packaging. Investigación Nautilus adicional.
Estimaciones de tiempo
- 7 Abril:
- Iconos del treeview cambiados para que sean diferenciables a simple vista las carpetas de los archivos.
- Funcionalidad de borrar los snapshots ya desarrollada y por testear.
- Base de datos thread-safe.
- Backups ordenados por el usuario funcionando.
- Bugs de encoding solucionados.
- Detener notificador de cambios.
- 14 Abril:
- Desarrollo congelado.
- Bugs resueltos: recargar vista contrae las carpetas desplegadas
- La mayoría de los problemas de rendimiento detectados y en solución.
- Consola funcionando.
- Estabilización de la entrega. Testeo intensivo.
- Formación del nuevo personal completada.
- 17 Abril:
- Entrega de código.
- Inicio de la revisión de calidad.
- Descongelado de features en paralelo al bugfixing.
- Inicio de revisión del UML.
- 24 Abril (estimado):
- Prints eliminados de toda la aplicación.
- Decisión sobre los testunits.
- Investigación sobre Pylint terminada; integración con proceso de calidad si es relevante.
- 28 de Abril:
- Documentación actualizada en el wiki.
- Nueva congelación total de features.
- 1 de Mayo: entrega (telemática) de la documentación del mes.
- 8 de Mayo: siguiente entrega de código (ya que el 1 y 2 serán previsiblemente puente).
Seguimiento
Planificación iteración Mayo
Tipo de iteración
Elaboración / Transición
Objetivos generales
Dado que nos acercamos ya al final del curso y el tiempo disponible por parte de todos se reducirá bastante para poder estudiar y trabajar en el proyecto, nos planteamos que será poco el desarrollo adicional que podamos hacer, y crearía demasiados riesgos sobre un aspecto tan crítico para nuestro proyecto como la robustez de la aplicación. Por tanto optamos por pulir lo más posible lo que tenemos, preparándonos para un hipotético mantenimiento, y preparando la también importante presentación y la documentación, tanto de cara a la entrega como a preparar entre todos el examen.
Sin menoscabo de esto, es posible que hacia la mitad de la iteración se escinda un pequeño grupo de "fuerzas especiales", como se les denominaba en las charlas de representantes de grupos de otros años, para intentar desarrollar alguna feature extra.
Por tanto, hemos decidido congelar el código y dedicar 2 semanas a documentación y calidad. Una vez finalizadas, nos escindiremos en grupos de presentación, bugfix, features y calidad, probablemente con solapamiento de responsabilidades por nuestro escaso número. Esto lo decidiremos a mitad de iteración, y en función de la disponibilidad prevista del personal.
Calidad y documentación
- Revisión de calidad del código: Se planifica que cada uno revise el código en el que ha estado trabajando (ya que es la persona mejor cualificada para reescribirlo) y además otra sección adicional, de modo que todo sea revisado por al menos dos personas.
- Cambiar los términos snapshot y backup por versión en toda la aplicación.
- Preparar la presentación para la entrega final.
- UML: patrones presentes en nuestro código
- Despliegue de la aplicación definitivo y documentación del mismo.
- Actualizar riesgos.
- Centralizar apuntes de cara al estudio de la asignatura.
Features
- Asistente inicial de la aplicación.
- Porcentajes y estimaciones de tiempo en la aplicación para proporcionar feedback.
- Ordenar por columnas la lista de snapshots.
- Caducar -> Exportar a CD
- Mover el directorio del backup finalizado.
- Empaquetado definitivo de la aplicación (instalador, etc).
- Precacheo del árbol en el GUI para mayor eficiencia.
- Refactor watcher: hacerlo independiente de inotify.
Reparto de trabajo
Revisión de calidad
- Salva - GUI + apuntes junto a Eze.
- Jorge - GUI
- Fede - Watcher
- Rober - Watcher
- Mario - snapshot-manager
- Tabas - snapshot-manager
- Adri - base de datos
- David - Cron
- Carlos - consola
- Diana - hará una revisión general siguiendo el UML
- Carmen - hará una revisión general siguiendo el UML
- Eze - la documentación
Features
- Wizard - Carlos
- Porcentajes - Tabas y Fede
- Ordenar por columnas - Carlos y Rober
- Centralizar apuntes - Eze, Salva
- Caducar -> Exportar a CD - Salva y Fede (Si da tiempo)
- Mover el directorio del backup - Adri
- Empaquetado - Eze
- Precacheo del arbol en el GUI - Tabas
- Refactor watcher: hacerlo independiente de inotify
Estimaciones de tiempo
- 9 de mayo: Primera entrega.
- 19 de mayo: Nueva organización para preparar la entrega final. Empaquetado listo. Congelado final de código salvo grupo de "fuerzas especiales".
- 22 de mayo: Última entrega antes de la final.
- finales de mayo / principios de Junio: Reunión un día común para preparar el examen.
Seguimiento
Ver seguimiento-mayo
Seguimiento
Aquí centralizamos el seguimiento cada iteración, del plan de fase, de la documentación, etc.
Plan de fase
A lo largo del desarrollo de la aplicación nos hemos encontrado con diversos problemas que podrían haber modificado el plan de fase original, pero por suerte solo uno de ellos nos obligó a ello. Incluso la incorporación de un nuevo miembro al equipo ha podido ser asimilada sin mayores dificultades.
En Enero, tras una iteración muy poco productiva debido a las vacaciones y también debido a los problemas encontrados con rdiff, la planificación de fase sufrió una modificación que introdujo un retraso en la entrega del primer prototipo Beta de Enero a Marzo.
Esto produjo un reajuste de la iteración de Enero que se convirtió en una de investigación de nuevas tecnologías que pudieran sustituir a la descartada. Además la iteración de Febrero se vio ligeramente modificada, aunque mantuvo el objetivo principal de investigación sobre nuevas funcionalidades.
Además, la iteración de Abril se vio afectada pasando a ser el objetivo principal la entrega de una segunda beta cuando estaba programado empezar con el mantenimiento y hacer pruebas de usabilidad con usuarios reales. Ello quedó atrasado para Mayo junto con lo que ya tenía asignada esa iteración.
Seguimiento de las iteraciones
Aquí comprobamos objetivos cumplidos y fallados del plan de iteración, y establecemos medidas correctoras al respecto.
Noviembre
Objetivos cumplidos
La investigación ha alcanzado un gran nivel de éxito, ya que se ha encontrado un módulo escrito en python que resuelve gran parte del problema del almacenamiento y gestión de instantáneas, sobradamente probado. Asimismo la documentación ha ganado en calidad mucho, y es bastante extensiva.
En cuanto a la organización del modelo de desarrollo, a falta de probar la integración de módulos diversos de momento es un éxito, ya que el personal se ha adaptado relativamente rápido al control de versiones.
Objetivos no alcanzados
La investigación ha llevado a cambiar de lenguaje de programación usado, lo que obliga a posteriores fases de investigación para familiarizarnos con el mismo; hubiera sido deseable concluir ya la investigación. Las estimaciones de requisitos no funcionales no ha dado tiempo a hacerlas, ya que la investigación ha cambiado bastante la orientación de la práctica.
Riesgos reducidos
Buena parte de los tecnológicos; confirmamos que las tecnologías responden a lo que necesitamos de ellas, y no encontramos ningún escenario de uso que no quede cubierto por ellas.
Nuevos riesgos
Usar un nuevo lenguaje de programación como python, con el que no tenemos familiaridad ninguno.
Tiempo real empleado
Al no haber una planificación previa esta sección es irrelevante, pero informalmente se pretendía tener lista la investigación de las tecnologías repartidas para diciembre, y se ha conseguido.
Conclusiones
La iteración ha resultado exitosa ya que ha reducido mucho los riesgos de proyecto, al encontrar una tecnología que reduce mucho los tiempos de desarrollo y cubre funcionalidad. Se han cumplido plazos (informales).
Diciembre
Objetivos cumplidos
En la iteración se han logrado dos prototipos. Por una parte, una GUI funcional que permite editar las preferencias (aunque aún no leerlas), además de mostrar una ventana de log en el menú View para comprobar que se monitorizan la creación, borrado y modificación de los archivos o carpetas configurados.
Por otra, se ha diseñado una aplicación que, mediante consola, permite realizar backups, listarlos y recuperarlos. Cuando se realiza un backup de algo que no estaba en las preferencias la aplicación añade dicha carpeta a las mismas.
Durante la integración hemos trabajado sobre los problemas de arquitectura y organización de código que deberemos utilizar, lo que nos resultará útil para futuras integraciones. El brainstorming ha ayudado a definir la arquitectura respecto a nuestras estimaciones iniciales, ayudando a tener en mente algunos casos de uso (como Exportar a disco externo importantes que hemos relegado para fases posteriores del desarrollo. Este caso y su simétrico, importar, cubren la importante funcionalidad de poder recuperarse después de un fallo catastrófico (formateo), o de un cambio de equipo, siempre que se conserven copias de seguridad.
La investigación en esta iteración se ha centrado en:
Python
Todos los equipos de desarrollo han debido familiarizarse con el nuevo entorno y bibliotecas; el nuevo lenguaje de programación no ha traído demasiados problemas. Se han puesto de manifiesto algunas carencias en la documentación interna (tutoriales) que deberán ser solventadas; no era posible detectarlo hasta que se realizaran las primeras integraciones y se probara un poco más el lenguaje.
Rdiff-backup
Por decisión común se decidió en la anterior iteración utilizar la aplicación rdiff-backup como medio de gestión de snapshots. Así, el desarrollo se limitaba al diseño de una API general expuesta al resto de módulos y una serie de wrappers que envolviesen el funcionamiento de la aplicación.
La investigación fue corta pero concluyente y se encuentra reflejada en el apéndice I del informe de investigación sobre snapshot-manager.
El desarrollo fue apresurado y difícil debido en primer lugar a la escasez de tiempo disponible por las circunstancias académicas y personales de los desarrolladores. Aun así, la entrega se efectuó a tiempo y la API cubría algunos de los casos de uso críticos expuestos en el documento correspondiente.
Uno de los principales problemas fue causado por el abandono de uno de los integrantes del equipo HD Lorean asignado precisamente a este módulo. Las consecuencias de la marcha de nuestro compañero resultaron en un aumento de la carga de trabajo del otro componente del equipo que se vio desbordado; un riesgo que no podemos mitigar completamente debido a la falta de personal, pero que en adelante mitigaremos mediante rebalanceos más frecuentes del trabajo. Además el análisis de alcance y el reparto de objetivos era incompleto, ya que no estaban explicitadas las prioridades; queda pendiente para la siguiente iteración.
La investigación a fondo de la aplicación ha puesto de manifiesto varios problemas. Por una parte, rdiff-backup genera deltas inversas, a diferencia de lo que creíamos: ello que cambia buena parte de las presuposiciones que hacíamos sobre el programa (tanto en funcionamiento como en requisitos), y a priori dificultaría el borrado de snapshots concretos, una funcionalidad necesaria entre otras para reducir el uso de disco. Además, por estar orientado a una granularidad mayor que la nuestra no ofrece la posibilidad de actualizar un archivo individual en el backup: el escaneo siempre es sobre los tiempos de modificación de la carpeta completa monitorizada, lo que inutiliza inotify y ralentiza el programa respecto al uso que queremos darle. Por otra parte, en el desarrollo de la arquitectura quedó patente que una base de datos que indexe contenido es necesaria aunque se use rdiff-backup debajo, lo cual limita aún más sus ventajas. Queda pendiente la investigación sobre si es posible y merece la pena solucionar estos problemas, o se debe descartar el uso de rdiff-backup y buscar alternativas o construirlas desde cero.
Cron
Administrador regular de procesos en segundo plano (véase demonio) que ejecuta programas a intervalos regulares (por ejemplo, cada minuto, día, semana o mes). En un primer momento se intentó modificar el crontab del usuario, pero para acceder a él se necesitaban privilegios de superusuario. Un requisito de la aplicación es que ésta se pudiera ejecutar como usuario (por ser el usuario medio el objetivo del desarrollo), y no necesariamente como administrador, lo cual suponía un problema.
Linux nos otorga ciertos comandos para poder acceder al crontab de forma segura, sin requerir estos permisos. Entre ellos existe uno que nos lista el contenido del fichero. La solución adoptada es abrir un pipe asociado a la salida de este comando para obtener su contenido, el cual verteremos en un archivo temporal. Este archivo temporal podemos modificarlo a nuestro antojo (manteniendo siempre la sintaxis de cron). Por último actualizaremos el crontab del usuario con este archivo temporal.
Un problema es que cron supone sistemas que están operativos siempre, y por ello si el sistema no esta activo en el momento de ejecutar la tarea, esta simplemente se pierde. Sin embargo, un pc personal suele apagarse y encenderse con cierta frecuencia, por lo que tenemos que buscar algún otro mecanismo para solventar este problema.
Anacron es un programador de tareas similar a cron, con la diferencia de que no necesita que el sistema esté en ejecución. Se puede utilizar para ejecutar los procesos que cron ejecuta normalmente de forma diaria, semanal y mensual. Lo más recomendable es que se utilicen ambos, cron para intervalos pequeños de tiempo, y anacron para intervalos mayores (a partir de un día). Con Anacron no se ha conseguido solucionar el problema de los permisos, por lo que posiblemente, si no se encuentra la manera, haya que decidir que nos interesa más, si usar anacron y ejecutar la aplicación como root o usar cron y que sólo se hagan las copias de seguridad cuando el equipo esté encendido.
Además se investigó fcron, similar a anacron, pero por el momento queda descartado, ya que instalarlo modifica instalaciones por defecto de Ubuntu.
Inotify
hemos descubierto que los límites por defecto se pueden saltar y definir según nuestras necesidades, lo que mitiga el riesgo de que no sirviera o de que dificultara en exceso el desarrollo. La funcionalidad que ofrece este componente está prácticamente concluida.
Formato de ayuda de YELP (ayuda de GNOME)
esta todo en xml y además resulta incómodo a la hora de editar. Sin embargo se ha localizado un editor (Conglomerate) específico para el formato docbook, todavía en desarrollo.
Objetivos no alcanzados
No ha dado tiempo a estabilizar la arquitectura ni a realizar la API; queda como tarea pendiente para la iteración de enero a fin de poder pasar a construcción cuando se concreten las clases y se realice el UML.
Riesgos reducidos
- La incompatibilidad de horarios ha sido mitigada al establecer como estándar el martes por la tarde para las reuniones, el día que viene "menos mal" a todo el grupo.
- El riesgo "no llegar a superar inotify" está cubierto e implementado, así como el riesgo que apareció durante la investigación de no tener suficientes handlers.
- GTK razonablemente superado; ya hay un GUI, pero aún falta funcionalidad por implementar en el mismo.
- Riesgo de corrupción de backup queda cubierto *siempre y cuando* se utilice rdiff-backup, que implementa checksums.
- Launchpad reducido, lo hemos usado todos.
- No lograr funcionar sin internet está superado, dado que dependemos menos del wiki y el control de versiones es distribuído (en última instancia puede funcionar "punto a punto", sin pasar por los servidores de launchpad).
Nuevos riesgos
- rdiff-backup no cubre los casos de uso, lo que nos aprieta bastante los tiempos de desarrollo y puede suponer un bloqueo para seguir avanzando con la aplicación (mejores interfaces, etc), así como dificulta su desarrollo respecto de la previsión (que era corta porque, en la primera investigación, creímos erróneamente que nos solucionaba todos los casos de uso sin trabajo adicional).
- Detectar dispositivos externos puede requerir del subsistema HAL, una nueva tecnología a investigar.
- La integración en bazaar es delicada; hemos comprobado que es posible romper el repositorio por parte de cualquiera. La solución prevista, a falta de comprobar si podemos restringir escrituras dentro del grupo en el servidor, es una política clara de integración: resumiendo, nadie sube a ninguna parte fuera de su grupo de trabajo, y de integrar se encargan personas determinadas. A tal fin se desarrollarán tutoriales de integración y guidelines de desarrollo específicos en python para facilitar la integración.
- Los exámenes están próximos, quedan bastantes entregas en las otras asignaturas y el problema de falta de tiempo se incrementa. Además hemos sufrido un abandono, lo que reduce aún más el personal disponible y convierte en más crítico otra hipotética baja de media duración. Mucha gente tendrá disponibilidad reducida o nula en vacaciones; para compensar, esta es la iteración más larga (un mes y una semana), y en vacaciones al no haber jornada lectiva ni laborable hay más tiempo para trabajar.
- No hay api de nautilus; va implícita en el código, y no hay documentación ninguna. La integración con el mismo se complicará bastante por ello.
- Cómo exportar nuestro sistema de backups aplanado a sistema de ficheros aún no está claro, pues es un problema no trivial en absoluto; además la documentación de FUSE, el sistema que se usaría para ello, es confusa. Como la funcionalidad que nos proporcionaría es principalmente interna este riesgo tiene un impacto bastante leve.
- Python es un lenguaje interpretado y puede ser muy ineficiente en comparación con otros módulos. No obstante, la optimización queda pendiente para futuras fases de desarrollo, es posible enlazar python con módulos en C y además presumimos que el cuello de botella no estará marcado por tiempo de cpu sino de entrada / salida.
- Fat32 impone límites al almacenamiento de archivo que se deben cubrir, sea mediante una aplicación externa o mediante un formato de archivo propio. Al ser el formato más común en discos externos (suelen venir preformateados) es crítico que funcione almacenar sobre fat32 si se quieren externalizar las copias. Algunos de esos riesgos son que no se soportan links (ni hard ni soft), ni permisos, ni archivos de más de 4 GB de tamaño. Los riesgos son compartidos en parte por ntfs.
- Rdiff impone límites en sus funciones internas para paths muy largos; hay que investigar el alcance de ese riesgo y actuar en consecuencia. Los desarrolladores de rdiff-backup parecen tenerlo solucionado no obstante.
- Las herramientas de modelado UML no suelen tener soporte para python: es escaso a la hora de realizar ingeniería inversa sobre código, y casi nulo para generarlo. Localizadas herramientas que cubren en teoría ambas funcionalidades, queda comprobar hasta qué punto lo hacen y familiarizarse con ellas.
Tiempo real empleado
En general no ha habido un buen reparto del trabajo, lo cual viene motivado en parte porque la investigación implica desconocimiento del tiempo de desarrollo, pero también porque el reparto no era bueno en origen y ha habido cierta desorganización. Para mitigar este problema, según la sugerencia dada en clase trataremos de hacer planificación semanal, mediante tareas atómicas ordenadas según su nivel de importancia y relevancia para el camino crítico, y revisando más frecuentemente el reparto. No obstante esto será difícil hasta la primera iteración de construcción, pues aún queda investigación por realizar. Asimismo se ha propuesto un método de refuerzo positivo: quien llegue tarde a la fecha de entrega pierde puntos, y quien la logre los obtiene. Esos puntos serían canjeables por fermentaciones líquidas varias en la cafetería, a gusto del consumidor.
Conclusiones
Aunque se han cumplido la mayoría de los objetivos, se puede mejorar bastante el proceso de trabajo. Es necesario mejorar la integración para conseguir interoperabilidad fácilmente entre el código de todos, y conseguir un reparto de trabajo más equitativo. Aunque la integración ha sido difícil era algo previsto por ser la primera; intentaremos resolver los procesos para ello para la próxima iteración. Además, la opinión general sobre Python, el nuevo lenguaje de programación usado en el proyecto, es que para lo que podía ser ha funcionado razonablemente bien, sin grandes dificultades de desarrollo.
Respecto del abandono de un miembro del equipo, solo destacar que al no ser un miembro activo hasta ese punto no ha afectado tanto a las planificaciones de reparto de trabajo. Confiamos en que no tengamos de nuevo ese problema, ya que el equipo de desarrollo está muy motivado.
Enero
Objetivos cumplidos
Integración de bases de código
Si bien el código del equipo de desarrollo del formato de snapshots no ha podido llegar a tiempo a la integración, las distintas bases de código ya están juntas en una única, de la que los distintos equipos harán branches independientes para trabajar en adelante. Para el equipo de desarrolladores trabajar sobre ramas de desarrollo separadas, y únicamente permitir acceso a los integradores en la rama conjunta y "de entregas" del código nos permitirá mucho más control de calidad que trabajar sobre un único repositorio, sin aumentar los riesgos derivados de ello ya que sí son posibles integraciones de código parciales entre código de los equipos, y todo el mundo tiene una versión razonablemente actualizada del código de los demás para poder probar. Además tener la aplicación completa permitirá una mayor visión de conjunto a todo el mundo de la función de sus respectivos subsistemas en el global de la aplicación.
Módulo Watcher
El módulo Watcher, a falta de retoques finales- como que se detecten automáticamente cambios hechos a mano en la configuración-, está finalizado. La lógica de planificación por ahora no existe por no ser crítica y depender de pruebas en condiciones reales, pero todo el código está listo para que pase por el planificador y por tanto es factible no realizar backups si no se está conectado a la corriente, o si la carga de CPU o E/S es demasiado alta. Ello permitirá reasignar a sus componentes de personal a grupos más necesitados de personal.
Wrapper base de datos
Los componentes dependientes de una tecnología concreta han sido abstraidos a un módulo wrapper que encapsula y abstrae los lenguajes propios de sqlite al resto de la aplicación. Esto, con poco coste de desarrollo y sobrecarga, nos permite reducir al mínimo el riesgo de que sqlite no de la talla para nuestros requisitos, facilitándonos un futuro cambio de tecnología de base de datos que durante el desarrollo se temió (sin llegar a confirmarse) necesario. Quedan por fijar las consultas finales que se harán desde las distintas tablas a la base de datos, que no están fijadas aún en código por no saberse fijas, pero que también irán en sitios concretos y abstraerán la funcionalidad que proporcionan las bases de datos del código SQL necesario para las mismas.
Especificación del formato de backups
Tras un importante esfuerzo de desarrollo se ha completado una especificación del formato de snapshots que esperamos sea lo bastante completa para el resto del trabajo que queda por hacer. Se adjunta al final de la entrega de Enero.
Tabla de historia
La tabla de historia, donde se guarda toda la información de los snapshots que almacena el sistema y donde se diseñaron las operaciones más críticas, está diseñada e implementada en los diversos módulos.
Comunicación frontend / backend
Con mayores dificultades de las previstas en el desarrollo, dbus ha cumplido su cometido y nos permitirá separar la aplicación en un demonio que corra siempre y un gui. Quedan por limar detalles de la implementación (como que si se lanza el gui sin un demonio corriendo arranque al demonio), pero el problema ha quedado solventado. Ello además conlleva modificaciones del diseño UML, ya que el propio sistema dbus actúa como proxy y elimina la funcionalidad del módulo DbusManager.
Cron
Un módulo sencillo que ha complicado el desarrollo del watcher por problemas con su nula integración con dbus para poder pasar mensajes al backend de la aplicación. Su desarrollo completo (incluyendo funcionalidad de realizar las tareas pendientes si el equipo estaba apagado) permite en adelante una planificación adecuada de backups, con funcionalidad como p.e. generar backups integrales por seguridad cada mes con la que se contaba en la planificación inicial de requisitos de HD Lorean.
Requisitos tiempo y espacio
Se han realizado las estimaciones pedidas de tiempo y espacio de la aplicación, que se adjuntan en la entrega de documentación de Enero.
Generación automática de documentación
Un script en la máquina de un miembro del equipo permitirá que, cada noche, se genere automáticamente la documentación de todos los módulos de HD Lorean, lo que sin duda facilitará el desarrollo y la comunicación entre equipos. Dicha documentación se encuentra en http://www.hdlorean.com .
Revisión de calidad de la documentación
Aunque aún no se encuentre finalizada, se ha efectuado una revisión en profundidad de los documentos de clases e interacciones de clases que se generaron la anterior iteración, y todos los problemas detectados se corregirán tan pronto como se terminen de concretar las clases que finalmente quedarán en el proyecto.
Objetivos no alcanzados
Reducir el riesgo del núcleo de la aplicación
El riesgo de rdiff-backup se ha mostrado crítico, tal y como se previo en la planificación del mismo. Finalmente dicha aplicación no cubre ni nuestros casos de uso (en particular borrados), ni nuestras restricciones informales de tiempo y espacio. La dificultad ha venido de que estos problemas no aparecieron en la fase de investigación debido a pruebas insuficientes para revelarlos, lo cual, junto a otra serie de problemas que se mencionan en "nuevos riesgos", ha impedido lograr los principales objetivos planificados para esta iteración y obligarán a modificar notablemente el plan de fase, y probablemente el alcance previsto de HD Lorean.
Primer prototipo funcional
Al no tener un módulo funcionando que hiciera los snapshots, nuestro siguiente prototipo es incompleto y solo se ha podido desarrollar funcionalidad periférica.
Interfaz de navegación de archivos
Los citados problemas de comunicación entre equipos, unidos al retraso del grupo encargado de los snapshots y a una dificultad imprevista para el grupo de GUI en desarrollar una interfaz más allá de las posibilidades del diseñador de interfaces Glade han paralizado casi por completo el desarrollo de la interfaz. Al no haber snapshots funcionando aún, no estaba claro qué se debía mostrar, y al no poder desarrollar tampoco la interfaz a tiempo el resultado ha sido no tener un API claro con los datos que tiene -o tendrá- el sistema de backups almacenados dentro.
Fijar la arquitectura del sistema.
Pese a que la arquitectura preliminar se ha mostrado bastante acertada, aún quedan flecos por concretar en los módulos por terminar, y APIs por definir entre módulos como la citada en el apartado anterior sobre información de un snapshot. Dichas APIs habrán de esperar para ser estables a que el núcleo de la aplicación esté concluido y funcionando, pero se está trabajando en aproximaciones cuanto antes a ellas.
UML
Tras cerca de dos semanas de investigación, se ha concluido que, debido a las características altamente dinámicas de python como lenguaje (reescritura de los diccionarios de funciones de las clases, por poner un ejemplo), no existen -o no se han logrado localizar- herramientas libres y de calidad que generen automáticamente ningún tipo de diagrama UML lo suficientemente completo y útil a partir del código existente. Ello ha ralentizado y frenará en el futuro el crear documentación en este lenguaje, ya que ha de ser mantenida a mano por cada equipo de desarrollo y está muy desacoplado del código fuente. A falta de investigar algunas alternativas de última hora que se han localizado, el UML se está generando a mano mediante la herramienta umbrello, que permite crear todos los tipos de diagramas necesarios; no obstante nos limitaremos a una descripción lo más de alto nivel posible (algo menos que subsistema, pero sin llegar a *todas* las clases necesarias) para que nos sea útil sin dificultar el trabajo.
Un ejemplo del trabajo realizado son las siguientes dos instantáneas:
Diagrama de interacción (parcial) para el caso de uso 2: Añadir nueva carpeta a indexar
Fijar prioridades de los casos de uso
Por falta de tiempo no se ha realizado de un modo formal y consensuado, quedando implícito que la funcionalidad prioritaria es realizar y restaurar un snapshot, así como borrarlos para poder mitigar el impacto en espacio de la aplicación, que se preve el más crítico. Queda por tanto pendiente.
Investigación tecnologías (beagle, nautilus, HAL)
La falta de tiempo general ha provocado que haya sido imposible la investigación de tecnologías adicionales. Exceptuando nautilus, que se considera mucho más deseable de cara a la usabilidad de la aplicación, es probable que el resto queden fuera de alcance en la revisión que se haga del mismo en la próxima iteración.
Documentación adicional
De la documentación adicional faltan aún las guidelines de python y las de integración, aunque sobre python ya hemos concretado aspectos importantes como por ejemplo cómo guardar registros de errores / debug. Se han retrasado por problemas de incomunicación durante el periodo estival entre responsables, y se ha decidido esperar a concluir la integración en una sola base de código para simplificar la tarea a todos los miembros del grupo.
Riesgos reducidos
Sqlite
Al disponer de un wrapper según el diseño de la arquitectura, ya no dependemos tanto de esa tecnología específica y sería más sencillo cambiar a otra más potente como mysql.
Rdiff-backup
Al no usar esta tecnología, tras haber mostrado sus consecuencias su riesgo desaparece.
Problemas de definición de la arquitectura
La arquitectura diseñada parece responder a las necesidades de la aplicación correctamente, lo cual ha sido un éxito de diseño conseguido gracias a la interacción de clases con tarjetas CRC. En general el equipo es más consciente de la misma.
Investigación instalador
Se ha investigado la tecnología de instalación de python (distutils), lo que ha contruibuido a la viabilidad de integrar todas las distintas bases de código en una y facilitará el proceso de despliegue hacia el final del proyecto.
Integración de código (buscar por "bazaar").
Ya está claro y probado cómo se realizará la integración del código de los distintos equipos, y solo queda generar la documentación pertinente.
Demonio y frontend corriendo independientementes
El riesgo tecnológico que presentaba dbus como tecnología de interconexión está controlado y resuelto; ya tenemos la aplicación separada en demonio y frontend.
Nuevos riesgos
Aumenta: no lograr cubrir los casos de uso requeridos por la aplicación, por las nuevas dificultades de desarrollo en el backend. Ya no tenemos el colchón de seguridad que proporcionaba basarnos en una aplicación ya probada.
Aumenta: no lograr que HD Lorean sea lo bastante intuitivo y transparente al usuario, por falta de tiempo en el desarrollo que haga imposible lograr suficiente integración con el escritorio.
Nuevo riesgo tecnológico: por las tentativas que hay de formato de backups se ha detectado que usa un gran número de archivos. El número de inodos posibles en un sistema de ficheros está limitado, y si no se tiene cuidado podemos toparnos con él.
Aumenta: Falta de tiempo; el segundo cuatrimestre dos miembros del equipo se han incorporado a sendos trabajos, y además hay una optativa con prácticas que muchos de nosotros cursaremos que nos robará aún más tiempo.
Tiempo real empleado
Menor del deseable y planificado, ya que la planificación para las navidades no era realista y casi nadie ha sacado el tiempo necesario.
Conclusiones
Esta iteración ha resultado poco exitosa por la unión de varios factores. El principal problema que hemos debido afrontar ha sido el riesgo tecnológico de rdiff-backup, tecnología que no supimos detectar a tiempo que no era suficiente para nuestros propósitos porque nuestras pruebas fueron demasiado reducidas en ámbito; sencillamente no ha habido suficiente tiempo para finalizar el desarrollo de una tecnología nueva de snapshot desde cero. Por otra parte, en general todos hemos trabajado sensiblemente menos de lo planificado, lo cual nos servirá para futuras estimaciones de tiempo en presencia de otras fiestas de guardar. Además ha habido problemas importantes de comunicación entre equipos, y entre miembros de equipos, que han parado completamente el desarrollo durante las vacaciones; no se han sabido resolver los interbloqueos con propuestas de compromiso de API, lo cual ha detenido mucho al grupo de GUI, que por otra parte se ha encontrado en su desarrollo con más problemas de los esperados al comenzar con la funcionalidad más compleja del mismo. Asimismo, la sensación general ha sido de moderado desánimo, provocado por el cansancio, por haber encontrado las primeras dificultades de cierta envergadura en el desarrollo, y también en parte por una falta de delimitación de tareas claras que en ocasiones dejaba a la gente desocupada, esperando instrucciones sobre qué hacer que se creían entendidas.
Para solucionar estos problemas, en Marzo haremos una revisión profunda de procesos de desarrollo y reasignaremos al personal de Watcher, para mejorar esos problemas de comunicación y centrar los esfuerzos de programación en las zonas más necesitadas. Intentaremos recuperar el máximo posible del tiempo gastado de la planificación de fase original, para conseguir completar el máximo de funcionalidad posible. En cuanto al reparto de tareas, se espera que teniendo el código unificado sea más claro quién tiene que hacer qué y en qué momento, a lo que también contribuirán los movimientos de responsables en el personal.
Además será necesario reevaluar en profundidad las planificaciones, lo que probablemente obligará a reducir el alcance de la aplicación y la viabilidad del desarrollo de algunos de sus casos de uso.
Febrero
Objetivos cumplidos
Núcleo de la aplicación terminado
La funcionalidad crítica de crear y recuperar backups está finalizada. Aunque no era un objetivo fijado para el mes, gracias a un notable esfuerzo por parte del desarrollador principal durante la última semana ya está desarrollado el código para crear y recuperar snapshots. Lo que queda por delante, en esencia, será ampliar la funcionalidad para cubrir el máximo de casos de uso (pues por ahora solo cubre lo esencial), así como conectarlo con el resto de la aplicación definiendo ya de un modo fijo las API internas, y naturalmente un testeo intensivo de esta parte de la aplicación.
Investigación unit tests
La investigación sobre unidades de prueba está finalizada, con un tutorial aquí. Queda decidir los procedimientos sobre el mismo, así como automatizar el testeo una vez se tengan disponibles las pruebas en un servidor para que se realice todas las noches, lo cual se estima trivial.
Investigación nautilus
Durante exámenes un miembro del grupo ha realizado la investigación sobre la arquitectura interna de nautilus y sus posibilidades de extensión, mediante estudio de la documentación disponible y contacto con los desarrolladores mediante correo electrónico. La conclusión es que resultaría notablemente más difícil de lo estimado, al no tener ninguna documentación sobre código ni estar realmente preparado para ello con interfaces externas. Si bien hay bastantes sitios donde integrarse con el mismo (propiedades de un archivo, menús contextuales…) para realizar una vista nueva que incluyese la funcionalidad de la barra de tiempo hay que reimplementar, en C, y prácticamente desde cero sin documentación. No obstante lo dicho, se intentará durante la primera semana confirmar la dificultad del desarrollo, dado que es una parte que aportaría gran calidad y usabilidad a la aplicación.
Concluir la integración de las bases de código
La adaptación del equipo al nuevo esquema de trabajo en el launchpad ha sido sorprendentemente rápida y efectiva. Todos los equipos están trabajando ya sobre la base de código común, y por tanto la integración de trabajo entre grupos es en esencia trivial y no es obligatorio esperar a cada mes para ello, si bien pueda ser recomendable en algunos casos. Además disponemos de la ventaja del control de versiones que proporciona historial extensivo e independiente para cada cambio realizado por cada grupo, lo que en potencia facilitará mucho el depurado y testeo de regresión al poder localizar enseguida cualquier cambio introducido que haga fallar a la aplicación.
Concluir la gestión de archivo de configuración
La clase ConfigFileManager está finalizada y el formato del archivo de configuración definido, junto a funciones get y set auxiliares adicionales. Ello reduce las decisiones a tomar y los posibles malentendidos, al haber un api al que ceñirse.
Objetivos no alcanzados
Completar módulos planificados
Los módulos que se debían completar (watcher y dbus) aún están faltos de pequeños retoques, en algunos casos por peticiones de última hora como en el de dbus (para conseguir una ruta de feedback desde el backend hacia la aplicación). Se estima que lo que queda es mínimo.
Unificar la jerarquía de excepciones del programa
Por falta de tiempo durante exámenes aún no está documentado este paso, si bien existen jerarquías parciales de excepciones.
Migrar la información de depuración a la clase HDLogger
Revisión de calidad de la documentación
Decisión sobre la licencia final del código
Haber utilizado código ajeno (pequeños snippets de ejemplo, principalmente) nos obliga a ceñirnos a la licencia de dicho código. En principio es LGPL, pero se adoptará la GPLv2 por comodidad. Falta simplemente consensuar entre todo el equipo esto, así como modificar los archivos para añadirles la licencia, y posiblemente modificar el entorno de desarrollo para que añada esa cabecera automáticamente.
Riesgos reducidos
- El riesgo más importante de la aplicación está solucionado, a falta de integrar y testear. Ello nos da un respiro al plan de fase, permitiéndonos probar durante más tiempo la aplicación y en potencia cubrir más casos de uso.
- El riesgo de integración de bases de código está solucionado sin apenas problemas, que se estimaba de importancia crucial.
- Riesgos de personal que se habían detectado, independientes de la falta de tiempo, están mitigados y planificados convenientemente.
- Dos grandes subsistemas de la aplicación (Watcher y SnapshotManager) están muy avanzados (en el primer caso está concluido totalmente, a falta de pequeños problemas que se van detectando y de optimizaciones que se pudieran aplicar). Ello reduce bastante el impacto del riesgo de falta de personal, y además los problemas de intercomunicación, ya que solo quedan dos grandes equipos (backend, concretamente gestión de backups, y frontend dedicados al GUI, estando solucionado casi todo el código intermedio de comunicaciones y gestión de la base de datos).
Nuevos riesgos
- Otro miembro del equipo ha encontrado trabajo, lo que hace un total de 4 los que están simultaneando trabajo y estudios, más del 25% del equipo. Esto reduce en mucho el ya de por sí pequeño equipo de desarrolladores y aumenta el riesgo de no lograr completar el desarrollo a tiempo.
- Relacionado con este problema de personal, aún desconocemos el esfuerzo que requerirán las asignaturas de carácter práctico del segundo cuatrimestre para los miembros del equipo. Cabe suponer que, como es habitual, el segundo cuatrimestre sea más intenso en este ámbito que el primero, lo que reducirá aún más el tiempo disponible.
- El fin de exámenes ha traído notable desorganización al grupo, al no tener el día fijo común para reunirnos. Esto crea un riesgo muy importante de no lograr los objetivos de la primera entrega de Marzo, para la que de por sí hay muy poco tiempo.
- La sorpresa de la entrega de Marzo, unida al retraso en los grupos de GUI y backend, hace un riesgo de consecuencias severas e importancia altísima el de no poder cumplir ese plazo. Desde el equipo se achaca a avisar con solo un mes y medio de antelación, con los exámenes de por medio.
- La negativa por parte del equipo técnico a instalar software en los laboratorios nos va a dificultar notablemente el despliegue y testeo de la aplicación, así como hará imposible su instalación en dichos pc's debido a las dependencias lógicas del software que desarrollamos, que intenta reutilizar el máximo de componentes externos posibles. Por nuestra parte consideramos imposible dicho objetivo (desplegar sobre unos equipos que no admiten ningún cambio en la aplicación), y trataremos de llegar a soluciones de compromiso mucho menos que ideales (equipos personales, accesos remotos).
- La fecha avanza y se agota el tiempo para testeo, mantenimiento y demás.
Tiempo real empleado
Muy poco, al estar de exámenes todo el equipo. El lead developer ha sido quien más trabajo útil ha sacado, dedicando por completo la última semana a finalizar su módulo.
Conclusiones
Como se previo la iteración de Febrero ha sido improductiva, pero nos ha cogido por sorpresa la desorganización del fin de exámenes y los nuevos horarios del segundo cuatrimestre, haciendo que durante la última -y crítica- semana de Febrero no nos hayamos reunido y nos hayamos comunicado mucho peor por ello. No obstante lo dicho, el trabajo de última hora ha salvado la iteración y nos permite un respiro para Marzo, a sabiendas de que, al margen de terminar el interfaz gráfico, lo que queda sobre todo es comunicar módulos, y depurar. Todo el equipo está mentalizado para la importante entrega de Marzo y ya se ha retomado el ritmo de trabajo, en especial ahora que las prácticas de terceras asignaturas aún nos permiten un pequeño respiro.
Marzo
Objetivos cumplidos
Beta funcional del programa
Consideramos que la primera entrega fue un fracaso previsto y avisado, ya que el tiempo era poco, y si bien se realizaron avances extraordinarios en dos semanas de intenso trabajo, la presión por la inmediatez de la entrega redujo notablemente la calidad del desarrollo, lo que condicionó notablemente nuestro fallo. Por parte del equipo consideramos que no es razonable volver a pedirle al personal semejante esfuerzo de desarrollo, que va contra la buena gestión del tiempo y contra una planificación realista y efectiva de los recursos humanos, y de cara a no gastar en exceso a la gente pretendemos que no se vuelva a repetir bajo ningún criterio. Esto, aunque implique tener que incumplir requisitos externos, siempre que por mayoría simple los juzguemos irrazonables, y con consciencia de las consecuencias.
No obstante, una vez liberados de ese problema inmediato hemos podido dedicarnos a la mejora del código solventando todos los problemas que habíamos ido localizando y posponiendo durante el apresurado desarrollo. Ejemplo sean los problemas detectados de codificación en el código con acentos, que se debían principalmente a faltas de consistencias entre los módulos.
Todo ello nos ha permitido una entrega a final del mes en gran parte ya funcional: al margen de hacer y recuperar versiones de archivos, también creamos un snapshot inicial del sistema al arrancar la aplicación (para protegernos de periodos durante los que esté cerrada), y están resueltas las planificaciones periódicas e instantáneas con cron (entre las que la inicial se puede considerar un caso particular) y los pequeños problemas que tenía el mecanismo de notificaciones de cambios en archivos. Además de esto, tenemos previstas y desarrolladas parcialmente (incluso sólo por probar exhaustivamente) bastantes de la funcionalidades que aún nos faltan para aproximarnos a los objetivos iniciales de proyecto y a los casos de uso planteados entonces, como por ejemplo borrar snapshots, caducarlos para poder borrarlos, obtener una eficiencia de uso de los recursos que permitan no notar la aplicación, feedback de las operaciones en curso hacia el usuario, o una versión en consola de la aplicación.
Queda pendiente una refactorización de partes del código que no están a la altura de la calidad requerida y que supondrá restar un tiempo extra al ya ajustado del que disponemos, en buena parte motivada por ese apresurado y algo caótico desarrollo inicial.
Contratación de personal
La reciente incorporación de un miembro extra a nuestro proyecto nos enorgullece y da perspectiva sobre cómo se percibe a nuestro grupo de proyectos externamente. Nos permitirá repartir mejor la carga de trabajo y reforzar áreas donde andamos escasos de personal y que podrán hacer buen uso de su talento, si bien nos supone nuevos riesgos y dedicarle a su vez a personal para introducirla a todo el material (documentación, procedimientos y código) que tenemos hasta ahora y que el resto conocemos. Nos supondrá, en resumen, un esfuerzo extra en formación que esperamos rentabilizar cuanto antes.
Puesta a prueba de la arquitectura
A raíz de tener la primera versión funcional del programa hemos empezado a explorar lo que haría falta para ampliarlo, de cuyo análisis inicial concluimos que buena parte de las horas invertidas en pensar la aplicación inicialmente ahora dan su fruto, y la mayoría de las extensiones para completar funcionalidad parecen "factibles" y hasta "fáciles", solo limitadas por el tiempo del que disponemos. La falta de cambios notables a la arquitectura para conseguir esto nos habla de la calidad de la misma y nos permite a partir de ahora un desarrollo mucho más rápido que en el caso contrario.
Puesta a prueba del despliegue
Dos entregas sucesivas en unos 10 puestos simultáneos han probado la arquitectura provisional de despliegue con éxito, no notándose ralentización alguna durante el uso pese a su perfil relativamente intensivo de uso de disco. Ello se ha debido en parte al equipo donde se ha desplegado, lo bastante potente y con un subsistema de disco solvente (dos discos en RAID0), y en parte a la relativa complejidad en probar una aplicación de este perfil en condiciones más reales (con un volumen más grande de documentos y archivos del usuario). Tener dos miembros del equipo trabajando de administradores de sistemas también ha sido determinante, con acceso a recursos de red que nos hubiera sido complicado obtener de otro modo.
Si bien esta arquitectura es provisional y solo motivada por las limitaciones que nos imponen los técnicos de laboratorio, nos servirá para generar el UML de despliegue y seguimos explorando y proponiendo a los técnicos otros medios de despliegue, como máquinas virtuales que, sin suponer un riesgo de seguridad, son un entorno más real sobre el que probar.
Quedan pendientes aún temas de empaquetado del software que se resolverán en breve.
Revisión de las pruebas
Durante las pruebas con usuarios reales, sobre todo la segunda, hemos obtenido bastante feedback sobre las mismas. Parte del mismo nos será de gran ayuda para mejorar usabilidad de la aplicación, habiéndose detectado problemas nuevos que por la falta de revisión formal se habían pasado por alto hasta ahora. Se dará buena cuenta de las sugerencias recibidas mientras seguimos explorando por nuestras cuenta otras mejoras adicionales.
Nuevo GUI
El uso de herramientas de prototipado rápido, como Python y sobre todo la herramienta Glade de desarrollo visual de interfaces en XML, nos han permitido cambiar el interfaz que teníamos inicialmente reutilizando casi todo el código preexistente, así como desarrollar nuevas interfaces como la vista en dos paneles, en muy corto espacio de tiempo. Ello ha mejorado mucho la calidad de la aplicación y nos demuestra lo acertado del enfoque de utilizar herramientas que desacoplen el diseño de interfaces del de código. Si bien hay multitud de aspectos a mejorar detectados, ahora el GUI es mucho más ordenado y visualmente atractivo. Además se han añadido elementos como una barra de botones que hacen accesibles las funciones más comunes y se han solventado fallos elementales como el no poder diferenciar entre una carpeta y un elemento, aunque esta mejora no llegó a la entrega.
Ruta de comunicación inversa
Un miembro del equipo ha desarrollado la funcionalidad de comunicación inversa usando el mismo canal D-Bus existente, esto es: de backend a frontend. Ello nos resuelve finalmente el riesgo del sistema de comunicación interproceso que utilizamos (D-Bus) y nos permite proporcionar feedback al usuario de modo eficiente (sin usar polling). Gracias a esto podremos desarrollar varias mejoras, como un refresco de la ventana principal para responder a cambios en el backend y exploraremos la posibilidad de incluir barras de progreso o popups de notificación.
Fechas de reunión
Ante la dificultad de encontrar horarios comunes por tener a 4 miembros del proyecto trabajando (un 30%, cifra muy elevada) hemos establecido para ello las horas de laboratorio de Jueves y Viernes, normalmente improductivas en lo que a desarrollo se refiere y en las que normalmente estamos todos presentes. En cualquier caso, el estado del desarrollo actual nos permite reunirnos menos que en la fase previa de definición del proyecto.
Licencias en el código
Hemos añadido la licencia GPLv2 al código y los copyright pertinentes para cumplir con la legalidad, al haber reutilizado pequeños fragmentos de otras aplicaciones que nos obligaban a ello. Con este cambio nos integramos plenamente en el floreciente mundo del desarrollo de software libre y mejoramos las posibilidades de su mantenimiento una vez acabado el desarrollo del proyecto, sea por nosotros o por terceros.
Hdlogger y tratamiento de fallos
El módulo desarrollado de logging nos ha permitido centralizar toda la información de depuración útil para diagnosticar fallos, e incluso desarrollar. Sobre el mismo hemos construido un módulo de informe de excepciones inesperadas y cuelgues, que nos enviará los archivos que Hdlogger genera, para poder analizar en profundidad los fallos que se produzcan en la aplicación.
Queda pendiente que sea exhaustivo y más útil aún y que se aproveche desde el GUI, lo que requiere moverlo ligeramente de donde está en la arquitectura para sacarlo del backend, y de un esfuerzo por parte de todos los desarrolladores para utilizarlo adecuadamente.
Bugtracker, listas de correo y traducciones
La aplicación web que utilizamos para la gestión de configuración, http://launchpad.net , además de centralizar el control de versiones que hemos estado usando hasta ahora, nos integra funcionalidad extra de seguimiento de bugs detectados, así como gestión de traducciones online (un aspecto sobre el que investigaremos, pues fue mencionado en las revisiones de las entregas), y recientemente listas de correo (archivadas e indexadas para su búsqueda). Exploraremos también la posibilidad de integrar la gestión de fallos mencionada anteriormente con launchpad, ya que recientemente hemos descubierto módulos Python que sirven para ello.
Retoques al modelo de desarrollo
Pendientes de ser documentados en inmediatas actualizaciones de la documentación, hemos realizado retoques al modelo de desarrollo para facilitar las integraciones de código y reducir riesgos. En adelante tendremos múltiples niveles de repositorios. Los que ya teníamos (los privados de cada usuario), se integrarán en los de cada grupo de desarrollo (como gui, db para bases de datos, console o snapshot-manager), donde se desarrollarán las features nuevas en progreso. La integración entre estos nuevos repositorios se hará a través de un repositorio común llamado unstable, que probablemente tenga problemas producto de esta integración. Tras estabilizarlo se migrará el código a un nuevo repositorio de testing, que debe ser estable y probado, y sobre el cual solo aplicaremos correcciones de errores (que, gracias al control de versiones que usamos, podrán ser portadas con algo de cuidado bidireccionalmente entre testing y unstable sin afectar a las divergencias que hayan surgido entre ambos). Finalmente, las versiones que hagamos se etiquetarán en testing y se dejarán en trunk, de donde obtendremos el resumen de todas las entregas al final del curso, y que estará establecido como repositorio principal.
Con esto solucionaremos todos los problemas de integración a la vez que podremos mantener baselines estables independientes del desarrollo y portar parches entre repositorios.
Objetivos no alcanzados
Documentación
La documentación ha sufrido un descenso de la calidad motivada por el exceso de trabajo. Al margen de la revisión y actualización de la documentación existente, no se han cumplido en absoluto las planificaciones acerca del desarrollo de UML por parte de los respectivos grupos de trabajo. Ello se debe sobre todo a la sobrecarga de trabajo de todo el mundo. Para solventar este problema hemos reasignado a tiempo completo a un miembro del equipo que ha trabajado en prácticamente todas las partes de la aplicación. Su trabajo, consistente en consultar a todos los equipos sobre la aplicación, desarrollar los pertinentes diagramas, detectar patrones de diseño aplicables que no hayamos usado y documentar los que sí, aún está por completar pero esperamos tenerlo listo para la siguiente iteración.
En cuanto a la revisión de la documentación existente, supone un riesgo cada vez mayor sobre el que exploraremos soluciones.
Por último, mencionar el retraso en las fechas de entrega de la documentación, motivado por el exceso de trabajo del mantenedor de la misma, así como por haber esperado a la segunda entrega de código y a evaluar sus resultados, la cual a su vez se retrasó hasta la primera semana de Abril por la Semana Santa.
Eficiencia aplicación
Al conseguir poner a funcionar la aplicación hemos detectado algunos problemas de esperas excesivas de cara al usuario sin feedback alguno. Como nos supone un riesgo muy importante (ya que si la aplicación es demasiado lenta será el primer impedimento para su usabilidad), según se detectó el problema se reasignó a personal para su evaluación y solución. El problema está en buena parte generado por el uso de llamadas síncronas -las más sencillas y habituales para el equipo de desarrollo- que dejan a la aplicación "esperando" operaciones grandes de disco, así como otros problemas relativos a la gestión de patrones para expresiones regulares. Confiamos en que la arquitectura, mediante el scheduler que tenemos incorporado, y un uso juicioso y sencillo (para evitar inestabilidad) de threads, nos permita al menos no perder la responsividad frente al usuario.
Consola
La consola, desarrollada hacia la mitad de la iteración, no ha sobrevivido a los numerosos cambios de la aplicación por no haber sido adecuadamente mantenida y probada. Su uso nos sería muy útil para automatizar el testeo de la aplicación completa muy fácilmente, con meros scripts (que pueden ir incluso al margen de las unidades de prueba), y cubre casos de uso con relativa sencillez.
Se resolverá cuanto antes y además se solventarán riesgos relativos a la misma, como medios alternativos de conectarla con el backend que no dependan de D-Bus (por ejemplo señales convencionales) y un nuevo proxy para las mismas (ya que es un servicio del sistema que no suele estar presente en un entorno sin gráficos, precisamente donde sería más útil en recuperación del sistema).
Calidad
Carecer de un plan de calidad más allá de las directrices establecidas nos empieza a pasar factura. El seguimiento de la calidad del código es irregular y no existen procesos para rechazar código, ni revisiones formales y exhaustivas sobre el mismo. Estas deficiencias, aparte de reducir nuestra puntuación para la evaluación de Software Capability Model, nos generan problemas al desarrollar y nos suponen un riesgo a la hora de mantener la aplicación que deberemos valorar y solucionar cuanto antes, mejorando nuestro proceso existente. Sin embargo, carecer de personal suficiente nos lo pone muy complicado.
Formación del nuevo personal
El nuevo miembro de personal incorporado aún no ha concluido su formación y por tanto aún nos supone un balance neto negativo de productividad; la información nueva es mucha, y además hay algunos fallos de actualización de la misma cuando está explicitada en el wiki. Ello deberá solventarse a la mayor prontitud posible.
Riesgos reducidos
- Aplicación: ya tenemos una versión de la misma funcionando. Aunque le falten características, ha tranquilizado a todo el equipo, ya que desde aquí el proceso es mucho más incremental.
- Despliegue: dos entregas sin percances nos quitan el problema de cómo presentar y probar la aplicación, uno de los más importantes y olvidados de cara a una entrega con éxito.
- Personal: la reciente incorporación de un miembro más al equipo nos puede reducir la carga de trabajo en áreas importantes y descuidadas.
- Personal: puesta a prueba durante un fin de semana de programación extrema, la dinámica del grupo funciona perfectamente y hemos resuelto todos los problemas entre nosotros sin percance alguno. El grupo funciona muy bien para trabajar, la relativa falta de jerarquías contribuye a la confianza entre miembros, lo que mejora el flujo de información y el control de los distintos grupos. Basar las decisiones delicadas y discutidas en revisiones del grupo permite reaccionar con cierta rapidez a cambios polémicos y subsanarlos de modo eficaz mediante consensos. A pesar de dicha falta de jerarquías formales, la confianza en las relativas capacidades de los miembros del equipo nos permite mejorar la rapidez en solucionar esas discusiones y agilizar la toma de decisiones.
Nuevos riesgos
- Personal: Contratar a un nuevo miembro siempre supone un riesgo de personal: integrarse en un equipo y proceso de trabajo preestablecido, posibles roces con la gente, formación intensiva a esa persona, etc., no sin descuidar en entornos más formales que este los posibles problemas que surgieran de adquirir credenciales de seguridad, boicoteos internos, etc. Para mitigar este riesgo confiamos sobre todo en la buena dinámica de personal antes mencionada, pero además hemos comprobado que los procesos establecidos de gestión de código, ya basados en niveles de acceso a distintos repositorios de código, nos permiten dar permisos lo bastante atómicos para trabajar, así como determinar la autoría de los cambios en caso de posibles problemas. Por ello creemos mínimas las consecuencias de ese hipotético problema (principalmente en tiempo), y comprobamos la validez del proceso.
- Personal: conforme avanza el desarrollo y se reduce el tiempo restante, el riesgo de "quemar" al personal crece por exceso de trabajo, y una planificación cuidadosa de procesos y asignación de responsabilidades es la única forma de minimizarlo hasta que sea irrelevante por haber acabado la asignatura. Es importante intentar extraer el máximo rendimiento posible del equipo, pero no debemos intentar extraer más que lo razonable y necesario por querer avanzar más de lo realista.
- Tiempo: reducido por la formación del personal nuevo.
- Tiempo: reducido del lead developer por otras asignaturas y cansancio del desarrollo seguido.
- Tiempo: muy escaso para concluir la aplicación (solo dos iteraciones más).
- Problemas de rendimiento de la aplicación que la hagan poco usable aumentan su posibilidad de aparición, pues ya han sido detectados, y se están evaluando y subsanando.
- Tecnología de base de datos: demasiado lenta (bloquea entera la base de datos en escrituras); un cambio fue planificado y por tanto la arquitectura del código minimizaría el impacto, pero aún así sería un problema añadido que reduciría aún más el tiempo del que disponemos.
- El uso de threads puede hacerse necesario para solucionar esos problemas de rendimiento, con el consiguiente riesgo de desarrollo por ser una tecnología relativamente complicada de aplicar bien y de depurar.
- Carencias en la documentación: podrían no llegar a ser subsanadas a tiempo, y cuanto más tardan mayor es su impacto. Por ejemplo, por no haber examinado y completado el documento de la evaluación de Software Capability Model