Mostrando entradas con la etiqueta estilo de programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta estilo de programación. Mostrar todas las entradas

miércoles, 18 de noviembre de 2009

Cosas que hago mal

Dejando aparte errores de sintaxis y algunos fallos lógicos, más o menos normales, he estado pensando que hago algunas cosas mal en mi "estrategia" (por decir algo) de desarrollo.

Una de las principales es que tiendo a centrarme demasiado en lo periférico, con lo cual avanzo relativamente poco en mis tareas, aunque teclee innumerables líneas de código.

Por ejemplo, llevo unos meses trabajando (un poco irregularmente) en el desarrollo de un proyecto que, en principio, será un CMS y la base para una aplicación de Intranet para el colegio en el que trabajo.

Pues bien, he dejado la parte de CMS para el final, y mientras tanto he estado desarrollando módulos auxiliares que, si bien son importantes, no son el objetivo principal de la cuestión. Sólo últimamente he empezado a trabajar en el módulo de contenidos, el cual, en muchos aspectos debería haber sido el primero (o uno de los primeros, ya que también me resulta muy importante el de gestión de usuarios y autorización).

Con todo, no he estado parado, sino que he desarrollado una serie de módulos que aportan gran cantidad de funcionalidad: comentarios, etiquetas, licencias, colecciones, uploads..., pero todavía no hay una aplicación real que esté funcionando. Lo que resulta frustrante.

La cuestión es que desde un punto de vista más "pragmático" lo lógico hubiera sido empezar a desarrollar la parte de gestion de contenidos (dejaré fuera de la cuestión la parte de acceso, que estoy revisitando ahora mismo) y seguramente estos otros elementos hubieran ido surgiendo de forma natural, aportando funcionalidad "avanzada" a la básica.

Mi CMS se estructura en torno a los modelos Channels e Items. Los Channels son canales, que pueden ser blogs, podcasts, photologs o similares. Los Items son los posts, episodios, etc. Si conoces la estructura de los RSS entenderás en qué me he inspirado.

La idea que intento explicar es que probablemente es más eficaz y mejor práctica comenzar por desarrollar una funcionalidad básica "gruesa", sin preocuparse de detalles. Es decir, en este caso, poner a funcionar mis channels e items, perfeccionando luego, de forma iterativa, el sistema añadiendo nuevas prestaciones.

Probablemente eso ayudaría también a mantener una buena motivación a lo largo del trabajo, cosa que en algunos momentos hecho de menos.

jueves, 16 de julio de 2009

Usando plugins para modularizar aplicaciones

Después de una temporada de alejamiento "forzoso" del desarrollo con CakePHP he decidido afrontar un par de nuevos proyectos utilizando nuevos enfoques en mi metodología de trabajo.

El primero de ellos es la modularización del código en base a plugins. El otro es la introducción del unit-testing y del desarrollo dirigido por tests.

Hoy voy a escribir sobre los plugins, por qué me he decidido a replantear mis aplicaciones con ellos y qué detalles he descubierto que hay que tener en cuenta para hacerlos funcionar bien.

Modularizar con plugins

Una queja habitual de la estructura de CakePHP es que no se pueden organizar los modelos, controladores y vistas de forma significativa, pues todos los modelos tienen que ir juntos en su carpeta, al igual que todos los controladores, etc.

Los plugins nos permiten abordar ese problema ya que con ellos agrupamos los modelos, controladores y vistas (y sus extensiones) que guarden alguna relación. Cada plugin es como una mini-aplicación CakePHP y en su interior reproduce su estructura general.

Los plugins pueden ser bastante autocontenidos, de modo que es sencillo reutilizarlos en nuevos proyectos. Supongamos, por ejemplo, que hemos creado un sistema de gestión de usuarios y grupos con el que nos encontramos muy a gusto. Si lo tenemos como plugin, tan sólo debemos copiar la carpeta que lo contiene en la nueva aplicación para disponer de toda la funcionalidad.

En cambio, si no está en forma de plugin, es más fácil perder la pista de algún archivo a la hora de copiarlo, en especial si se manejan varios modelos, etc.

Mi objetivo al usar plugins

Pues mi objetivo es muy sencillo. Se trata de tener "piezas" de código relativamente independientes que puedan servir para montar una diversidad de aplicaciones. De este modo dispondré de una especie de "superframework" con módulos reutilizables. Cada aplicación o proyecto tendría partes propias, y partes comunes. De este modo, al avanzar en uno, estoy contribuyendo a otros. Y, por otro lado, me puedo concentrar en el núcleo de una aplicación específica.

Y en caso de trabajar en equipo, es fácil distribuir el trabajo.

