domingo, 11 de agosto de 2013

Como hacer una WebApp y no perder la cabeza (Parte 2)

Esta es la segunda parte del tutorial, de como hacer una aplicación una WebApp sin perder la cabeza, hasta este punto el tutorial aplica para aplicaciones de escritorio, celular o cualquier otra plataforma, incluyendo esta parte. Ahora voy a tocar el tema de la base de datos, aunque es un tema tal vez considerado avanzado, realmente no lo es tanto. Un gran porcentaje de aplicaciones resalta la importancia de almacenar información; Whatsapp por ejemplo la información se almacena por partida doble, en sus servidores y en el celular, la tecnología HTML5 impulsa incluso una base de datos interna en el navegador "IndexedDB". Es algo ya inherente dentro de la concepción de un programa.

Seguramente habrás oído de SQL o si estas al tanto de la tecnología aplicada a base de datos NoSQL. SQL significa Lenguaje de Consulta Estructurado, mientras que NoSQL es No solo SQL, este ultimo se debe más a la componente de como se trabaja con las estructuras de las base de datos que veremos más adelante. Para entender un poco sobre como trabajar con base datos, si es bueno conocer sobre tecnología aplicada a ellos.

Bien SQL lleva mucho tiempo, seguramente (otra vez) habrás oído de MySQL, ese pequeño delfin que sale hasta en la sopa. Las bases de datos tienen dos componentes importantes como software, uno es el gestor, quien se encarga de trabajar con la información y otro es el almacenamiento. Saliendo de SQL siempre existen gestores de datas caseros, y muy sencillos y no por ello nada malos. Vamos a ver, tengo un celular con acelerometros y quiero registrar el movimiento de un tren... Aparte de la logística de como pegar el celular al tren. Mi aplicación del celular que toma los datos del acelerometro lo va a guardar en un archivo de textos, los valores de voltaje del acelerometro se separan por comas o puntos y comas. Si veo esa información me encontrare con esto:

#Data 10/04/2013
#t,V.X,V.Y,V.Z
0.000,2.430,2.530,5.010;
0.001,2.431,2.560,5.110;
0.002,2.429,2.510,5.030;
0.003,2.444,2.520,5.080;
...

Como ven la data fue almacenada de manera "bruta", no se compacto ni se copilo de otra manera que no fuera fácilmente visible. Esto es muy útil para datación científica pero el gestor de data la debemos muchas veces crear, y no es muy útil para casos donde la lógica de computo es mas relevante que la potencia de computo.

Con esta mera y corta presentación volvamos al papel. Ya respondimos "¿Qué?" y "¿Como?"... Pero ahora debemos tocar la escencia propia de las cosas con las que trabajamos... Estamos haciendo un catalogo, de equipos y sus piezas, de manera funcional.

Vamos al diccionario y encontramos que catálogo es según la RAE:
Relación ordenada en la que se incluyen o describen de forma individual libros, documentos, personas, objetos, etc., que están relacionados entre sí.
Mmm, esto ya te introduce un poco como diseñar la base de datos. Si tienes dudas, mira un catálogo de un fabricante:


Esto es una base de datos, sip, una simple y detallada base de datos de rodamientos, todo distribuido en filas y columnas. Las columnas son las características de la piezas,  y las filas las piezas propiamente. Esta misma pieza pertenece a una base de datos MUY larga, de todas piezas ciertos atributos de la pieza nos permite clarificarlos (esa lista es de rodamientos simples de bola y una sola hilera). Ahora bien vamos al detalle:

Voy a tener una muy larga lista de piezas, un equipo esta compuesto de varias piezas y una misma pieza (por ejemplo un tornillo) puede estar presente en varios equipos. esto es lo que llamamos una lista varias a varias. Esto se llama relaciones y es bueno aprender a usar:

Relación uno a uno: Se da cuando un elemento de la tabla A y un elemento de la tabla B mantienen una relación única, existente o no. Suponte que cada cliente de una tienda tenga un ID, y aparte tengas una base de datos de unas cuentas de créditos. No todos los clientes tiene una cuenta de credito pero si una cuenta de crédito tiene una y solo cliente.

