Cómo hice el simulador de proyectos
Un lienzo para armar la arquitectura de una app, esbozar sus pantallas y obtener una estimación referencial en vivo, hecho con SvelteKit y sin backend.
4 min de lectura
- SvelteKit
- UX
- Accesibilidad
En este artículo
La pregunta que más recibo antes de empezar un proyecto es «¿cuánto costaría?». La respuesta honesta es «depende», así que construí el simulador para mostrar de qué depende. Arrastras tecnologías a un lienzo, las conectas, armas una pseudo maqueta con bloques de interfaz y el presupuesto se recalcula al instante.
#Tres piezas: catálogo, cálculo y estado
Quería separar lo que cambia seguido (las cifras) de lo que casi no cambia (la lógica). Quedaron tres módulos:
catalog.ts: todas las cifras editables. Horas por tecnología y por componente, costo mensual de cada servicio, horas por tipo de conexión, tarifa por defecto y porcentajes de QA y gestión.estimate.ts: una función pura que recibe el estado y devuelve la estimación. Sin efectos, fácil de razonar.store.ts: el estado (nodos, conexiones, maqueta y ajustes) en un store de Svelte, con las acciones para modificarlo.
Cada pieza del catálogo es un objeto plano:
{
id: 'postgres',
name: 'PostgreSQL',
category: 'database',
hours: 16,
monthly: 15,
description: 'Base de datos relacional',
badge: 'Pg',
notes: ['Relacional y con transacciones: primera opción para la mayoría de las apps.']
}Si mañana cambian mis tarifas o descubro que algo toma más tiempo, edito un número y listo.
#Cómo se calcula
La estimación suma cuatro cosas:
- Tecnologías: las horas de cada pieza. Si repites una (dos backends iguales, por ejemplo), la segunda cuenta la mitad, porque se reutiliza configuración.
- Pantallas: cada bloque de la maqueta (login, carrito, panel…) tiene sus horas.
- Conexiones: unir dos piezas también es trabajo. Conectar un frontend con un backend suma el contrato de la API y los estados de carga; un backend con un servicio externo suma credenciales y webhooks.
- Lo que siempre se olvida: QA (20 %), gestión y reuniones (10 %) y la puesta en producción.
Todo se multiplica por la complejidad elegida (0,85 simple, 1 media, 1,35 alta) y el resultado se muestra como rango, no como una cifra exacta: de −15 % a +20 % por imprevistos. Un número único transmite una precisión que ninguna estimación tiene.
El plazo sale de dividir las horas por la capacidad semanal del equipo. Sumar personas ayuda, pero no de forma lineal: con dos personas la eficiencia baja al 90 %, con tres al 82 %, porque coordinarse también toma tiempo.
#Consideraciones, no solo números
Lo que más me gusta del simulador es que opina. La misma función que calcula revisa el conjunto y devuelve avisos:
- Si conectas el frontend directo a la base de datos, advierte que expone credenciales.
- Si la maqueta tiene login pero no hay servicio de autenticación, lo sugiere. Lo mismo con carrito sin pagos o subida de archivos sin almacenamiento.
- Si hay piezas sueltas, las nombra para que las conectes.
Son reglas simples, pero convierten una calculadora en una conversación sobre arquitectura.
#Arrastrar sin depender del ratón
El lienzo usa pointer events con setPointerCapture, así funciona igual con ratón, lápiz o dedo. Pero arrastrar no puede ser la única forma de usarlo:
- Cada pieza de la paleta tiene un botón + para agregarla sin arrastrar.
- Los nodos se mueven con las flechas del teclado y la tecla C inicia una conexión. También hay un selector «Conectar con…».
- En la maqueta, los botones ↑/↓ reordenan los bloques, además de arrastrarlos.
- Cada acción se anuncia en una región
aria-live, para que un lector de pantalla sepa qué pasó.
#Estado que sobrevive a recargar
La simulación se guarda en localStorage en cada cambio. Al cargarla, filtro las piezas que ya no existen en el catálogo y las conexiones que quedaron huérfanas: si renombro una tecnología, una simulación antigua no rompe la página. Todo va dentro de try/catch, porque en navegación privada el almacenamiento puede no estar disponible, y el simulador debe funcionar igual.
#La tarjeta para compartir
Al final agregué una forma de llevarse el resultado: una imagen con la estimación, el diagrama, la maqueta y los logos del stack, en formato Post (1080×1350) o Historia (1080×1920).
- La imagen se genera en el navegador con
html-to-imagea partir de un componente Svelte. La librería se carga conimport()solo cuando alguien abre la tarjeta, así no pesa en la carga inicial. - Los logos vienen de Simple Icons (se abre en una pestaña nueva) (licencia CC0).
- En el móvil se comparte con la Web Share API y la imagen adjunta, lo que abre Instagram, X o WhatsApp. En el computador, X solo acepta texto y enlace desde la web, así que se abre con el texto y la imagen se descarga.
Un detalle que me costó: Safari exige que
navigator.sharese llame dentro del gesto del usuario. Si genero la imagen después del clic, el menú no se abre. Por eso la imagen se genera apenas se abre la tarjeta y el botón solo la comparte.
#Lo que aprendí
Estimar es comunicar incertidumbre. Mostrar un rango, explicar de dónde sale cada hora y señalar los riesgos de la arquitectura genera más confianza que cualquier cifra redonda. Y separar los datos del cálculo hizo que ajustar el simulador sea editar un archivo, no reescribir código.