Parametrizando datos

April 16th, 2008

Stormie, CMS / FrameWork Tiendas OnlineLa estructuración de datos en la aplicación Stormie se basa en un conjunto de tablas, en las que se definen una serie de relaciones, que permiten parametrizar los datos para ser tratados de forma automática.

Productos

¿Cómo guardar la información relativa a los productos si de una tienda a otra, los campos relacionados pueden variar de forma abismal? fue de las primeras preguntas a responder cuando comencé a dar vueltas a la estructura de datos que soportaría la aplicación.

Una de las cosas claras es que se haría uso de una tabla de productos, donde se guardarían los datos (nombre, descripción, precio) asociados a ellos. Los nombres de los campos, no podrían llamarse de una forma lógica (es decir, diferente para cada cliente en función de lo que fuese a contener), pues la aplicación debe controlar los campos de forma automática, sin necesidad de estar cambiando los nombres de los campos en los scripts. Los campos, pues, se llamarían de forma progresiva como campo_01, campo_02… menos el campo identificador, que se llamaría siempre id.

Mapeo de campos. Por este sistema, quedaba estandarizada la nomenclatura de campos, pero existían varios problemas. El primero, que en muchas ocasiones se necesita saber de qué tipo es el campo en cuestión; en base a ello Stormie toma unas decisiones u otras en la presentación o mantenimiento de datos. En segundo lugar, un campo puede ser clave ajena; la aplicación necesita saberlo para coger los datos automáticamente de la tabla relacionada. Y el tercero, es que se pierde la referencia de qué campo se está tocando; campo_07 no dirá mucho de lo que contiene si no entramos en la tabla y lo deducimos por sus valores.

Para solventar todos estos problemas, creé una tabla de mapeo, que contendría el nombre físico (campo_01, campo_02), el nombre lógico al que correspondería (título, descripción), el tipo de dato (entero, fecha…) y la tabla de quién es clave ajena (en caso de que lo fuera).

A la hora de instalar la aplicación, bastaría rellenar la tabla de mapeo y la aplicación se encargaría de todo lo demás.

Categorías

Las categorías, como los productos, podían tener estructuras muy dispares, y Stormie debía ser capaz de adaptarse a toda posibilidad. Un producto, no siempre tendría asociada una única categoría (la relación podría ser de 1 a n, de 1 a 1 o de 1 a 0), por lo que quedaba descartado meterlo como posible campo de la tabla de productos. Se crearía por tanto una tabla que relacionase los productos con las categoría/s a las que perteneciese.

En cuanto a la jerarquía… pueden existir indefinidos niveles de categorías (subcategorías, subsubcategorías..), haciendo inviable que cada nivel estuviese en una tabla. Pensando un poco, se me ocurrió indicar la jerarquía en una única tabla, usando un campo llamado nivel_previo, que contendría el id de la categoría anterior a la que perteneciese la categoría. (Si la categoría fuese de primer nivel, el valor del campo sería 0). Este campo, sería clave ajena de la propia tabla. (Modelo Jerárquico)

Añadiendo funcionalidad

Las búsquedas, los filtros, noticias, enlaces… se definen en tablas… y se comentará en el siguiente capítulo… :P


Un script para gobernarlos a todos

April 4th, 2008

Stormie, CMS / FrameWork Tiendas OnlineDesde hace varios meses, vengo desarrollando un script / aplicación que combina elementos de CMS con elementos propios de un framework, al que he puesto por nombre Stormie (en honor a Susan Storm, aka La mujer invisible), y que sirve para desarrollar tiendas online de forma cómoda y rápida. Esta es la primera parte, a modo de introducción, de su post - mortem. (Versión actual 1.07.01)

La idea

Si hay algo que incordia a un programador, es repetir una y otra vez lo mismo. En una empresa, además, esto se traduce en importantes retrasos en la salida de proyectos y en una mínima eficiencia en la gestión de recursos. Y cuando se trata de una tarea más o menos uniforme, puede ser un verdadero trauma. Imaginemos que tenemos que desarrollar 5 tiendas online, cada una de una tématica diferente. Crearíamos una y luego la clonaríamos, cambiando lo necesario. Dicho así no parece tampoco nada tedioso, pero imaginemos que, por ejemplo, tenemos que andar tocando en los 4 sitios restantes los nombres de cada campo, las consultas, el diseño… se pierde mucho tiempo en algo sistemático…

