Tuesday, January 12, 2010

Primer prototipo TP 2.0

¡Hola!

Según avanzamos en el diseño de la nueva versión de TwinPanel, se hace necesario "prototipar" determinadas cosas. De este modo, podemos capturar requisitos no visibles a primera vista, y comprobar en cierto modo la viabilidad de algunas propuestas.

Por eso, presentamos el primer prototipo escrito teniendo en cuenta parte del nuevo diseño. Básicamente está formado por dos partes: el entorno de objetos distribuidos y los clientes (aunque, en este caso, sólo hay uno ;) )

Aunque el prototipo es funcional, no está escrito a fuego, por lo que es posible que cambien muchas cosas. Aún así, vamos a desgranarlo un poco, para entenderlo bien.

Distributed Component Platform

El nombre todavía no es definitivo, pero de alguna forma hay que llamarlo. DCP es el conjunto de objetos (plugins, factorías, etc.) que dan servicio a los clientes. De el forman parte los sirvientes que presentan un modelo de datos o de acceso para determinado recurso, así como las factorías utilizadas para la gestión de estos componentes.

En el prototipo hay dos factorías. La primera gestiona los plugins que proveen modelos de acceso a determinado recurso. Tiene un método, getThingFromURI, que analiza una URI, y crea un sirviente para dar acceso a esa URI. El objeto que se retorna puede tener diferentes interfaces, dependiendo de los plugins que soporte. En el prototipo, sólo hay uno registrado, que presenta una interfaz de tipo FILE, y que soporta el esquema HTTP.

La segunda factoría, gestiona modelos de datos. Aunque la interfaz tiene varios métodos, el más interesante es simpleCreateDataModel, que crea un sirviente para un modelo de acceso determinado. Los plugins de esta factoría son capaces de "entender" y manipular el recurso, presentando una interfaz para manipularlo. El único plugin registrado en el prototipo es HTMLDir, que reconoce el formato HTML, lo "parsea" y genera una estructura de directorios con el contenido servido.

Cliente

La otra parte del prototipo es el cliente. Su cometido es sencillo: obtiene los proxies a las factorías antes mencionadas, y crea los sirvientes adecuados para explorar una URI de tipo HTTP (como "http://www.google.es"). Crea una interfaz gráfica muy sencilla (a modo de Skin) con un IconView para mostrar el modelo generado a partir del HTML.

He de remarcar que es un prototipo, por lo que no está depurado, no es tolerante a fallos y puede comportarse de forma indefinida, aunque por lo general, hará lo que le dices :) El código fuente está disponible para todo el que lo quiera probar. Depende de python-zeroc-ice y de pyicebox. Para probarlo, es necesario lanzar por un lado el DCP, usando:

$ ./launchFactories.sh

y por otro, el cliente, de una forma parecida a:

$ ./Client.py --Ice.Config=client.cfg http://www.google.es

Conclusiones

Todavía quedan muchas cosas por pulir:
  • Es necesario definir un mecanismo para registrar los plugins en las factorías correspondientes. En caso de que sea la factoría quien los cargue, es necesario establecer una interfaz para los plugins (interfaz que se implementará en el módulo).
  • Definir el mecanismo de interacción entre plugins, es decir, es necesario especificar aquellas interfaces que cierto plugin es capaz de manipular.
  • Se han de especificar las relaciones entre componentes activos, inactivos y no instanciados, así como los protocolos de reutilización, compartición y limpieza de recursos.
  • Es preciso determinar si es escalable o no, y la forma de hacerlo escalable. Por ejemplo, en un recurso con múltiples ficheros ¿se debería crear un sirviente por cada nodo? ¿Se podría utilizar un default servant?

Algo que he visto bastante acertado es la separación entre la "plataforma de componentes" y los clientes. Esto nos permite mucha flexibilidad a la hora de diseñar diferentes interfaces de usuario, o de hacer pruebas a la plataforma. También hace más sencillo entender todo como conjunto (divide y vencerás), y escribir sus partes, siempre que estas sean lo más ortogonales posible.

Descargas

Monday, December 21, 2009

Organización de ideas

El pasado viernes estuvimos discutiendo algunos aspectos interesantes de TwinPanel. De ahí, obtuvimos varias ideas clave y otros puntos un poco difusos (al menos, para mi).

Partimos de la idea de Recurso, que fué una de las más controvertidas ;). Un Recurso no deja de ser un modelo (de acceso, si se quiere aclarar), al igual que los otros modelos que ya teníamos (los modelos de datos). La distinción que queríamos hacer principalmente se mantiene (la que diferencia entre el mecanismo de acceso a los datos, y la manipulación de estos), pero no se añade (a primera vista) una capa más (aunque esto es discutible :P)

