featured image

Cuando programaba en VisualBasic usaba un elemento de tabla que conectaba a la base de datos y presentaba los datos, pero si quería mostrar los datos de otra forma tenía que crear todo el elemento desde cero yo mismo, ¿por qué no había posibilidad de usar bloques de construcción?

Al igual que con Visual Basic, esta experiencia me ha sucedido con muchos frameworks, librerías y herramientas. Una función que da todo lo que necesitas, hasta que necesitas una personalización y entonces, no, esa función no permite configuración ni composición.

Pero hay otros sistemas que sí están pensados y creados a base de composición de pequeños elementos y cuando necesitas ir al detalle, entonces puedes dejar de usar la función general y emplear la composición de bloques que esa misma función usa para implementar la solución o la función tal y como la necesitas.

Un ejemplo claro es la forma en que los formularios están creados en Django. Cuando creas un formulario, el código a nivel de plantilla es tan fácil como hacer:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Send</button>
</form>

Este formulario está a muy alto nivel, nos permite una configuración básica de la etiqueta de formulario pero agrega todo el contenido a través de un generador, la función as_p. Además, tenemos otros generadores como as_div pero, ¿qué sucede si necesitamos una salida de formulario empleando un framework específico como Tailwind, Bootstrap, Bulma o cualquier otro?

En este caso, form está pensado para poder tratar cada elemento interno de forma independiente, por lo que podemos crear entradas como la siguiente:

{{ form.non_field_errors }}
<div class="field">
    {{ form.first_name.errors }}
    {{ form.first_name.label_tag }}
    {{ form.first_name }}
</div>
...

Como vemos, form contiene cada uno de los subelementos y pueden emplearse para obtener los errores, el ID para la etiqueta o usado tal cual para hacer la salida del input, select o textarea correspondientes. También podemos cambiar la implementación por defecto por una personalizada:

{{ form.non_field_errors }}
<div class="field">
    {{ form.first_name.errors }}
    <label for="{{ form.first_name.id_for_label }}">First name:</label>
    {{ form.first_name }}
</div>
...

Podemos ir a otro nivel más al detalle si queremos poner nosotros mismos el input, select o textarea de modo que podemos usar la información del id, value y name.

A eso me refiero cuando digo que un sistema está construido por composición y empleando bloques que podemos emplear independientemente según nuestras necesidades.

Bloques en Telco

Una vez tras otra siempre acabo trabajando en empresas de telecomunicaciones y estas empresas, aún empleando protocolos por capas tienden a desarrollar soluciones excesivamente acopladas. Es decir, aplicaciones que toman la transmisión al nivel más alto que sus equipos las proveen (p.ej. SMPP, SIP, RTP, XMPP, HTTP), las pasan a la lógica de su aplicación y generan la respuesta. Todo de forma conjunta y acoplada.

¿Cuál es el problema? Normalmente es muy común que un proveedor trabaje con una forma de hacer la transmisión vía SIP, su propia implementación para enviar mensajes ya sea usando HTTP, SMPP o cualquier otro protocolo que le venga bien y sin embargo, la lógica de transmisión de la información sigue ligada al protocolo, por lo que hay que replicarla para cada protocolo.

Además, la forma específica de implementar la comunicación, por ejemplo HTTP, no es reusable entre unos y otros. Algunos emplean HTTP REST con JSON, otros dicen usar REST, otros emplean XML y lejos de implementar cada una de estos elementos como bloques que puedan componer la solución final, se implementa todo a base de librerías donde la única base es la que provee la librería genérica de HTTP, JSON, XML y otras.

Lo ideal sería crear bloques. Es decir, cada vertical y en este caso las operadores de telecomunicaciones, trabajan siempre de la misma forma. El trabajo consisten en obtener una solicitud para realizar una llamada o una petición para enviar un mensaje. A alto nivel lo podemos definir así y si hacemos una implementación de arriba a abajo caeremos en la trampa de acoplar los elementos para crear únicamente el código de tomar la entrada, transformar y realizar la salida.

Sin embargo, si empezamos la implementación de abajo a arriba pronto vemos muchas más ramificaciones o puntos de inicio. Dependiendo del sistema específico para realizar llamadas podemos realizar la abstracción a un formato específico y general que nos permita tratar las llamadas independientemente de cómo se hagan en el sistema de señalización. Este es un método implementado por muchos sistemas como Asterisk o FreeSwitch y ha probado ser muy útil para gestionar de forma abstracta llamadas con protocolos diferentes.

Por otro lado, los mensajes pueden llegar y normalizar los datos de entrada independientemente de si llegaron por XMPP, SMPP o HTTP. Incluso a bajo nivel el bloque de HTTP puede unificar la forma de trabajar de varios sistemas normalizando los datos recibidos o acomodando los datos normalizados para construir una salida. Cada bloque quedaría como una caja negra donde reciben una entrada estándar.

Principio de Intercambio de Liskov

Finalmente y como los principios SOLID establecen, a través de el Principio de Intercambio de Liskov, la idea es desarrollar un elemento que permita ser intercambiado por otro que realice una tarea similar o igual a alto nivel pero que disponga de una implementación diferente para no tener que reescribir la lógica de negocio una y otra vez.

Pero esto puede aplicarse incluso a las reglas que constituyen la lógica de negocio. Si vemos que el flujo de información es siempre lineal, en la entrada se transforma para que pueda ser transformado por la lógica de negocio y esta genera una salida que puede ser tratada por el sistema que se encarga de generar el envío de la información.

Si la lógica de negocio está construida por bloques que permiten incrustar en cualquier punto un bloque de seguridad para una lista de bloqueo, una transformación necesaria para los datos de contabilidad o simplemente obtener información para auditar.

Esto transforma el desarrollo de un sistema en un conjunto de bloques que pueden ir conectándose a lo largo del flujo de información y no es nada nuevo, ¿te suena el Enterprise Service Bus?

Arquitectura Orientada a Servicios (SOA)

Fue en 2012 cuando comencé a hablar en este blog sobre SOA mostrando una forma de poder implementar este sistema sobre un sistema de comunicación XMPP y también en 2013 para mostrar un artículo donde se exponía el uso de XMPP para IoT y SOA. En estos artículos me centraba únicamente en el sistema para conectar estos bloques pero no comenté la construcción de estos bloques en sí.

A lo largo de este artículo creo que he dejado clara la idea que tengo sobre los bloques. Eso sí, dejo aquí la reflexión porque es el inicio de una idea que tengo para intentar crear un sistema, lenguaje o programa que permita definir bloques que definan una interfaz concreta de entrada(s), salida(s) y realicen una transformación en esos datos o una operación con efectos colaterales (p.ej. almacenar en base de datos o enviar un email) Si te interesa la idea, no dudes en contactarme.