Por otra parte, los plugins son también una buena manera de crear bibliotecas de behaviors, components o helpers, que puedan reutilizarse en varios proyectos. Lo bueno, es que puedes agruparlos por algún criterio útil. Por, ejemplo, una biblioteca de helpers relacionados con la interfaz de usuario. O un módulo con un behavior para añadir comentarios a cualquier otro objeto, que incluye la gestión de los mismos.

Creando un plugin

Lo mejor es utilizar cake bake para crear la estructura básica del plugin.

cake bake plugin nombre_del_plugin

Lo más importante a tener en cuenta es que los modelos y controladores dentro de un plugin no deberían descender de AppModel o de AppController, sino indirectamente, a través de AppPluginModel o AppPluginController. Cake Bake se ocupa de eso por nosotros.

También podemos generar modelos y controladores básicos mediante cake bake

cake bake plugin NombreDelPlugin model NombreDelModelo

Accediendo a las acciones de un plugin

Las URL que nos llevan a un plugin son las típicas de cake prefijadas con el nombre del plugin:

/plugin/controller/action/param

Como, por ejemplo:

/content/posts/edit/first_post
/admin/tickets/tickets/edit/123

Como puedes ver, también es posible usar el admin routing con plugins.

Por otra parte, es perfectamente posible llamar a las acciones de los plugins con RequestAction.

Creando URL

En el caso de que crees las URL para link o redirect con el formato array, debes incluir la clave 'plugin' con valor true.

array('admin' => true, 'plugin' => true, 'action' => 'index')

Asociaciones con modelos dentro de un plugin

Cuando necesitamos asociar un modelo con otro que está en un plugin, tenemos que indicárselo. Puede ser en la forma simple:

var $hasMany = array('Plugin.Modelo');

O si tienes que especificar parámetros de la asociación, incluyendo la clave

'className' = 'Plugin.Modelo',

Recuerda que ésta, y las demás indicaciones, se aplican incluso cuando los modelos asociados están en el mismo plugin.

Usando behaviors, components o helper de un plugin

Decláralos como siempre, añadiendo antes el nombre del plugin, como en este ejemplo:

var $actsAs = array('Comments.Commentable);

Usando elementos de un plugin

Entre los parámetros que pasamos al elemento, hay que indicar la clave 'plugin' y el nombre del plugin.

element('ejemplo', array('plugin' => 'el_plugin')); ?>

Importando modelos o controladores

Hay que indicar el nombre del plugin, para que importe el objeto correcto.

App::import('Model', 'Plugin.Model');
App::import('Controller', 'Plugin.Controller');

Testing con plugins

Algunas cosas que he observado que es necesario tener en cuenta son:

Los controladores que usamos para testar deben incluir el parámetro plugin (gracias a Mark Story)

class TestPostsController extends PostsController {
var $plugin = 'Content';
}

Y hay que tener en cuenta el apartado anterior para importar los objetos que estén en plugins.

La declaración de las fixtures, también lo tiene en cuenta:

var $fixtures = array('plugin.content.post);

El test suite de CakePHP trata cada plugin aisladamente, lo que resulta muy cómodo y casi te evita tener que hacer grupos de tests por funcionalidad u otro criterio.

Shells

Puedes empaquetar shells en plugins. Crea la ruta vendors/shell dentro de la carpeta del plugin que se trate y pon ahí los shells que desees. La utilidad de línea de comandos cake sabrá acceder a ellos.

Por supuesto, hay más información en el Cookbook.

miércoles, 17 de septiembre de 2008

Encuesta chorra (o no)

Aprovechando que el Blogger ahora admite encuestas (ver arriba), se me ha ocurrido la siguiente pregunta. Supongamos que tienes un sistema de blogs con los modelos Blog y Post, asociados de modo que Blog hasMany Post.

Ahora supongamos que la raíz del sitio (/) saca una lista de todos los Post recientes, con independencia del Blog al que estén asociados. Es decir, una accion como /posts/index.

Por supuesto, cada Blog tiene su página principal, que muestra una lista de posts. Mi primera tendencia fue a crear una accion /blogs/view/blog_id, pero me dije: "Un momento, esto no es más que un /posts/index/blog_id. Puedo hacer que /posts/index maneje la situación de listar sólo los post de un blog determinado".

Así que en principio creé una acción que modificaba la búsqueda de datos en función de si se pasaba un parámetro para indicar un blog. Luego en la vista, incluí una lógica para actuar de manera ligeramente distinta si se listaban los post de todo el sitio o si eran sólo los del blog indicado. Como tampoco me gustaba, preparé dos vistas y dejé que el controller eligiese la adecuada.

Sin embargo, esta solución tampoco me convence. Finalmente he decidido crear dos acciones en el PostsController (index y blog), cada una con su vista. El Controller ahora no toma tantas decisiones, y la vista tampoco. Pero ¿Qué opinas tú?