Relación uno a varios: Se da cuando un elemento de la tabla B y varios elementos de la tabla C (o viceversa) mantienen una relación existente o no. Ahora plantea lo siguiente, la tabla B es la mencionada cuentas de créditos y la tabla C el de operaciones de crédito. Para cada B puede o no puede a haber uno más operaciones de crédito, pero cada operación de crédito guarda relación con una sola cuenta de crédito.

Relación varios a varios: Se da cuando varios elementos de la tabla C y varios elementos de la tabla D (o viceversa) mantienen una relación existente o no. Este caso es mas difícil de ver, en una operación de la tabla C puede haberse comprado varios productos de la tabla D, en caso contrario, varios productos de la tabla D pudieron haber sido comprado en varias operaciones de la tabla C.

Relación Auto-constitutiva: Muy pocas veces la oirás mencionar o ver de manera publica, es muy practica para vendedores de equipos tanto por piezas como conjuntos, de hecho me atrevo a decir que la empresa Doppelmayr lo implementa bastante. En este caso, la tabla D de productos se vincularía así misma. Un ejemplo más practico, has de cuentas que tienes una tienda que venden equipos al detalle, cuyas piezas únicamente sirve para un equipo especifico (una especie de relación un equipo a varias piezas) y un cliente te pide tanto el equipo como sus repuestos. Es una modalidad muy practica aunque requiere bases bien definidas. Permite definir relaciones de jerarquía indefinidas.

Relación Auto-constitutiva Mixta: Este mezcla la relación auto-constitutiva con la relación varias a varias, En la misma Tabla D un elemento de menor jerarquía esta vinculado a varios de mayor jerarquía. Vamos al caso de un tornillo, lo cual es una pieza seguramente presente en distintos equipos diferentes.

Estas dos ultimas son manejadas de manera natural en bases de datos NoSQL, son muy utilizadas para aplicaciones como Twitter. SQL por el nivel de confianza son implementadas los tres primeros tipos de relaciones e implementado las dos ultimas con algunas técnicas jugando con las tablas. Maneja muy bien estas estructuras pues es algo fundamental.

Ok volvamos atrás y empecemos a ver las relaciones del proyecto. Para la empresa a la que trabajo, los equipos se engloban dentro de un universo particular: Sistemas, Subsistemas, Equipos y Componentes, se añade una jerarquía más: Servicio pues se manejaran equipos de diferentes medios de transporte publico. Esto quedaría de la siguiente manera:

  • Cada componente puede estar en diferentes equipos y cada equipo tiene al menos uno o más componentes. (Relación Varios a Varios)
  • Cada equipo pertenece a un subsistema y un subsistema contiene varios equipos (Relación uno a Varios)
  • Cada subsistema pertenece a un sistema y un sistema contiene varios subsistemas (Relación uno a Varios).
  • Cada sistema pertenece a un servicio y un servicio esta compuesto de varios sistemas (Relación uno a Varios).
Un detalle técnico en base de datos, la relación de varios con varios "no existe", para establecer esta relación se usa una tabla de intercambio que lo explicaré más adelante (osea ya).

Una vez que tengas las relaciones, es necesario que definas la información contenida en cada lista, este proceso se denomina normalización de la información. Este punte es cumbre, pues indica el numero de columnas necesarios para ello, siempre existe la posibilidad agregar o quitar columnas (tarea que se va hacer) pero siempre se busca un formato definitivo pues la migración de un formato a otro de base de datos es una tarea bastante tediosa y aveces (casi siempre) se realiza item por item.

Repasando, propone que cada lista tenga una presentación de información básica (Nombre y Descripción), debes incluir una columna de dependencia en la tabla donde evocan varios item de una tabla primaria. Es decir "Cada sistema pertenece a un servicio" esto nos indica que SERVICIO no tiene dependencia pero SISTEMA si, entonces en SISTEMA debemos agregar una columna que relacione UN SERVICIO con los SISTEMAS. Si la relación es de varios a varios, se unen ambas tablas con una tabla de dependencia. esta relaciona en nuestro caso LOS EQUIPOS con LAS PARTES.

