sábado, 12 de enero de 2013

Comparando frameworks PHP (II) : El Modelo

Comenzar por el modelo, al analizar frameworks, puede no ser una buena opción. Pero creo que es un buen candidato para empezar a explorar el problema estricto del MVC (sin entrar en particularidades de dicho paradigma, dentro del desarrollo web).

Decir que este post es sobre "el modelo", es bastante general. En realidad, es sobre los sistemas de persistencia, y su relación con las clases que implementan parte del 'businness layer' del sistema.
Y, como primer paso, habría que definir exactamente a qué llamamos "modelo", porque haber incluido dos cosas distintas en el párrafo anterior, no es casual. Una de las preguntas frecuentes que suele aparecer en foros es sobre cómo encajar cierta funcionalidad dentro del modelo, vista o controlador.

Por ello, dentro del modelo voy a incluir dos cosas diferentes: Entidades de un cierto sistema (por ejemplo, la típica clase 'Producto'), y los sistemas capaces de persistir dichas entidades (a una base de datos, por ejemplo).

La justificación de esta separación, es clara: una entidad 'Producto' tiene las mismas propiedades, métodos, etc, independientemente de que los datos de una instancia de Producto, hayan sido almacenadas en XML, una base de datos, un fichero CSV, codificado en JSON o vía variables GET. Y, en esta lista, hay sistemas que ofrecen persistencia, y otros que no. Por eso, de forma más general, al proceso de "persistir" un modelo, yo prefiero llamarlo "serializarlo"  a un cierto formato o soporte.

Esto tiene muchas consecuencias: si 'Producto' tiene una relación con 'Compra', es porque conceptualmente existe esa relación; el hecho de que eso se traduzca en columnas de una tabla, foreign keys, etc,etc, son particularidades del serializador a base de datos.

En general, cualquier metadata pertenece a la Entidad, no a ningún serializador. Es decir, si la entidad 'Producto' tiene una propiedad 'nombre', y ese nombre tiene como máximo 20 caracteres, ese máximo ni lo especifica, ni se deriva de ningún serializador/sistema de persistencia. Es precisamente lo contrario; el serializador o sistema de persistencia debe tomar ese máximo del establecido en la metadata de la Entidad.

Hay otros motivos que demuestran esta necesidad: supongamos la propiedad 'password' de una entidad 'Usuario'.Supongamos que decidimos que un password debe tener un máximo de 10 caracteres.Supongamos que decidimos almacenar los passwords en la base de datos usando algún mecanismo de encriptación.
Muy posiblemente, la columna 'password' en la base de datos no tendrá 10 caracteres de longitud.

Otro motivo es que las propiedades de una entidad pueden estructurarse en formas "poco apropiadas" para un cierto sistema de persistencia.Supongamos que tenemos una entidad "Foto", que queremos que tenga una propiedad 'posicion' para almacenar el lugar donde se tomó la foto.Ese campo 'posicion' se compone de una 'latitud' y una 'longitud'.Para un serializador XML, que es anidado por naturaleza, almacenar la propiedad 'posicion' no es un problema.Para un serializador MySQL, lo que nos fuerza a guardar son las columnas 'latitud' y 'longitud', cuando , en realidad, desde un punto de vista conceptual, no son datos independientes.Son subpropiedades de una propiedad superior, llamada 'posicion'.Obligar a la entidad (que no es más que una clase PHP) a definir sus propiedades según las necesidades de un cierto soporte de datos, es algo que no debería ocurrir.

Algo interesante que también hay que estudiar cómo los diferentes frameworks implementan, es si las clases Entidad, se refieren a una instancia, o a una colección de instancias, o a ambas cosas a la vez, debido a su relación con los sistemas de persistencia.Es decir, ¿se usan las clases Entidad para obtener / modificar / eliminar más de 1 instancia de dicha entidad, para, por ejemplo, crear un listado?
Es esto un uso "legitimo" de la clase entidad? Y, siendo más prácticos, qué podemos pensar sobre el rendimiento?

Otras cosas que, conceptualmente, me llaman la atención de la capa del modelo, es a qué sistema pertenecen las entidades que existen dentro de él.Supongamos que queremos hacer una tienda online. Supongamos que las secciones de la web, por algún motivo, las queremos tener en base de datos, y asociarle plantillas, imágenes, tags meta, textos,tiempos y sistemas de cacheo, etc. Además, queremos tener configuraciones para la publicidad, unos feed rss, etc,etc.

Lo más probable es que todas esas cosas acaben siendo entidades.Pero, ¿la naturaleza de esas entidades es la misma que la de Producto, Compra, Factura,Inventario,etc que componen el sistema de la tienda?
En mi opinión, no.Las entidades que modelan las páginas,secciones, feeds, emails, etc, pertenecen a un "sistema" independiente , que es el "sistema web", que tiene sus propias reglas de negocio, independientes de las reglas de, en este caso, el "sistema tienda".De hecho, el "sistema web", existirá , con mucha probabilidad, en cualquier web que hagamos, y su funcionalidad es la misma que un CMS.
Es decir, la capa "M" es única? En mi opinión, en cualquier web, existen al menos dos sistemas distintos.Si un framework permite mantenerlos separados, y, pidiendo la luna, incluye un CMS que permita una fácil inclusión de contenidos procedentes del "otro" sistema, me parecerá que es mejor que otro que no lo haga.

Aparte, hay muchas otras cosas que se le pueden pedir a la capa del Modelo:
  • Herencia de Entidades.La entidad B deriva de A.Se puede instanciar tanto objetos de B, como de A.
  • Factoria de Entidades.La entidad B deriva de A, pero su "rol" es de "tipo".Es decir, B es un tipo de A, y todo A tiene un tipo.Por lo tanto, no se pueden crear instancias "puras" de A.Si se instancia A,se obtendrá una clase B, o C, o D, según el tipo de ese 'A'.
  • Relaciones 1:N, M:N e inversas.Con inversas quiero decir: Si A tiene una relación con B, B tiene una relación inversa con A, que representa todos los A que apuntan a B.
  • Relaciones basadas en más de 1 campo: A se relaciona con B usando más de un campo.
  • Estaría interesante poder nombrar relaciones específicas. Supongamos que tenemos una entidad Usuario, con una relación a la entidad Compras.La entidad Compras tiene un campo 'estado', que puede ser 'pagada' o 'no pagada'.Sería interesante poder acceder, desde Usuario, a las compras 'pagadas' o 'impagadas' , de forma sencilla.
  • Estructuras de árbol (Entidades con relacion "padre" a una instancia de la misma entidad).Esto significa que el framework proporciona a esta entidad, métodos como getChildren(), getParent(), isLeaf(), etc.
  • Estructuras de grafo (Entidades con n relaciones a instancias de la misma entidad).Esto significa que el framework proporciona a esta entidad métodos como getConnected().
  • Cómo modela cada framework el caso de relaciones M:N con propiedades? Por ejemplo, un Producto puede tener una relacion M:N con Compras, modelando los productos incluidos en una cierta compra.Pero esa relacion M:N tiene propiedades, como "numeroUnidades".Al tener propiedades (y, posiblemente, métodos), pasa esta relación, a convertirse en una entidad? En caso contrario, cómo se modela?
  • En caso de que haya separación entre Entidad / sistema de persistencia, cómo se mantienen separadas la metadata de la Entidad, de la metadata del sistema de persistencia (por ejemplo, qué índices requiere una cierta tabla que almacena dicha entidad).
  • Si A está relacionado con B, y tengo una instancia de A, y hago la siguiente secuencia:
    - 1) Modificar la instancia de A.
    - 2) Obtener la instancia de B relacionada con ese A.
    - 3) Modificar la instancia de B
    Qué objetos tengo que guardar? A? B? ambos?
Supongo que saldran más preguntas, a medida que vayamos viendo la capa de modelo de los distintos frameworks, pero, para empezar, es una buena lista, que va más allá de simplemente esperar que un ORM cargue una fila de una base de datos a partir de un ID.

Obviamente, he puesto el foco en la funcionalidad, no en el rendimiento,Independientemente del sistema del que se hable, lo más rápido que vaya, mejor.Como decía al principio, lo que busco es ver qué características de los frameworks ayudan a implementar el paradigma MVC, más que en ver qué cosas se sacrifican en pos del rendimiento.
En un próximo post, veremos Symfony , con sus ORM's Propel y Doctrine. Hasta entonces!!

viernes, 11 de enero de 2013

Comparando frameworks PHP (I) : Introducción

Quisiera comenzar una serie de posts en los que hacer una comparación crítica de algunos frameworks que hoy en día pueblan el ecosistema PHP.
Sin embargo, no se lo quiero poner fácil; la mayor parte de los frameworks PHP, publicitan sus virtudes en comparación con la programación PHP "tradicional", (léase, la existente hace unos 10 años).

Pero, después de varios años en los que la tendencia han sido los frameworks (y ahora, los microframeworks, y mañana...), y con la experiencia acumulada, la referencia al comparar los distintos sistemas, ya no debe ser el PHP heredero de la versión 3.0.

El paradigma Modelo-Vista-Controlador ha llevado a muchos programadores a pensar en esos términos. Tras los años de uso de dicho paradigma, las virtudes de los frameworks pueden empezar a medirse según las facilidades que dan para usar eficazmente dicho paradigma, y no sólo sobre las ventajas que tienen sobre el PHP "pelao y mondao".

Por mi parte, durante muchos años he estado reflexionando sobre los modelos de desarrollo PHP, probando diferentes aproximaciones, no sólo MVC. Esto me ha mantenido algo al margen de la tendencia a usar frameworks "populares", pero, cuando he leído algo sobre ellos, he visto que intentaban resolver los mismos problemas que me había ido encontrando en el pasado.

Por ambas cosas, es posible ya mirar hacia delante, en vez de hacia atrás, y buscar características avanzadas que ayuden a profundizar en el paradigma MVC, o, de forma más general, en los problemas inherentes al desarrollo web.

Para comparar los frameworks, voy a hacer "listas de los reyes magos", o sea, pedir cosas que pienso que sería útil que tuvieran, y ver hasta qué punto son soportadas en un conjunto de frameworks más o menos reconocidos, teniendo en cuenta que no tengo demasiada (o nula) experiencia previa con los mismos, y mi única referencia será la documentación, y artículos relacionados existentes en la web.

Para mí es también toda una experiencia de aprendizaje, no tanto por aprender a usar los frameworks en sí mismos (no es el objetivo), sino para ver distintos enfoques a los mismos problemas, y ver qué filosofía impregna cada uno de los sistemas analizados.