Stormie, por tanto, nació para solventar ese problema, siendo capaz de controlar cualquier tipo de tienda online, aislando código (php) de diseño (xhtml - css) y haciendo que la productivad entre un equipo de programadores y diseñadores, además del tiempo de desarrollo, sea más que interesante.

Comenzando

Las tareas de diseño llevaron un par de días. Había que pensar en una forma de parametrizar lo más posible los elementos de una tienda online, de modo que el script pudiese adaptarse prácticamente a cualquier petición o necesidad del cliente. El asunto se centraba en dos partes: datos y diseño.

Diseño: uno de los puntos fuertes de la aplicación es que permite adaptarse a cualquier diseño, puesto que todo el código xhtml se define en plantillas. Los datos dinámicos se calculan en los scripts, pudiendo ser llamados desde la propia plantilla y siendo reemplazados por el parser de la aplicación.

Dos ventajas fundamentales de este sistema es que un diseñador podría tocar los ficheros .html y adaptarlos a su CSS, sin necesidad de que el programador inserte ese código en los .php a través de echos o afines. :P Y otra derivada de ésta, es que se desliga por completo la relación del estilo visual y la disposición de elementos en la página web de todo el cálculo de los datos a mostrar, dando una mayor sensación de orden e integridad.

Datos: los diferentes datos que puede manejar una tienda, puede diferir mucho de aquellos que maneje otra. Por ello, hubo que dar varias vueltas a cómo se guardarían los datos y a cómo, de alguna manera, se podían definir de forma genérica, para que el script los tratáse de forma automática, sin necesidad de estar tocando código alguno.

La solución, a grandes rasgos, fue crear una serie de tablas standar, con la suficiente flexibilidad de adaptación y, para aquellos datos imprebisibles, hacer que con las funciones de la aplicación fuese fácil añadir módulos o código adicional.

Próximo capítulo

Datos. Tablas. Relaciones. :P :D


Wendy: ¿qué árbol es?

January 19th, 2008

Ayer noche y hoy tarde he estado trabajando en un pequeño programa, Wendy, echando una mano a mi chica y a sus compañeros de prácticas. Éste es su post-mortem.

Descripción

El programa desarrollado debía ser capaz de mostrar el nombre de un árbol en función de unos datos (altura, tipo de hoja, fruto que da..) que previamente hubiera introducido el usuario. Es decir, se presentarían en pantalla varias preguntas tipo test y según aquellas respuestas elegidas Wendy hallaría el nombre del árbol que tiene esas características.

Como única condición se tenía el no utilizar código demasiado avanzado, creando una aplicación funcional pero sin demasiado refinamiento técnico, en lenguaje C.

Planteamiento

Por un lado teníamos una serie de árboles… (pino, castaño, madroño…) y por otro lado, una serie de preguntas acerca de esos árboles. Por lo tanto, se deduce que un árbol va a tener ciertas propiedades, sobre las que formular las preguntas. Una forma propicia para albergar un conjunto de datos pertenecientes a una entidad o objeto, es una estructura. (Por las limitaciones de C, quedaba descartada la POO y el uso de objetos o clases). Definiendo…

typedef struct {
nombreArbol nombre; // Nombre del arbol

int familia; // Familia
int altura; // Altura del arbol
int porte; // Porte del arbol
int tipoHoja; // Tipo de hoja (per
int formaHoja; // Forma de la hoja…
int fruto; // Fruto que da
} arbol;

Nombre es otra estructura que a su vez define el nombre técnico y el nombre común del arbol.

Y.. ¿por qué todos los miembros de la estructura son enteros? El asunto era buscar una forma de relacionar el número de respuesta del usuario con los datos de cada arbol, sin tener que hacer infinitos if/else comprobando opción por opción y propiedad por propiedad. Así que, en la carga de datos del array de árboles disponibles (un array de la estructura arbol), metería en cada variable el número de opción correspondiente…