Queremos respetar el MVC a toda costa, algo que me parece muy bunea idea, dada la pluralidad de interfaces de usuario que vamos a tener.

También quedó claro que la arquitectura para todo esto nos la provee perfectamente Ice, más concretamente IceBox + Slice. Usaremos el evictor de IceBox para gestionar dinámicamente los plugins instanciados (una pena que PyIceBox no tenga evictor, así que o lo implementamos o usamos otros lenguajes...). Por tanto, algo en lo que tenemos que trabajar primero es en la factoría de plugins.

Si, por ejemplo, queremos inspeccionar una URI dada, como "http://www.google.es", tendríamos primero que comprobar si denota un proxy válido (pues cualquier cosa que se desee explorar, deberá primero tener forma de proxy). Si no lo es, habrá un componente que se encargue de convertir esa URI. Ese componente, que posiblemente esté asociado a la factoría, deberá buscar un plugin capaz de manipular ese recurso, en este caso, un plugin para HTTP. Se creará (o se retornará) una instancia que manipule nuestra URI y ya tendremos el proxy que buscábamos (al modelo de acceso). Ahora, necesitaremos otro plugin para manipular el contenido del recurso, que se creará de forma análoga. Por último, una tercera entidad deberá representar de forma visual el contenido de los datos, aunque esta parte no es imprescindible, pues este modelo puede ser fuente para otro modelo, que a su vez... Sí, los modelos son 'stackables' :)

Como vemos, otra labor vital que resolverá parte de los problemas actuales de TP, será definir las interfaces para todos los tipos de modelos necesarios.

Un problema que tendremos que resolver será el mecanismo para decidir que modelo escoger. Por ejemplo, el de HTTP puede ofrecer una interfaz de tipo FILE, la más común. Pero también se puede diseñar un interfaz de tipo HTTP, que implemente los verbos correspondientes: get, post, etc. En el siguiente nivel (modelo de datos), ocurre exáctamente lo mismo, y también en la capa de presentación.

Por otra parte, en lo que se refiere a la factoría, también se han oido ideas curiosas que hay que resolver, como el hecho de que sea distribuida (y por tanto, sea necesario un mecanismo de descubrimiento de "factorías", o búsqueda, con algo como ASD.Search).

El caso es que esto está tomando un cáriz interesante :D Ahora te toca a ti, busca los siete gazapos :P

再见!

Tuesday, December 8, 2009

Un par de sugerencias

Buenas llevo tiempo detrás de escribir un par de sugerencias, hasta ahora sólo he estado leyendo los post y comentarios, y hoy me he decidido a hacerlo. Tened en cuenta que aunque he estado mirando algo de código estoy muy muy verde, gracias por vuestra comprensión y espero que os sirvan de algo.

1) Desacoplar Twin Panel - GTK

Hasta ahora por temas de rendimiento Twin Panel utiliza TreeViewPanel de GTK como representación interna, pero para permitir el desacople con GTK o con cualquier otra tecnología se puede recurrir al patrón Factoría, de forma que según el tipo de interfaz requerida (puede seleccionarse a través de un fichero de configuración o un parámetro en el arranque), genere una instancia especifica que es utilizada a través de una interfaz genérica. Vamos con un ejemplo: Si a la factoría se le pide una instancia de la aplicación para escritorio, esta construirá un TreeViewPanel de GTK, como hasta ahora; si en lugar de esto se le llama solicitándole la aplicación para consola, devolverá una instancia con otra representación interna; pero ambas tienen la misma interfaz.

Es decir, sería necesario especificar una interfaz con los métodos necesarios para trabajar con los modelos de representación interna, de forma que se permita desacoplar la tecnología, y permitir además la implementación multiplataforma pero sin perder la eficiencia que proporciona el trabajar con un modelo interno específico.


2) Sobre la inspeción de recursos.

Como bien han comentado David y Oscar en anteriores posts, uno de los problemas de TP es que mezcla la forma de acceder a un recurso con la forma de analizar o usar dicho recurso.

Por lo tanto debe de haber un analizador de URIs que por un lado, sepa qué usar para acceder a ese recurso (según el método o protocolo que se haya especificado) y por otro lado decidir el inspector a usar.

Por ejemplo tenemos http://example.org/video.avi, ftp://example.org/video.avi para ese recurso una vez se accede a él a través de un protocolo, se pueden realizar diferentes acciones, como abrir el navegador web, abrir un dialogo para almacenar el fichero, mostrar un resumen de la información del vídeo, traer el vídeo, lanzar un reproductor, etc. Todas estas acciones pueden ser realizadas con el recurso definido por esa URI, por tanto, puede que según el tipo de protocolo y de fichero, y los inspectores que se tengan instalados, puede haber un despachador que tenga una serie de reglas definidas, de forma que pueda o bien ejecutar la regla seleccionada (o la establecida por defecto) o solicitar la elección de una acción (preguntar por la regla a ejecutar y permitiendo a su vez que sea guardada como regla por defecto). Este comportamiento es el similar al que tienen los sistemas operativos con respecto a un fichero, donde según su extensión pueden tener definido quién es el programa encargado en atender ese fichero, o pueden ofrecer una lista de candidatos y elegir quién lo va a atender.

De la misma forma, al instalar un plugin este registra una serie de tipos de recursos que puede atender. Y así el despachador puede saber mirando la reglas que tenga, si debe utilizar un inspector u otro, o debe ofrecer los posibles candidatos para atender ese recurso.

Y enlazando con el post anterior si se indica en la ruta al recurso el modo o forma de acceder se usará el indicado, si no se usará el marcado por defecto para este tipo de recurso o si no se preguntará al usuario.



Thursday, December 3, 2009

URI, URL, URN y otras hierbas

Todo Resource debe ser identificado de alguna forma. A ser posible, que sea 'human readable' (como el XML :P). Esto no es nada nuevo, pero sería interesante comentar las opciones que tenemos, sean o no estándar, y que se adapten a nuestras necesidades. Sobre todo, sería muy interesante poder coger cualquier 'identificador' estándar y poder explorarlo.

En la primera versión de TwinPanel, usábamos algo llamado 'URI', pero que no se adecuaba a ningún estándar. Por ejemplo, para explorar un objeto Ice, usábamos algo como "ice://objeto -t:tcp -h host -p 1234". En los objetos complejos, que tienen jerarquía, separábamos el objeto de la "ruta" hacia el nodo, por ejemplo "ice://[objeto -t:tcp -h host -p 1234]/cameras/garage/". Si además es necesario añadir autenticación, entonces se puede añadir antes del recurso, por ejemplo "ftp://user:passwd@hostname/path/to/file".

La primera parte de estas URIs (lo que hay antes del '://') especificaba el tipo de acceso al recurso (ice://, http://, etc.). Ahora bien, nos surge la necesidad de especificar el acceso al recurso, pero también el tipo del recurso. Por ejemplo, subversion utiliza uris de la forma 'svn+ssh://box/path'. El recurso es un repositorio subversion, y la forma de acceder a el es por medio de ssh. A nosotros nos pasa algo parecido. Por ejemplo, tenemos un fichero zip, accesible por medio de http. En este caso, se podría omitir el modelo y dejar que algún mecanismo de introspección detectara que es. Esto es muchas veces caro, y alguna inviable. Por eso, surge la necesidad de ampliar nuestro esquema de nombrado de recursos.

Un ejemplo algo más claro: una imagen SVG modelada como un byteseq de Ice. Si no se especifica de algún modo el contenido de ese byteseq, se puede interpretar de muchas formas. Se podría detectar, analizando el byteseq, pero para eso, habría que obtenerlo primero (además, no siempre es posible detectar así el modelo). También se podría especificar como una propiedad, pero entonces se complica si queremos modelarlo como otra cosa (por ejemplo, como texto plano). Si esta información la añadimos al identificador del recurso, es inmediata la elección del modelo, y nos permite cambiar fácilmente entre distintos modelos.

Ahora, sería interesante elegir un esquema de direccionamiento. Uno de ellos podría ser URN, un identificador independiente de la localización, que es un tipo de URI. Básicamente, este esquema se compone de un identificador del dominio, mas un identificador dependiente del dominio. Algo así como 'urn:ice:object@adapter'. Esto sería perfecto si no fuera por la cantidad de restricciones que tenemos para componer el identificador dependiente del dominio. Cosas vitales como '/' o '[]' no son admitidas. Sí lo son en formato hexadecimal, lo cual es una carga a la hora de trabajar manualmente con ellas. Una posible solución pasaría por permitir al usuario entrar URN 'prohibidas' y convertirlas inmediatamente para manipularlas internamente. Así, se adaptaría al estándar a la vez que serían manejables. En esos casos, obviamente, prescindiríamos del prefijo 'urn:', con lo que tendríamos cosas como 'http:svg:server/path/file.svg', que sería traducida internamente a 'urn:http:svg:server%40path%40file.svg', o algo parecido.

¿Qué opinais?