Mostrando las entradas con la etiqueta microwiki. Mostrar todas las entradas
Mostrando las entradas con la etiqueta microwiki. Mostrar todas las entradas

22 diciembre 2011

"Developability"

Existen numerosos atributos de calidad, e incluso clasificaciones estándar de ellos.

¿Para que sirven estas clasificaciones?

Por un lado sirven para darle a los diseñadores de sistemas un punto de partida. Algo que permita dar respuesta a la pregunta: "entre las características que requiere nuestro sistema ¿nos estaremos olvidando de algo?". Por otro sirven para que los investigadores de arquitectura de software puedan definir métricas y estilos de solución.

Y por otro, sirven para que yo tenga una excusa por donde empezar este post :)

Estaba pensando que en estas clasificaciones hay un atributo de calidad perdido, que voy a bautizar como "Developability", y voy a definir así: la capacidad un sistema para reflejar los cambios introducidos durante el desarrollo.

Después de todo si en Java existen productos como JRebel y frameworks como Play anuncian sus bondades con frases como: "No need to compile, deploy or restart the server"; creo que existe una necesidad de tener la característica de "developability" en mente a la hora de pensar en el diseño de un sistema.

¿No es lo mismo que Maintainability?
Es parte de la mantenibilidad, en el sentido que forma parte de la facilidad de cambio de un sistema.

Pero muchas veces cuando se habla de mantenibilidad se hace referencia a cuan fácil es introducir nueva funcionalidad sin tener que hacer grandes cambios en el diseño.

Podemos tener, por ejemplo, un sistema muy fácil de extender, donde cada vez que un desarrollador introduzca un cambio tenga que esperar 2hs a que termine la compilación para poder verlo.

¿No es lo mismo que Testablity?
Testabilty se refiere a que tan fácil es verificar el software, por ejemplo: si es posible realizar test automatizados con facilidad o no.

Y lo que planteo es en cierto sentido similar, pero con objetivos levemente distintos: un sistema puede ser fácil de testear en el sentido que es posible automatizar tests u obtener información de estado relevante para el testing y aún así ser un tremendo "dolor" para desarrollar.

Un ejemplo: Mejorando el "developability" de Microwiki
Mi pequeño proyecto: microwiki; del que les conte hace un par de posts atras. Utiliza templates de html para renderizar las paginas web. Estos templates son resources y se cargan del classpath.

Por default Jetty no hace un reload del classpath cada vez que algo cambia -principalmente por que estar viendo el filesystem por cambios es una operación costosa.

Al principio tener que reiniciar microwiki para ver los cambios en un template no me molestaba: el proyecto es chico y reiniciar es rápido.

Sin embargo cuando empece a mejorar un poco el diseño del HTML esos segundos de presionar restart en el IDE y volver a cargar la página se volvieron una molestia.

Por suerte para no meterme con cuestiones de classpath reload y configuración de Jetty, algunos astros de "mantenibilidad" y "testeabilidad" se alinearon.

Para permitir que microwiki sea configurable mediante archivos de configuración, y que la interpretación de estos me sea fácil de mantener utilice un DSL de Groovy.
Es decir los archivos de configuración son código fuente Groovy, y en ellos es posible definir un template de la siguiente manera:

templates {
    display = '/dir/disp.html'
    edit = '/other/edit.html'
}

Por otro lado para facilitar el testing los templates implementan la interfaz: ViewTemplate. Esto me facilita la creación de mocks en los tests.

Juntando estas dos cosas, el cambio para facilitar el "developability" fue muy sencillo:

Agregue un método al builder que interpreta el DSL del archivo de configuración (ConfigBuilder):

ViewTemplate debug(source, Map context = [:]) {
  { Map ctx -> template(source, context).applyWith(ctx) } as ViewTemplate
}

Con este método es posible definir la configuración de esta manera:

templates {
 File prjDir = new File('/Users/diegof/Projects/microwiki/src/main/resources')

 edit = debug(new File(prjDir, 'microwiki/templates/edit.html'))
 search = debug(new File(prjDir, 'microwiki/templates/search.html'))
}

Y ya no hay que preocuparse por el reload: microwiki va a leer el archivo cada vez, y los cambios se ven de forma instantánea (claro que esto no tiene en cuenta los cambios en el stylesheet, aunque es un avance).

De que sirve esto... cuando tengan uno de esos proyectos web que cargan millones de cosas al inicio, es bueno dedicar un poco de tiempo a pensar como mejorar el "developability": aunque los appserver pueden hacer reload de ciertas cosas, no pueden hacer magia, y a veces pensar un poco en esta característica como parte de la calidad de la solución les va a ahorrar horas de frustración.

09 noviembre 2011

Microwiki: Primeros pasos de diseño

No importa que hable sobre principios y patrones de diseño, sobre polimorfismo, o si el ejemplo que di fue bueno o malo; al momento de la practica quien recién comienza aprendiendo diseño orientado a objetos se siente perdido y quiere una especie de guía que le diga que esta bien o mal.

El secreto es que incluso con más experiencia, uno tambien se encuentra algo perdido cuando se empieza con un problema nuevo.

Creo que un buen consejo para encarar un diseño es tener una "mente de principiante" y no dejar de preguntarse "¿Por qué?".
Claro que para hacerse las preguntas y poder responderlas se necesita un conocimiento previo.
Ambas cosas -hacerse las preguntas y construir ese conocimiento- van de la mano.

Esta introducción, viene a cuento que me dieron ganas de contarles las preguntas que me fui haciendo en la construcción de microwiki.

Para quienes no hayan visto mi post anterior, microwiki, es un pequeño servidor wiki que comencé a programar en mis ratos libres. Como objetivos de diseño, microwiki tiene las siguientes características:
  • Se utiliza localmente: no hay usuarios, ni permisos, ni historial de versiones en las paginas. 
  • Iniciar el servidor debe ser tan simple como ejecutar un comando.
  • Las paginas se guardan en el file system, y pueden editarse tanto dentro como fuera de la aplicación web.
  • La búsqueda de contenido debe ser rápida.


Las cuestiones técnicas

En un mundo teórico ideal, uno debería evaluar la funcionalidad, los atributos de calidad, ver las herramientas disponibles, un largo etcéra y luego elegir la solución técnica más adecuada. La realidad es mucho más simple, venia jugando un poco con Groovy y Gradle así que esas fueron las herramientas que elegí para trabajar.

Al principio pensé en hacerlo con Scala para practicar un poco este lenguaje, pero la comodidad de IntelliJ IDEA para usar Groovy me compro -me estoy volviendo viejo, ya no tengo ganas de ponerme a configurar plugins en versión beta.

El resto de las opciones fueron más simples. Conocía la sintaxis Markdown de usar GitHub y Stackoverflow, y PegDown fue el primer parser que encontré para Java.

Y si voy a hacer un pequeño web server tampoco iba a empezar de cero, Jetty es muy conocido por proveer un API simple para crear web servers en Java sin meterse con todo el lío de JEE (otra opción en Grizzly, pero es mucho más nuevo y no tiene tanta documentación).


Primeros pasos

Partiendo de que microwiki es una aplicación web, y que voy a utilizar servlets con Jetty, el primer paso fue pensar en un servlet que mostrara una pagina.
Consejo: Empezar a diseñar siempre por un caso particular y simple.
Entonces tenemos nuestro servlet que muestra la pagina. ¿Implementamos en el servlet la funcionalidad de abrir el archivo e invocar al parser? Respuesta rápida: no.


¿Por qué? El servlet se encarga de manejar el request y response de http, si ponemos todo junto no hay forma de testear la funcionalidad de obtener y parsear una pagina por separado.

Probablemente en alguna clase sobre diseño orientado a objetos escuchaste que las clases deberían tener alta cohesión, se referían justamente a este tipo de casos: hacer que la clase servlet implemente dos funcionalidades distintas es contraproducente a la hora de introducir cambios.

Los tests de unidad son útiles para detectar este tipo de problemas: si dejamos todo junto para testear la responsabilidad de brindar una pagina vamos a tener que crear un mock HttpServletRequest y un mock HttpServletResponse.
Consejo: Los mock objects son útiles, pero si tus tests necesitan muchos, probablemente le estés pifiando en la separación de responsabilidades.
Entonces separando responsabilidades termine con algo así:


Para los "Templates" no hubo mucho análisis de mi parte: implementar la generación de HTML dentro del servlet es engorroso e inmantenible (en este caso la necesidad de separar responsabilidades es bien clara). Para implementar los templates use los GStrings de Groovy. Me pareció bueno mantener las cosas bien concretas: el template por ahora se utiliza para visualizar una pagina.
Nota: En el código actual en GitHub van a ver que el uso de los templates evoluciono hacia algo más generalizado, en otros posts les cuento el por que.
¿Por que Writable?
Writable es una interfaz de Groovy que simplemente describe el método "writeTo(Writer)". Podría haber usado String, pero usar Writable permite expresar solo lo que necesito y optimizar las cosas si fuese necesario.
Si te estas preguntando a que me refiero con "optimizar": si uno tiene una pagina grande es preferible hacer un "streaming" que guardar toda la pagina en un gran String. Lamentablemente el parser de Markdown que estoy usando no permite hacerlo, pero como están planteadas las cosas podría usar otro parser sin afectar al resto de la aplicación.

¿Por que un objeto Page y no retornar directamente el String con el contenido?
Esta claro que para mi sistema una pagina no es simplemente un String.
Un fanático de TDD y del "paso a paso" me diría que para el test de mostrar la página un String alcanza. Sin embargo sé que voy a querer modelar más cosas de una pagina: una pagina tiene un titulo, una representación HTML y una representación en formato wiki.

¿Por qué una interface PageProvider?
Bueno yo tambien tengo la misma duda :)
Por ahora solo tengo una implementación de PageProvider y tampoco tengo intenciones de tener una distinta a futuro. En este punto hay dos cuestiones basadas en la experiencia que me llevaron a esto:
  • Una interfaz PageProvider me facilitaría la creación de mocks en el caso que quisiera testear otros componentes que dependan de un PageProvider (si esta es una de las "malas" costumbres adquiridas de la experiencia en Java).
  • Si quisiera agregar un cache podría usar un decorator que implemente esta interfaz.
    Otra vez me estoy adelantando -son las manias que uno adquiere de la experiencia previa- en estos casos es importante tomar nota mental de que uno se esta adelantando. A veces por adelantarse, uno le puede errar fiero (de hecho me paso con la búsqueda, pero eso se los voy a contar en otro post). En este caso decidí seguir adelante: le veo mas ventajas que contras, pero si les pasa algo asi en un diseño y les queda la duda... paso a paso como diría mostaza.

Espero no haberlos aburrido mucho, la próxima les cuento algunos pasos más.

17 octubre 2011

Microwiki

El feriado lluvioso de la semana pasada, lo dedique a un pequeño proyecto que tenia en mente hace tiempo: hacer una pequeña wiki.

¿Para que sirve? Sirve para tener un wiki sin necesidad de un servidor externo, guardando los archivos en forma de texto plano. La ventaja es que la documentación del proyecto se mantiene en una carpeta junto con el código, en una forma fácil de editar y buscar. El formato que usa es Markdown, que es lo suficientemente amigable y legible para mantener los archivos de texto sin necesidad del wiki.

Pueden encontrar el código en GitHub: https://github.com/dfernandez79/microwiki

Todavía esta en desarrollo, pero la funcionalidad básica de ver y editar esta disponible. Hay muchas cosas por hacer que voy a ir agregando cuando tenga tiempo, al menos la siguientes características van a estar terminadas para el "release 1.0":
  • Búsqueda de texto rápida (quizás usando Lucene). Mi objetivo es que browsear y buscar sea rápido, de lo contrario no le veo mucha ventaja sobre utilizar archivos Word u HTML :)
  • Paquete binario fácil de usar, la idea es que el típico caso de uso sea hacer checkout de los archivos fuentes e iniciar el wiki (ya sea por un comando o un icono) con cero configuración (por default voy a hacer que tome el subdirectorio docs del directorio actual).
  • Modo solo lectura (lo veo útil para integrar con Hudson u algún otro servidor de CI)
Otras cosas que me gustaría agregar a futuro son:
  • Soporte para LaTeX probablemente usando http://www.mathjax.org/.
  • Soporte para renderizar grafos de GraphViz directamente (la idea seria que los links a gráficos usando la notación ![Alt text](file.dot) de Markdown se muestren directamente como PNG).
Si tienen interés en chusmear el código fuente, las herramientas que use son: