Posts Tagged ‘phonegap’


En la semana he recibido un par de consultas que me parecen super importantes y que trataré de responder en un par de post y de pasada repasar los fundamentos.

La segunda pregunta que recibí creo que es mejor tratarla primero: ¿Ionic con PouchDB y Cloudant es más rápido que usar MySQL y websql? Veamos, desde mi punto de vista por más que parece lo mismo, no lo son.

Antes debemos revisar un par de puntos:

Primero, PouchDB es además una capa de abstracción de datos porque puede utilizar varios tipos de archivos para almacenar los datos (Adaptadores), principalmente puede usar IndexedDB, WebSQL y otros menos usados. La recomendación es que le indiquemos a PouchDB que utilice WebSQL si queremos que sea más rápido. En alguna eventualidad, PouchDB nos libra del problema pues puede elegir automáticamente cual es el mejor almacenamiento para nuestros datos.

Segundo, WebSQL, sqlite o como lo quieran llamar, es un estándar que ya está “depreciado”. El consorcio que maneja los estándares de Internet ya ha fijado que IndexedDB sea el estándar. Los navegadores siguen teniendo soporte para WebSQL pero no se sabe exactamente hasta cuando, mas bien IndexedDB es una obligación para todos.

Ahora comparemos:

PouchDB y Cloudant (o CouchDB en general) es realmente una solución de gestión de datos de extremo a extremo que parte del concepto denominado “offline first” donde la aplicación cliente, luego de una sincronización inicial, está preparada para trabajar sin conectarse al Servidor. Incluso, hay otro movimiento más radical denominada “No Backend”, pero no lleguemos a extremos, de alguna manera la base de datos es el backend y, si fuera necesario, se puede colocar una capa de lógica intermedia. Para resumir, PouchDB – CouchDB incluye, gestión de datos, sincronización y segmentación de datos. Un aspecto adicional es que, dado que no hay esquemas, es necesario “transformar” los datos del modelo relacional para que cuadre en el modelo “documental” de CouchDB y para esto pensaremos en la estructura que mejor nos acomode en la aplicación cliente lo que significa que vamos a “limpiar” el modelo para tener solamente lo que nos interesa.

MySQL y WebSQL (o sqlite para los amigos) es en el sentido estricto solamente un gestor de datos. Pasar datos desde MySQL a la base local en WebSQL es algo que tenemos que hacer nosotros, al igual de la segmentación de datos. Además, dado que en sqlite tenemos tablas y un dialecto de SQL, nuestra primera tentación será la de repetir el modelo de datos que tenemos en el backend.

Entonces, para comparar papas con papas, hablemos del aspecto de gestión de datos solamente de ambas soluciones. La verdad dura y simple es que consultar datos con sqlite es más rápido que consultar datos con PouchDB. Hay un documento que explica el rendimiento comparado de las bases de datos en el lado del cliente que pueden consultar Comparación datos móviles

Ahora bien, esto no me parece determinante porque, dependiendo del modelo de datos que tengamos, es muy probable que con el modelo relacional de sqlite tengamos que hacer más consultas que con PouchDB. Esto no tengo como sustentarlo en números, pero en los proyectos que he realizado es algo evidente que si modelas bien, consultas menos y dado que en un “Documento” de CouchDB puedes organizar los datos en más de 1 nivel, puedes traer más datos en una sola consulta.

Otro punto importante es la cantidad de datos. Mientras más datos tengas, será más claro el tema de la velocidad. En mi caso, tengo apps donde guardo mas de 300 documentos en el móvil y la velocidad es aceptable. Debemos considerar que los documentos no son tan simples, incluso la gran mayoría contiene BLOBs de 20K en promedio de tamaño con un tamaño total de 12 MB de la base de datos, lo que sería una locura en un entorno sqlite. Si el volumen de datos que vas a manejar es menor a mi ejemplo, entonces la diferencia de performance no la vas a sentir.

Guardo el tema de índices para el final porque es muy importante. Con Sqlite podemos crear índices donde y cuando nos dé la gana lo cual casi no tiene costo en procesamiento ni en almacenamiento. En el caso de PouchDB, los índices no se hacen por nada: Existe un índice por defecto que solamente contiene el campo _id de todos los documentos en la base de datos, y como no hay tablas pues estamos hablamos de absolutamente todos los registros. Suena a limitación, pero significa que recuperar un registro es super mega extra rápido y recuerden que un registro puede tener mucha información que en Sqlite podría tomar más de una consulta, además, si usamos el ID correcto nuestras consultas pueden beneficiarse de este super índice: la clave es crear los IDs manualmente incluyendo los criterios de búsqueda que necesitemos. Por ejemplo, si queremos guardar un documento para el Comic 1 de la editorial DC que salió en 01 de febrero del 2015, el ID que nos convendría sería com_dc_2015-02-01_01, de esta manera podremos hacer consultas muy rápidas con el método allDocs de PouchDB:

– Todos los comics: startkey: ‘com_’, endkey: ‘com_\uffff’;

– Todos los comics de la editorial DC: startkey: ‘com_dc_’, endkey:’com_dc_\uffff’

– Todos los comics de DC que salieron el 2015: startkey: ‘com_dc_2015_’, endkey: ‘com_dc_2015_\uffff’

La mala palabra en PouchDB es ‘Joins’ al estilo sql. No existe, así de simple, pero no desesperen pues existen muy buenas alternativas. Aquí van dos: Podemos crear vistas que son parecidas a las del mundo relacional pero que siguen el modelo Map/Reduce que es lo mejor en lo referido a escalabilidad, igual la recomendación es usarla solamente en condiciones extremas tal como se explica en este artículo. La segunda opción se llama Mango y es una forma de indexar toda la base de datos de la forma que nos de la gana y podrán encontrar información aquí.

Finalmente, y creo que es la razón definitiva por la cual se debería usar el modelo con PouchDB, es que tenemos que valorar que estamos usando una solución completa para el manejo de datos, no es solamente un modo de tener una base local, es una solución de sincronización. En un modelo Sqlite, la sincronización es un proceso que tiene que ocurrir de modo secuencial, es decir: ingresas datos, modificas datos, parar para sincronizar, lees datos, modificas datos. Con PouchDB, la sincronización es un proceso que se ejecuta en una tarea paralela, por lo que podremos ingresar, leer, modificar datos sin parar.

Si realmente necesitan velocidad, Sqlite no va a estar en el vecindario por mucho tiempo, así que mi recomendación está en mejorar el modelo.


Este post lo hago de urgencia pues acabo de experimentar todo lo que no se debe hacer en el tema de sincronización. Para esto les doy un resumen de mi entorno de desarrollo:

  • Servidor: Instancia en Cloudant.com
  • Cliente: PouchDB como base de datos con sincronización al iniciar el app
  • Framework: Ionic

En resumen, se inicia una sincronización entre mi base de datos local en PouchDB y la base remota en Cloudant. Y puede ser todo lindo en Producción, pero como estamos en Desarrollo, el proceso normal es parar e iniciar el app a cada rato. Ahora veamos las consecuencias en desarrollo:

  • Costo: Cloudant te cobra por transacciones y te dice que por transacciones “pesadas” te va a cobrar mas, y pone varias transacciones HTTP y las define como pesadas. Lo que no dice es que hay otras transacciones que se utilizan para la sincronización que también se califican como pesadas, principalmente OPTIONS que se manda a cada rato. Por lo tanto, cada sincronización es bastante intensiva en costo.
  • Tráfico: Para un modelo de desarrollo, no es bueno iniciar conexiones de datos muy seguido. Entonces, el modelo debe saber cuando es bueno iniciar la sincronización sin importar que sea en Desarrollo o Producción.
  • Batería: Como consecuencia de la reducción de tráfico, estaremos también bajando el consumo de energía en el móvil.

No malentiendan, CouchDB/PouchDB es muy bueno, y si existe la necesidad, podemos activar la sincronización “live”, pero como no todos tenemos servidores y ancho de banda de sobra, tenemos que pensar en servicios en demanda en la red, como Cloudant en mi caso. Tengan en cuenta que otros servicios como IrisCouch, también cobran por transacciones.

La salida que encontré depende de como se necesita que fluyan los datos:

  • El recolector de datos: si nuestra app necesita solamente capturar datos y no necesito bajar información desde el servidor. En este caso, lo mejor es implementar un contador que incrementaremos cada vez que se actualice o se inserte un dato nuevo. Lo bueno es que para un entorno NoSQL, insertar o actualizar es el mismo método, así que en ese método podremos insertar el incremento del contador. Luego, al momento antes de sincronizar, verificaremos si es que el contador es mayor a 0, de lo contrario no iniciaremos la sincronización. Sincronizar solamente cuando hayan datos locales.
  • El visualizador de datos: Aquí es totalmente al revés, el app jala información del servidor. En este caso, la primera alternativa es la de fijar un tiempo de sincronización relativamente alto, agregar un visor de la última fecha de sincronización y la opción para forzar la sincronización manualmente.
  • Finalmente, como siempre, en la vida real tendremos una combinación de necesidades, así que la recomendación final es la de utilizar un proceso de sincronizacion para descargar datos y otro para subir datos.

Hay una función que no he mencionado aún: Sincronización filtrada. Esto es super útil y lo voy a desarrollar en otro Post, Básicamente es la de descargar solamente la información que me interesa. Esto es tan importante que todos deben usarlo si es que tenemos que descargar datos.

En conclusión, es muy fácil sincronizar sin límites, pero en la vida real, no hay que pedir más de lo que debemos consumir.





%d bloggers like this: