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?

Friday, November 27, 2009

Interfaces: Resource

¡Hola!

Creo que es hora de ir pensando en cosas más profundas. Por ejemplo, en definir las interfaces que hemos visto hasta ahora. Por estos lares ando con un poco de miedo, pues la causa del "fracaso" del anterior diseño fue esto mismo: un mal diseño. Meter la pata a estas alturas nos va a costar mucho posteriormente.

De todos modos, por algún sitio hay que empezar. Y supongo que con la experiencia anterior, podremos ahorrarnos algunos errores. ¿Y qué tal si empezamos por los Recursos? Ok.

Ya hemos definido lo que es un recurso. También se comentó lo interesante que sería que todos los recursos compartiesen una misma interfaz. Así, todos los tipos de Modelo que pueda haber son accesibles usando cualquier mecanismo de acceso.

Un inciso: propongo cambiar la nomenclatura: recurso por acceso, pues me parece más próximo a la realidad. En este post, usaré Access como el mecanismo de acceso al recurso (por ejemplo, HTTP, FTP, File, etc).

Por ejemplo, si tenemos un AccessHttp, y añadimos un Modelo nuevo, con sus correspondientes inspectores, no es necesario hacer nada especial para que este modelo use el AccessHttp. Esto es una ventaja considerable, pero para ello, tenemos que ver si sería posible acceder a todos los recursos existentes usando una misma interfaz.

Podemos intentar ver si TODOS los casos son factibles. O mejor, encontrar uno que no encaje. Veamos, el mecanismo de acceso que se utiliza más comunmente es el consabido par get/set. Supongamos que dotamos al acceso de esta interfaz:
class Recurso:
    def get(): pass
    def set(blob): pass
Para HTTP, FTP, File... es válida. Son accesos que te proporcionan el recurso entero. Si las condiciones te lo permiten, es viable. Veamos un caso más complejo: Ice/CORBA/etc. Aquí, dependemos del tipo del recurso. Si es un entero o un byteseq, se puede seguir usando. Pero, ¿y si el "objeto" tiene una interfaz más compleja, por ejemplo AVStreams? Tendríamos un problema. Claramente no nos sirve, porque a lo que estamos accediendo no es a un recurso que se pueda tratar como un fichero o una imagen.

Vemos que una úinca interfaz, aunque interesante, no es posible. Tendríamos que crear una para cada tipo de recurso. Ya no es dependiente del mecanismo de acceso, porque es posible acceder a una fichero zip usando Ice, o a un objeto Bool usando File. Tendríamos un Access para recursos de tipo, llamemosle Data, que cubre un amplio espectro de uso. Pero también habría un Access para otros tipos de recursos (hay que pensar cuales).

Esto complica la estructura. Ya no solo clasificamos los Access por el mecanismo de acceso (FTP, etc.), sino también por el tipo de recurso al que se accede (un "Data", etc.). Quizá no sea esto lo que queremos.

¿Qué pensáis? Necesito ideas...

[Edición] Se me ocurre que en el caso de objetos Ice con interfaces complejas, podríamos considerar que la interfaz es parte intrínseca del Objeto, y que es el inspector quien sabe como usarla. Así, tendríamos un Access que provee la capacidad de "llamar" a métodos Ice (ya sea usando Ice, HTTP o File), sin conocer la interfaz real (es decir, un Access con dynamic Ice). Delegamos en el inspector el tratamiento del recurso. Esto se parece a lo que teníamos, pero con la salvedad de que ahora el acceso al recurso es transparente para el inspector (el inspector pide los ice_ids del objeto, y si el AccessX los obtiene de una base de datos, eso no importa). Y lo que es más, el inspector no tiene porqué conocer siquiera si el objeto está implementado en Ice o en CORBA. Eso es tarea del Access.

Quizá este tratamiento se pueda generalizar. Así tendríamos sólo tres o cuatro tipos de Access.
La siguiente figura es un ejemplo de cómo lo veo:



Un Model concreto podría dar soporte a una interfaz Access, por ejemplo, a DataAccess, siendo independiente del Access real que se use (DAFile, DAIce, etc.).

¿Como lo véis? ¡¡Feedback!!

Wednesday, November 25, 2009

Cuestión de conceptos

Bueno, dado el anterior post de David, ahora tengo claros algunos conceptos más. Pero, para mi sigue siendo un montón de ideas en el aire, con relaciones parciales entre ellas. Necesito ponerlas en algún sitio, establecer esas relaciones y verlo todo como un conjunto conexo. Por eso, me gustaría empezar a distinguir y definir conceptos. Por supuesto, las cosas que falten, ya sabéis... comentarios.

A primera vista, los conceptos son: Recurso, Modelo, URI, Factoría, Inspector, Skin... TwinPanel :P De momento, un conjunto de nombres. Pongámosle caras.
  • Recurso: es el "qué". Aquello que se quiere utilizar, es la entidad a la que se desea acceder (no se me ocurren palabras más genéricas que realmente digan algo).  Por ejemplo, un fichero zip en un directorio ftp de cierta máquina de nuestra red (como URL, sería "ftp://abox/ftp/afile.zip"). A nivel de TP, el recurso se puede considerar como un "proxy", un representante de lo que se quiere utilizar, y que sabe como acceder a él. El recurso (para TP) encapsula el mecanismo de acceso a esa entidad.
  • Modelo: especifica cómo se debe manipular el recurso. En el ejemplo anterior, tendríamos un fichero comprimido. El "modelo" es quien sabe lo que se puede hacer con ese fichero comprimido: leer su contenido, descomprimirlo, añadir otros ficheros, etc. El modelo es una entidad abstracta, que será instanciada por los Inspectores.
  • URI: es un identificador del recurso. Bien puede decir qué es (URN), o bien dónde está (URL). Este concepto es el más claro, aunque su estructura no la tenga tan clara... :D
  • Factoría: es la entidad encargada de proveer los componentes necesarios para inspeccionar determinado recurso. Antes, era un componente bien conocido, pero puede que cambie un poco su "personalidad".
  • Inspector: es el encargado de tratar con el contenido del recurso. Es la instanciación de un modelo. Para cada modelo puede haber varios inspectores, dependiendo de factores como la tecnología usada para tratar el recurso. Así, para el zip, tendríamos un inspector que usase "zip", y podríamos tener otro que se sirviera de un mecanismo online para ver el fichero, por ejemplo.
  • Skin: es la representación del recurso de cara al usuario: la vista del mismo. Este concepto tampoco ha variado mucho desde sus inicios, aunque sí la tecnología subyacente (¡ahora puede estar distribuido!). Utiliza un inspector para acceder al recurso.
Voy a intentar desempolvar los conceptos de UML para dibujar un ejemplo de clases.


Aquí se representan sólo las relaciones entre recursos, modelos e inspectores, y con ejemplos para verlo un poco más claro.

Ahora, podemos discutir cosas. Por ejemplo, la interfaz que debe conocer un modelo de cierto recurso. Si es diferente para cada recurso, un modelo dado debe ser consciente de los recursos para los que está disponible, algo que no es desable. Entonces, debe ser la misma para todos los recursos. Habría que ver si es posible una interfaz que sea práctica para todos los casos posibles.

De todos modos, ¿qué pensáis?