Imaginemos que tengo el árbol Pino, que tiene una altura entre 30 y 40 metros. En el programa, cuando se pregunte por la altura que tiene nuestro arbol a buscar, habrá varias opciones, una de ellas, la número 4, rezará “entre 30 y 40 metros“. En la variable altura del elemento del array en donde tengamos el Pino, meteremos en la fase de carga ese 4, que relacionará la respuesta con la propiedad del árbol. A la hora de buscar, sólo tendremos que comparar la opción elegida por el usuario con el valor de esa variable… y si es igual… (lo mismo se haría con todas las propiedades, y cuando un elemento tenga todas sus variables iguales a las que metió el usuario para cada propiedad.. habremos encontrado nuestro árbol).

Cargando Datos

Cuando arranca el programa, debemos cargar los datos de los árboles en un array de tipo arbol, en el que buscar una vez hayamos terminado de recoger datos por pantalla. Lo suyo hubiese sido algo refinado como un fichero xml… o un fichero binario… pero por crear algo simple, he utilizado un fichero de texto, donde sólo hay números. Cada línea del fichero corresponde a los datos de un árbol… y a través del sistema de númeración / relación de valores de las propiedades del árbol / opciones del test… el fichero tendría esta pinta..

0 0 0 4 1 1 1 1
0 0 0 4 2 1 1 1
1 1 1 3 2 1 2 2

En él vemos 3 árboles…. con sus propiedades. El primer número corresponde al nombre técnico, el segundo al nombre común, el tercero a la familia, el cuarto a la altura (numero de opción de la pregunta de test sobre la altura), el quinto al porte (número de opción de la pregunta de test sobre el porte) y así sucesivamente….

Con un bucle while hasta el final de fichero… leo los datos y los voy metiendo a cada elemento del array.

Nombres y Familias

Para crear un listado de los nombres de los árboles y sus familias, me creé tres arrays, que a través de funciones cargo con datos. (El índice de cada elemento hace referencia al valor de los miembros del array tipo arbol. Es decir, Si tenemos familias[0]=”familia1″, y el elemento arboles[4] pertenece a esa familia, en arboles[4].familia, tendremos un 0. (y así lo indicaremos en el fichero anterior).

Buscando

Con los datos cargados y con las respuestas del usuario guardadas en variables, sólo queda recorrer el array de árboles con un while, hasta que nos pasemos de rango o encontremos el árbol que reúne todos los requesitos. (Comparar en un if que cada variable es igual a cada miembro del elemento actual del array de árboles)


whatistc.com, upgraded!

December 26th, 2007

Cambio de versión! Tras mucho tiempo sin actualizar, la verdad es que el sitio estaba muy desatendido.. así que estos días he estado instalando y adaptando el wordpress, el script en el que se basa esta nueva versión de whatistc.com. ;) :)

Progresivamente intentaré subir los post antiguos más importantes, en especial los que hablan de programación / proyectos; de momento ya he subido algunos de ellos. También iré creando las páginas con las descargas de esos proyectos.. a ver si no me demoro mucho, que entre tanto lío…


Aprendiendo a programar: algoritmos básicos con arrays

February 27th, 2007

Definido el concepto de array, en este post se verán algunos algoritmos de las operaciones comunes sobre tablas, tales como inserción de un elemento, búsqueda, ordenación… El objetivo es generar una idea clara de cómo se trabaja con tablas, independientemente del lenguaje, por ello esta vez codificaré en pseudocódigo, teniendo en cuenta que:

- Llamaré N al número de elementos presentes en la tabla.

- Llamaré T al número máximo de elementos en la tabla, el declarado con la tabla. tabla(T) es tabla de…

- El rango irá de 1 a T, siendo tabla[1] el primer elemento y tabla[T] el último. (Si codificas en C, ten en cuenta que el índice de los arrays comienza en cero y no en uno)


Lectura y escritura

Como se vió en la primera parte, se puede hacer a un elemento de forma directa, indicando su indice, sin necesidad de recorrer toda la tabla. (tabla[indice]=4; ó variable=tabla[indice]).


Actualización del array

