Es indudable que las Single Page Applications (SPA) están de moda y parece que han llegado para quedarse. La tendencia es evidente, podemos comprobar su presencia en la red fijándonos en las aplicaciones web más conocidas como Gmail, Outlook, Facebook o Twitter. Otro hecho significativo es la gran inversión que están haciendo las grandes empresas tecnológicas para desarrollar frameworks que permitan desarrollar aplicaciones SPA de una manera sencilla y eficaz. Los ejemplos más destacados son ReactJS o AngularJS desarrollados por Facebook y Google respectivamente.
Las aplicaciones web tradicionales se caracterizan por contener la lógica de negocio y la mayoría de la lógica de aplicación en el servidor. En contrapartida, las SPA mueven gran parte de ese código al cliente convirtiendo las aplicaciones web en soluciones “thick-client”.
Antes de entrar en materia debemos aclarar a qué nos referimos por lógica de la aplicación y lógica de negocio.
DEFINICIONES
La lógica de negocio la componen todas aquellas reglas de un sistema que cumplen un aspecto funcional. Por ejemplo, si estoy navegando en una tienda on-line y añado un nuevo producto a mi pedido, el total de éste debe incrementarse con el precio del producto.
Por lógica de aplicación nos referimos al código necesario en una aplicación para poder funcionar. Es decir, se encarga de aspectos técnicos del sistema. Por ejemplo, cuando accedemos a la ruta X queremos que se muestre la vista Y. O bien, cuando hacemos clic en este botón queremos desencadenar este otro proceso.
CÓMO ELEGIR DÓNDE COLOCAR EL CÓDIGO
Una vez que tenemos claros los conceptos toca decidir qué código ponemos en el lado cliente. Es decir, ¿qué código ponemos en el navegador y cuál en el servidor?
Es evidente que la mayoría de la lógica de aplicación recaerá en el lado cliente ya que es la que principalmente nutre y hace funcionar a una SPA. Pero, ¿dónde ponemos la lógica de negocio?
Es muy difícil contestar a una pregunta tan genérica. Ya se sabe que en esto del desarrollo de software, cada sistema es un mundo. Podemos decir que en aplicaciones pequeñas no críticas donde no es necesario disponer de un repositorio de datos en el servidor, es recomendable y aceptable poner la lógica de negocio en el cliente. Montar un servidor para únicamente procesar algunos datos puede tener un coste demasiado alto. Por otro lado, puede ser problemático tener lógica de negocio el cliente en aplicaciones donde hay una dependencia con un repositorio de datos central y se tratan datos sensibles.
Supongamos que tenemos un sistema con la típica arquitectura distribuida:
- Un servidor con un repositorio de datos
- Una aplicación SPA del lado cliente
Si moviéramos la lógica de negocio al cliente nos quedaríamos con el servidor actuando como un simple repositorio de datos. El cliente interactuaría con la interfaz del servidor para indicarle qué operaciones quiere realizar en el repositorio (léase base de datos u otro tipo de almacenamiento). Por lo tanto, básicamente estamos hablando de operaciones CRUD. A continuación analizaremos qué problemas podemos encontrar al poner la lógica de negocio en este sistema:
Consistencia
Una de las razones con más peso es la consistencia de los datos de una aplicación.
Supongamos que tenemos una aplicación para realizar pedidos y que tenemos a un usuario bondadoso realizando un pedido. Utilizando nuestra nueva arquitectura, el usuario creará un pedido en la interfaz de usuario y añadirá un par de productos. La aplicación hará algunas consultas al repositorio de datos utilizando la interfaz expuesta en el servidor y después de hacer unos cálculos (siempre en el cliente) determinará que el precio total del pedido son 20€. Al final, el usuario pagará 20€ por su pedido, le llegará a casa y todos contentos.
¿Qué pasa si en lugar de un usuario bondadoso tenemos a un usuario malintencionado que quiere engañarnos? Encima, el usuario maligno tiene base técnica y es capaz de interceptar y manipular las peticiones al servidor y devolver resultados falsos. Entonces, podría, por ejemplo, interceptar la petición para saber el precio del producto y hacer que la aplicación reciba la información del producto con un coste de 0€. O también interceptar la llamada para persistir el pedido final (calculado en el cliente) en el repositorio y modificar su precio final.
Entonces, si quisiéramos poner algún mecanismo para prevenir estos casos, deberíamos implementar la lógica de negocio de nuevo en el servidor para validar que todos los datos recibidos son consistentes con el estado actual de nuestro sistema.
Moraleja: No confíes en tus clientes, pueden mentir :O
Seguridad
Existen varios problemas de seguridad en este tipo de solución. Uno de ellos está relacionado con la autorización. Si tuviéramos lógica de negocio en el cliente que requiriera reglas de autorización, tendríamos una vulnerabilidad.
Veamos un ejemplo de regla de negocio con autorización: Supongamos que tenemos una aplicación para introducir gastos en una empresa. El trabajador introduce los gastos y estos son aprobados por el contable de la empresa. Si un usuario no es el contable, no debe poder aprobar ninguna hoja de gastos.
Si nos encontramos de nuevo con el usuario maligno, modificaría el código de la aplicación para cambiar esa condición y así poder aprobarse todos los gastos que quiera. ¡Menudo chollo!
Moraleja: No confíes en tus empleados, pueden mentir :O
Rendimiento
Aunque hay la creencia de que mover la lógica de negocio al cliente mejorará el rendimiento, la realidad puede ser otra. Normalmente cuando la lógica de negocio está en el servidor, al procesar una petición del cliente se realizan numerosas consultas al repositorio de datos, bien para tomar una decisión, bien para determinar el nuevo estado. Es decir, una petición de procesamiento al servidor puede traducirse en múltiples consultas a una base de datos.
En el caso de tener la lógica en el cliente, habría situaciones en las que el cliente debería hacer muchas peticiones al servidor para tomar una decisión. ¿Qué es mejor?
- Una petición asíncrona al servidor + múltiples consultas al repositorio de datos (Lógica en el servidor), o
- Múltiples peticiones asíncronas al servidor + múltiples consultas al repositorio de datos (Lógica en el cliente)
Por no hablar de las transacciones. Muchas operaciones necesitan ser transaccionales (véase ACID). Realizar múltiples operaciones en una única transacción directamente desde el cliente parece casi una utopía. Siguiendo con nuestro ejemplo de la tienda on-line, un caso representativo de esto último lo constituiría el pretender, en una única transacción, crear un pedido y reducir el inventario del Producto A.
Moraleja: No confíes en las teorías, pueden mentir :O
Centralizado = Reutilizable
Para exponer el último problema imaginemos esta situación: Somos una pequeña startup convencida (al menos el fundador y jefe así lo está) de que cuanto más código en el cliente mejor. Además somos conscientes de los problemas mencionados anteriormente (tenemos la suerte de que nuestro jefe lo sabe todo sobre SPAs). Por ello, aunque el desarrollo ha sido más largo, de alguna manera hemos solucionado los agujeros. ¡Genial! Así que, tal y como quería el CEO, hemos lanzado nuestra SPA con la lógica de negocio en el cliente.
La web funciona muy bien, y el número de usuarios comienza a multiplicarse. Muchos de ellos quieren poder acceder a nuestra aplicación a través de su móvil,...Cuidado que vienen curvas…Debemos desarrollar una aplicación para móvil, pero ¡nuestra lógica de negocio no se puede reutilizar! ¿Qué hacemos ahora? ¿Duplicar la lógica de negocio en una nueva aplicación? ¿Crear una app móvil escrita en JavaScript para minimizar el coste de desarrollo? Problemas a la vista.
Moraleja: No confíes en los jefes, pueden mentir :O
Al final deberás sacar tus propias conclusiones en función de tu situación particular. Esperamos que las situaciones aquí expuestas te ayuden a tener una mejor perspectiva.