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!!

1 comment:

MagMax said...

A ver... conste que yo no tengo mucha idea, ya que no me peleé con la versión anterior.

El caso es que creo que la solución es "complicar" un poco el get y el set. Tú no deberías decir "set(blob)", ya que es demasiado específico, sino "set(object)". El object es un "blob".

De esta manera, es posible que a un zip le pasemos un objeto corba, mezclando churras con merinas.

Ante esto, pueden ocurrir dos cosas:

- Que el Access sepa interpretarlo. En cuyo caso, lo interpretará y todo queda ahí.

- Que el Access no sepa interpretarlo. Mala suerte. Se lanza una excepción y ya la capturará el programa principal, que puede decidir intentarlo con otro Access, realizar una operación por defecto o bien mostrar un mensaje por pantalla al usuario.

Evidentemente, el get funcionará de la misma manera, recibiendo un argumento: En qué quieres que lo convierta.

Otra opción es funcionar de forma similar a gstreamer, creando filtros que permitan comunicar Access, pero creo que esto es mucho más complejo (se necesitarían n! filtros, siendo n el número de Access o Recursos). Creo que es mejor que cada Access sepa qué soporta y sea él quien trate de transformar el objeto.

Evidentemente, hay dos maneras de implementar esto que cuento: usando polimorfismo o no usándolo. Personalmente, creo que en este caso el polimorfismo tiene más inconvenientes que ventajas, así que propongo no usarlo. Así, el get sería algo como:

get ( class )

y el set:

set ( object, class )

(sí, en algunos caso ni hará falta ese class).

Es posible que no haya dicho nada que se ajuste a lo que queréis, pero... ¡¡ Se intenta !! ;)