Ya que estamos MUY próximos a tocar el lenguaje SQL debes definir el tiempo de memoria que tiene ese recurso, por ejemplo, en todas nuestras tablas tendrá un nombre el cual es un texto corto, en ese caso le decimos como "Text" o bien "varchar(N)" donde N son los caracteres que usaras. Las imágenes generalmente no se cargan a una base de datos, pero si la imagen es pequeña existe lo que se llama blob (Objeto Binario de alta longitud). Esto ya es algo más avanzado pero deposita eso en tus ideas futuras.

Ok vamos a crear las tablas:


  • Servicio:
    • Nombre | varchar(255)
    • Descripción | text 
  • Sistema:
    • Nombre | varchar(255)
    • Descripción | text 
    • Servicio | ?
  • Subsistema:
    • Nombre | varchar(255)
    • Descripción | text 
    • Sistema | ?
  • Equipo:
    • Nombre | varchar(255)
    • Descripción | text 
    • Subsistema | ?
  • Componente:
    • Nombre | varchar(255)
    • Descripción | text 
  • Componentes en Equipos
    • Equipo | ?
    • Componente | ?
Listo, todo parece bien... mmm pero que pasara en el caso del sistema "Sistema de Control" que en piezas son totalmente distintos en los Cable Linear y de los Telefericos... Para evitar este rollo, generalmente evitas que una tabla solo tenga componentes de texto, necesitas un ID y ese ID aparte debe ser único en su propia tabla. Al ser un numero el tipo de memoria es int (integral). En las relaciones, esto se llama "Clave Foránea" 

  • Servicio:
    • ServicioID | int | Clave Primaria Única
    • Nombre | varchar(255)
    • Descripción | text 
  • Sistema:
    • SistemaID | int | Clave Primaria Única
    • Nombre | varchar(255)
    • Descripción | text 
    • ServicioID | int | Clave Foránea
  • Subsistema:
    • SubsistemaID | int | Clave Primaria Única
    • Nombre | varchar(255)
    • Descripción | text 
    • SistemaID | int | Clave Foránea
  • Equipo:
    • EquipoID | int | Clave Primaria Única
    • Nombre | varchar(255)
    • Descripción | text 
    • SubsistemaID | int | Clave Foránea
  • Componente:
    • ComponenteID | int | Clave Primaria Única
    • Nombre | varchar(255)
    • Descripción | text 
  • Componentes en Equipo:
    • EquipoID | int | Clave Foránea
    • ComponenteID | int | Clave Foránea
Ahora en el papel, y hoy lo presento de manera computarizada (en el trabajo ando full así que sorry) estas tablas las veras de la siguiente manera:




¿TIENES TU ESTRUCTURA DEFINIDA?
SI
¿TIENES TUS TABLAS DEFINIDA?
SI
¿TIENES TUS RELACIONES DEFINIDAS?
SI
¿¡ESTAS LISTO!?
SI

¡¡¡MANOS A LA OBRA CON SQL!!!

Vas a necesitar descargar un servidor SQL, las opciones son MySQL o MariaDB, entre otros. Recomiendo SQLite, es simple y ligero y muy funcional. Descarga SQLite o si estas desde Ubuntu:
sudo apt-get install sqlite3
Otra opción si no quieres llenar tu PC de aplicaciones, te recomiendo abrir una cuenta en Cloud9 donde tendrás acceso hasta una terminal con acceso a SQLite y PHP 5.4. No esta adaptado como servicio comercial pero es una buena herramienta para empezar.