Cuando trabajemos con arrays, no siempre lo tendremos “completo”. Es decir, podemos tener un vector de 5 elementos en el que la mayor parte del tiempo sólo los elementos con índice 1, 2 y 3 tienen algo significativo. A lo largo del programa, puede darse el caso que prescindamos del tercer elemento o añadamos un dato al elemento con índice 4. Por ello, de algún modo debemos llevar cuenta del número de elementos que nos valen, almacenandolos en las primeras posiciones. Respecto al N comentado al principio del post, diremos que los elementos con datos significativos estarán en el rango 1-N. (tabla[1] primer elemento con dato significativo, tabla[N] último elemento con dato significativo). A medida que vayamos considerando elementos o despreciandolos, iremos actualizando el valor de N.


Adicción a continuación del último elemento

Insertaremos en el último lugar (N+1) si el array no está lleno.

Si N < T
tabla[n+1]=valor
N=N+1
Sino
Escribir “tabla llena”
Fin Si

Inserción en una posición P

En este caso, además de comprobar que la tabla no esta llena, moveremos todos los elementos desde P a N al elemento con índice siguiente, para dejar hueco en la posición P y así poder meter el nuevo valor sin perder ningún dato.

Si N < T
Para j de N a P con incremento -1
tabla[j+1]=tabla[j]
Fin Para
tabla[p]=valor
N=N+1
Sino
Escribir “tabla llena”
Fin Si.

También podríamos haberlo hecho con un bucle mientras en lugar de un para y de P a N en lugar de N a P, pero la filosofía seguiría siendo la misma. ;) :)


Borrado de un elemento situado en una posición P

En este caso dará lo mismo que el array esté lleno o no, pero no si está vacío. Tras comprobar esto, moveremos hacia la izquierda todos los elementos posteriores a la posición P.

Si N>0
Para j de P a N-1 con incremento 1
tabla[j]=tabla[j]+1
Fin Para
N=N-1
Sino
Escribir “tabla llena”
Fin Si

Búsqueda de un valor x y la posición que ocupa

Aquí debemos tener en cuenta varias cosillas. En primer lugar, consideramos que tenemos una tabla de enteros, ordenada de menor a mayor. La cosa sería

j=1;
Mientras tabla[j]<x y j<N
j=j+1
Fin Mientras
Si tabla[j]=x Escribir “encontrado x en la posicion j”
Sino Escribir “No encontrado”.

Si la tabla no estuviese ordenada, bastaría cambiar el menor por diferente, en la primera condición del mientras. (Mientras tabla[j]<>x y j<N). Otra forma de hacer esto es utilizar un interruptor: lo inicializamos a false, ponemos la condicion en el mientras de mientras interruptor sea igual a false, si en algún momento del bucle lo encuentra hacemos interruptor=true y fuera del bucle preguntamos por qué condición se ha salido. Pero de la forma mostrada queda más eficiente.

Si la tabla contiene valores repetidos, queremos mostrarlos todos y su posición, haremos algo como:

sw=false
Para j de 1 a N con incremento de 1
Si tabla[j]=x
Escribir “encontrado en posicion j”
sw=true;
Fin Si
Fin Para
Si sw=false
Escribir “No encontrado”
Fin Si

Otro método de búsqueda es la búsqueda binaria o dicotomía, válido sólamente para tablas ordenadas. Se comienza comparando el elemento central de la tabla y, si no es el valor buscado, en función de que sea menor o mayor que el elemento buscado, se coge la mitad inferior o superior y se procede de la misma forma. En tablas muy grandes, es una buena opción, debido a su eficiencia respecto a la búsqueda secuencial.

izq=1
der=N
c=(izq+der)/2
Mientras tabla[c]<>x y izq<der
Si tabla[c]> x entonces der=c-1
Sino izq=c+1
Fin Si
c=(izq+der)/2
Fin Mientras

Si tabla[c]=x entonces Escribir “encontrado en la posicion c”
Sino Escribir “No encontrado”
Fin Si

Observa que izq va estrechando el cerco por la izquierda o principio del array y la variable der, lo mismo, pero por la derecha o fin del array. Si te fijas en la segunda condición del mientras, paramos cuando izq y der se mezclan o superponen, o lo que es lo mismo, el cerco se convierte en cero. Dentro del bucle, indicamos la nueva zona del array en la que buscar y finalmente preguntamos si coincide la variable buscada. La esencia de este algoritmo, como puedes intuir, es recursiva. (Bastaría con ir pasando a la función la porción de la tabla a evaluar, siguiendo la misma filosofía. Cuando llegue a recursividad, lo retomaremos)