Desde la terminal puedes operar SQLite3 igual que lo hicieras desde la terminal de la PC. SQLite, crea base de datos contenido en un archivo. Para empezar necesitamos que SQLite cree el archivo y a su vez lo opere:
sqlite3 basededatos.sqlite
El archivo "basededatos.sqlite" es el archivo de base de datos, puedes llamarlo "basededatos.db" como nombre alternativo. El nombre no es de importancia, pero a hora veras que el terminal cambia un poco y se presenta como:
sqlite>
Este es el entorno de trabajo. Seguramente solo por esta vez usaras el terminal, ya que puedes crear las base de datos y las tablas desde PHP. Pero este entorno es muy util cuando se trabaja un proyecto a largo plazo, donde crear las tablas y las relaciones son más importante que la redistribución de tu programa. Un webmaster que al mismo tiempo se encargue del computo juega más con PHP y SQL que sobre una plataforma de administración como los hay en los sistemas de gestión de contenidos.

Vamos a crear la tabla servicios, esta debe tener tres columnas: servicio_ID (PRIMARY KEY), servicio_name (varchar(255)) y servicio_desc (text). Volvemos a sqlite y lo escribimos así:
CREATE TABLE servicios (servicio_ID INTEGER PRIMARY KEY, servicio name VARCHAR(255), servicio_desc TEXT);

En el ejemplo el comando para crear una tabla es "CREATE TABLE", no es necesario que lo pongas en mayúsculas, pero es una manera de no perderse, el interprete de comando de SQL considera que la instrucción termina cuando se termina la expresión en punto y coma. Por lo que puedes trabajar en varias lineas si te resulta más cómodo:
CREATE TABLE servicios (
servicio_ID INTEGER PRIMARY KEY,
servicio_name VARCHAR(255),
servicio_desc TEXT);
Dentro de la tabla sistema definimos la columna entre paréntesis, como indicamos antes, aparecen las tres columnas. INTEGER es el tipo de memoria que vamos a usar, PRIMARY KEY nos dice que es la columna donde están los valores primarios o de referencia dentro de sus sistema, VARCHAR(255) indica un longitud de caracteres igual a 255 y TEXT es similar a VARCHAR pero no se le indica la longitud al texto.

Ahora vamos a ver la tabla de sistemas:
CREATE TABLE sistemas (
sistema_ID INTEGER PRIMARY KEY,
sistema_name VARCHAR(255),
sistema_desc TEXT,
servicio_ID INTEGER,
FOREIGN KEY (servicio_ID) REFERENCES servicios(servicio_ID));
FOREIGN KEY es la relación presente entre la tabla con otra, en este caso "servicio_ID" es el vinculo de la tabla sistemas, con la tabla servicios mediante el "servicio_ID" de esa tabla. Para las demás tablas se realiza de la siguiente manera:
CREATE TABLE subsistemas (
subsistema_ID INTEGER PRIMARY KEY,
subsistema_name VARCHAR(255),
subsistema_desc TEXT,
sistema_ID INTEGER,
FOREIGN KEY (sistema_ID) REFERENCES sistemas(sistema_ID));
CREATE TABLE equipos (
equipo_ID INTEGER PRIMARY KEY,
equipo_name VARCHAR(255),
equipo_desc TEXT,
subsistema_ID INTEGER,
FOREIGN KEY (subsistema_ID) REFERENCES subsistemas(subsistema_ID));
CREATE TABLE partes (
parte_ID INTEGER PRIMARY KEY,
parte_name VARCHAR(255),
parte_desc TEXT);
Ahora solo falta la tabla que relacione "equipos" con "partes":
CREATE TABLE partes_en_equipos (
equipo_ID INTEGER,
parte_ID INTEGER,
FOREIGN KEY (equipo_ID) REFERENCES subsistemas(subsistema_ID),
FOREIGN KEY (parte_ID) REFERENCES subsistemas(subsistema_ID));

De esta manera tenemos la base de datos funcional para el proyecto y el final de este post. Más adelante haré un énfasis en SQLite. La parte 3 tocará como hacer una script en PHP para agregar partes de equipos.

NOTA: NO TEMAS EQUIVOCARTE, practica, practica y practica... solo así se aprende.