Estamos construyendo infraestructura que casi nunca debe fallar. Para lograrlo, nos movemos rápidamente mientras lanzamos software de calidad increíble sin atajos ni compromisos. Este documento describe los estándares de ingeniería que nos guiarán hasta 2026 y más allá.
Estructura del Equipo
Nuestra organización de ingeniería consta de cinco equipos principales, cada uno con responsabilidades distintas:
Equipo de Fundación: Se enfoca en establecer y mantener estándares de codificación y patrones arquitectónicos. Este equipo trabaja de manera colaborativa con otros equipos para establecer las mejores prácticas a lo largo de la organización.
Equipos de Consumidor, Empresa y Plataforma: Equipos enfocados en el producto que lanzan características rápidamente mientras mantienen los estándares de calidad establecidos en este documento. Estos equipos demuestran que la velocidad y la calidad no son mutuamente excluyentes.
Equipo de Comunidad: Responsable de revisar rápidamente los PRs de la comunidad de código libre, proporcionar retroalimentación y guiar ese trabajo hasta la fusión. Este equipo se asegura de que nuestros colaboradores de código libre tengan una gran experiencia y de que sus contribuciones cumplan con nuestros estándares de calidad.
Nuestros Resultados Hasta Ahora
Los datos hablan por sí mismos. En el último año y medio, hemos transformado fundamentalmente cómo construimos software:

Hemos duplicado aproximadamente nuestro rendimiento de ingeniería mientras mejoramos simultáneamente la calidad. Aún más impresionante es el cambio en lo que estamos construyendo:

Hemos reasignado con éxito aproximadamente el 20% del esfuerzo de ingeniería de solucionarse problemas hacia características, mejoras de rendimiento, refactorizaciones y tareas. Este cambio demuestra que invertir en calidad y arquitectura no te ralentiza. Te acelera.
La Fundación de Cal.com Permite la Excelencia para coss.com
Cal.com es un negocio estable y rentable que continuaremos haciendo crecer.
Este éxito nos da una ventaja única mientras construimos coss.com. A diferencia de los primeros días de Cal.com, donde necesitábamos movernos rápidamente para establecer un ajuste producto-mercado y construir un negocio sostenible, coss.com comienza desde una posición de fuerza.
No necesitamos apresurar coss.com.
La estabilidad de Cal.com significa que podemos permitirnos construir coss.com de la manera correcta desde el primer día. Tenemos el lujo de implementar estos estándares de ingeniería sin la presión de las demandas inmediatas del mercado o restricciones de financiación. Esta es una posición de inicio fundamentalmente diferente.
La "lentitud" es una inversión, no un costo.
Sí, seguir estos estándares puede parecer más lento inicialmente e incluso puede ser frustrante para algunos ingenieros. Escribir DTOs lleva más tiempo que pasar tipos de base de datos directamente al frontend. Crear abstracciones adecuadas e inyección de dependencias requiere más diseño inicial. Mantener una cobertura de pruebas de más del 80% para el nuevo código requiere disciplina. Pero esta aparente lentitud es temporal y el beneficio es exponencial.
Considera los rendimientos compuestos...
El código que está arquitectado correctamente desde el principio no necesita grandes refactorizaciones más adelante
El alta cobertura de pruebas previene errores que de otro modo consumirían semanas de depuración y correcciones rápidas (ver 2023 a mediados de 2024)
Las abstracciones adecuadas hacen que agregar nuevas características sea mucho más rápido con el tiempo
Los límites claros y los DTOs prevenen la erosión arquitectónica que eventualmente exige reescrituras completas
La trayectoria de Cal.com muestra lo que ocurre cuando optimizas para la velocidad inmediata. Alta velocidad inicial que gradualmente se degrada a medida que la deuda técnica se acumula, los atajos arquitectónicos crean cuellos de botella y más tiempo se dedica a solucionar problemas que a construir características (ver gráfico anterior donde estábamos dedicando el 55-60% del esfuerzo de ingeniería a arreglos).
La trayectoria de coss.com abrazará el poder de construir correctamente desde el primer día. Velocidad inicial ligeramente más lenta mientras se establecen los patrones adecuados, seguida de una aceleración exponencial a medida que estos patrones dan dividendos y permiten un desarrollo más rápido con mayor confianza.
Principios Fundamentales
1. No diferir la calidad
Minimizaremos "Lo haré en un PR de seguimiento" para pequeñas refactorizaciones.
Los PRs de seguimiento para mejoras menores rara vez se materializan. En cambio, se acumulan como deuda técnica que nos agobia meses o años después. Si se puede hacer una pequeña refactorización ahora, hazlo ahora. Los seguimientos deben reservarse para cambios importantes que genuinamente justifiquen PRs separados o para casos excepcionales y urgentes.
2. Altos estándares en la revisión de código
No dejes pasar PRs con muchos detalles solo para evitar ser "la persona mala".
Esto es precisamente como se vuelven descuidados los bases de código con el tiempo. La revisión de código no se trata de ser amable. Se trata de mantener los estándares de calidad que demanda nuestra infraestructura. Cada detalle importa. Cada violación de patrón importa. Abórdalos antes de hacer la fusión, no después.
3. Empujarnos mutuamente a hacer lo correcto
Nos responsabilizamos mutuamente por la calidad
Tomar atajos podría parecer más rápido en el momento, pero crea problemas que ralentizan a todos más adelante. Cuando veas a un compañero de equipo a punto de fusionar un PR con problemas evidentes, habla. Cuando alguien sugiera un hack rápido en lugar de la solución adecuada, opónte. Cuando tengas la tentación de omitir pruebas o ignorar patrones arquitectónicos, espera que tus compañeros te desafíen.
Esto no se trata de ser difícil o ralentizar a las personas
Se trata de propiedad colectiva de nuestro base de código y nuestra reputación. Cada atajo que toma una persona se convierte en problema de todos. Cada esquina cortada hoy significa más sesiones de depuración, más correcciones rápidas y más clientes frustrados mañana.
Hacer que sea normal desafiar decisiones pobres, respetuosamente
Si alguien dice "simplemente codifiquemos esto por ahora", la respuesta esperada debe ser "¿qué se necesitaría para hacerlo bien la primera vez?". Si alguien quiere comprometer código que no ha sido probado, el equipo debe oponerse. Si alguien sugiere copiar y pegar en lugar de crear una abstracción adecuada, resáltalo respetuosamente.
Estamos construyendo algo que casi nunca debe fallar
Esa nivel de fiabilidad no ocurre por accidente. Ocurre cuando cada ingeniero se siente responsable de la calidad, no solo del propio código sino del sistema completo. Triunfamos como equipo o fallamos como equipo.
4. Apuntar a la simplicidad
Priorizar la claridad sobre la astucia
El objetivo es código fácil de leer y entender rápidamente, no complejidad elegante. Los sistemas simples reducen la carga cognitiva para cada ingeniero.
Hacerte las preguntas correctas
¿Estoy realmente resolviendo el problema en cuestión?
¿Estoy pensando demasiado en posibles casos de uso futuros?
¿He considerado al menos 1 otra alternativa para resolver esto? ¿Cómo se compara?
Simplicidad no significa carencia de características
Solo porque nuestro objetivo es crear sistemas simples, esto no significa que deban sentirse anémicos y carentes de funcionalidades obvias.
5. Automatizar todo
Aprovechar la IA
Generar el 80% de código de plantilla y no crítico utilizando IA, permitiéndonos centrarnos únicamente en lógica empresarial compleja y arquitecturas críticas.
Construir manejo de errores inteligentes y alertas sin ruido.
Las pruebas manuales son cada vez más obsoletas. La IA puede construir rápidamente y de manera inteligente mega suites de pruebas para nosotros.
Nuestro CI es el jefe final
Todo en este documento de estándares se verifica antes de que el código sea fusionado en PRs
No hay sorpresas que lleguen a la rama principal
Las comprobaciones son rápidas y útiles
Estándares Arquitectónicos
Estamos en transición hacia un modelo arquitectónico estricto basado en Arquitectura de Corte Vertical y Diseño Orientado al Dominio (DDD). Los siguientes patrones y principios se aplicarán rigurosamente en las revisiones de PR y mediante linters.
Arquitectura de Corte Vertical: paquetes/características
Nuestra base de código está organizada por dominio, no por capa técnica. El directorio packages/features es el corazón de este enfoque arquitectónico. Cada carpeta dentro representa un corte vertical completo de la aplicación, impulsado por el dominio que toca.
Estructura:
Cada carpeta de características es un corte vertical autónomo que incluye todo lo necesario para ese dominio:
Lógica de dominio: Las reglas de negocio y entidades principales específicas de esa característica
Servicios de aplicación: Orquestación de casos de uso para ese dominio
Repositorios: Acceso a datos específicos para las necesidades de esa característica
DTOs: Objetos de transferencia de datos para cruzar límites
Componentes UI: Componentes frontend relacionados con esta característica (donde sea aplicable)
Pruebas: Pruebas de unidad, integración y E2E para esta característica
Por Qué Importan los Cortes Verticales
La arquitectura en capas tradicional se organiza por preocupaciones técnicas:
Esto crea varios problemas:
Los cambios en una característica requieren tocar archivos dispersos en múltiples directorios
Es difícil entender lo que hace una característica porque su código está fragmentado
Los equipos se pisan los pies cuando trabajan en diferentes características
No puedes extraer o desaprobar fácilmente una característica
La arquitectura de corte vertical se organiza por dominio:
Esto soluciona estos problemas:
Todo lo relacionado con la disponibilidad vive en
packages/features/availabilityPuedes entender toda la característica de disponibilidad explorando un solo directorio
Los equipos pueden trabajar en diferentes características sin conflictos (si el equipo de ingeniería de Cal.com crece, pero ciertamente en coss.com tendremos equipos que asuman paquetes importantes)
Las características están poco acopladas y pueden evolucionar de forma independiente
Guías para la Organización de Características
En teoría, cada característica es independientemente desplegable. Aunque quizás no las despleguemos por separado, organizarlas de esta manera nos obliga a mantener claros los dependencias y el acoplamiento mínimo. Esta es la premisa y el éxito de los micro-servicios, aunque aún no desplegaremos micro-servicios.
Las características se comunican a través de interfaces bien definidas. Si bookings necesita datos de availability, los importa desde @calcom/features/availability a través de las interfaces exportadas, no accediendo a detalles de implementación internos.
El código compartido vive en los lugares apropiados:
Utilidades agnósticas de dominio e inquietudes transversales (auth, logging):
packages/libPrimitivos UI compartidos:
packages/ui(y próximamente coss.com ui)
Los límites de dominio se aplican automáticamente. Construiremos linting que prevenga acceder a los internos de las características donde no deberías estar permitido. Si packages/features/bookings intenta importar desde packages/features/availability/services/internal, el linter lo bloqueará. Todas las dependencias inter-características deben pasar a través de la API pública de la característica.


Las nuevas características comienzan como cortes verticales. Al construir algo nuevo, crea una nueva carpeta en packages/features con el corte vertical completo. Esto deja en claro qué estás construyendo y mantiene todo organizado desde el primer día.
Beneficios
Capacidad de descubrimiento
¿Buscas lógica de reserva? Está todo en
packages/features/bookings. No hay necesidad de buscar a través de controladores, servicios, repositorios y utilidades dispersas por toda la base de código.
Pruebas más fáciles
Pruébala característica completa como unidad. Tienes todas las piezas en un solo lugar, haciendo que las pruebas de integración sean naturales y sencillas.
Dependencias más claras
Cuando ves
import { getAvailability } from '@calcom/features/availability', sabes exactamente de qué característica estás dependiendo. Cuando las dependencias se vuelven demasiado complejas, es obvio y se puede abordar.
Patrón de Repositorio y Inyección de Dependencias
Las elecciones tecnológicas no deben filtrarse a través de la aplicación. El problema de Prisma lo ilustra perfectamente. Actualmente tenemos referencias a Prisma dispersas en cientos de archivos. Esto crea un gran acoplamiento y hace que los cambios tecnológicos sean prohibitivamente caros. Estamos sintiendo el dolor de esto ahora al actualizar Prisma a v6.16. Algo que debería haber sido solo un refactorización localizada detrás de repositorios protegidos se ha convertido en una persecución intrincada y casi interminable de problemas a través de múltiples aplicaciones.
El estándar en adelante:
Todo acceso a la base de datos debe pasar por clases de Repositorio. Ya tenemos una buena ventaja en esto.
Los repositorios son el único código que sabe sobre Prisma (o cualquier otro ORM). No debería haber lógica en ellos.
Los repositorios son inyectados a través de contenedores de Inyección de Dependencias
Si alguna vez cambiáramos de Prisma a Drizzle u otro ORM, los únicos cambios requeridos serían:
Implementaciones de repositorios
Conexiones del contenedor DI para nuevos repositorios
Nada más en la base de código debería preocuparse o cambiar
Esto no es teórico. Así es como construimos sistemas mantenibles.
Objetos de Transferencia de Datos (DTOs)
Los tipos de base de datos no deben filtrarse al frontend. Esto se ha convertido en un atajo popular en nuestro stack tecnológico, pero es un olor a código que crea múltiples problemas.
Acoplamiento tecnológico (tipos de Prisma terminando en componentes de React)
Riesgos de seguridad (fuga accidental de campos sensibles)
Contratos frágiles entre servidor y cliente (esto es particularmente problemático a medida que construimos muchas más APIs)
Incapacidad para evolucionar el esquema de la base de datos de forma independiente
Todas las conversiones de DTOs a través de Zod, incluso para una respuesta API para asegurarnos de que se está validando toda la data antes de enviarla al usuario. Es mejor fallar que devolver algo incorrecto.
El estándar de ahora en adelante:
Crea DTOs explícitos en cada límite arquitectónico.
Capa de Datos → Capa de Aplicación → API: Transforma modelos de bases de datos en DTOs de la capa de aplicación, luego transforma DTOs de la aplicación en DTOs específicos de API
API → Capa de Aplicación → Capa de Datos: Transforma DTOs de API a través de la capa de aplicación y en DTOs específicos de datos
Sí, esto requiere más código. Sí, vale la pena. Los límites explícitos prevenen la erosión arquitectónica que crea pesadillas de mantenimiento a largo plazo.
Patrones de Diseño Orientado al Dominio
Los siguientes patrones deben ser usados correctamente y de manera consistente:
Servicios de Aplicación
Orquestar casos de uso, coordinar entre servicios de dominio y repositorios
Servicios de Dominio
Contienen lógica de negocios que no pertenece naturalmente a una sola entidad
Repositorios
Abstraer el acceso a datos, aislar elecciones tecnológicas
Inyección de Dependencias
Permitir un acoplamiento débil, facilitar las pruebas, aislar los intereses
Proxy de Caché
Envolver repositorios o servicios para agregar comportamiento de caché de manera transparente
No es la única forma de hacer caching, por supuesto, pero un buen punto de partida
Decoradores
Agregar preocupaciones transversales (registro, métricas, etc.) sin contaminar la lógica de dominio
Consistencia del Código
Nuestras bases de código deberían parecer como si una persona las escribiera. Este nivel de consistencia requiere una estricta adherencia a los patrones establecidos, reglas integrales de linting que impongan estándares arquitectónicos revisiones de código que rechacen violaciones de patrones + la ayuda de revisores de código AI.
Mover Condicionales al Punto de Entrada de la Aplicación
Las sentencias If pertenecen al punto de entrada, no dispersas por tus servicios. Este es uno de los principios arquitectónicos más importantes para mantener un código limpio y enfocado que no se torne en complejidad inmantenible.
Así es como un código se degrada con el tiempo: Un servicio se escribe para un propósito claro y específico. La lógica es limpia y enfocada. Luego llega un nuevo requisito de producto, y alguien agrega una sentencia if. Unos años y varios requisitos después, ese servicio está plagado de comprobaciones condicionales para diferentes escenarios. El servicio se ha convertido en:
Complicado y difícil de leer
Dificultoso de entender y razonar
Más susceptible a errores
Violando la responsabilidad única (manejando demasiados casos diferentes)
Casi imposible de probar a fondo
El servicio ha excedido sus límites en términos de responsabilidades y lógica.
Una Solución: Patrón de Fábrica con Servicios Especializados
Utiliza el patrón de fábrica para tomar decisiones en el punto de entrada, luego delega a servicios especializados que manejan su lógica específica sin condicionales.
Ejemplo de nuestro base de código:
El BillingPortalServiceFactory determina si la facturación es para una organización, equipo o usuario individual, luego devuelve el servicio apropiado:
Cada servicio maneja su lógica específica sin necesidad de comprobar "¿soy una organización o un equipo?":
Por Qué Esto Importa
Los servicios mantienen su enfoque
Cada servicio tiene una responsabilidad y no necesita saber sobre otros contextos. El
OrganizationBillingPortalServiceno contiene sentencias if verificandoif (isTeam)oif (isUser). Solo sabe cómo manejar organizaciones.
Los cambios están aislados
Cuando necesitas modificar la lógica de facturación de la organización, solo tocas
OrganizationBillingPortalService. No corres el riesgo de romper la facturación de equipos o usuarios. No necesitas seguir condicionales anidados para averiguar qué camino toma tu código.
Las pruebas son directas
Prueba cada servicio independientemente con sus escenarios específicos. No necesitas probar cada combinación de condicionales en diferentes contextos.
Los nuevos requisitos no contaminan el código existente
por ejemplo, cuando necesitas agregar facturación empresarial con reglas diferentes, creas
EnterpriseBillingPortalService. La fábrica gana una condicional más, pero los servicios existentes permanecen intocados y enfocados.
Cómo Lograrlo
Empuja las condicionales hacia los controladores, fábricas o lógica de enrutamiento. Deja que estos puntos de entrada tomen decisiones sobre qué servicio usar.
Mantén los servicios puros y enfocados en una única responsabilidad. Si un servicio necesita comprobar "¿qué tipo soy?", probablemente necesites múltiples servicios.
Prefiere polimorfismo sobre condicionales
Las interfaces definen el contrato. Las implementaciones concretas proporcionan los detalles.
Vigila la acumulación de declaraciones if
Durante la revisión de código, si ves que un servicio gana condicionales para diferentes escenarios, esa es una señal de que debes refactorizar en servicios especializados.
Diseño de API: Controladores Delgados y Abstracción HTTP
Los controladores son capas delgadas que manejan solo preocupaciones HTTP.
Reciben solicitudes, las procesan, y mapean datos a DTOs que se pasan a la lógica central de la aplicación. De ahora en adelante, no se debe ver lógica de aplicación o central en rutas API o manejadores tRPC.
Debemos despegar la tecnología HTTP de nuestra aplicación.
La forma en que transferimos datos entre cliente y servidor (ya sea REST, tRPC, etc.) no debe influir en cómo funciona nuestra aplicación central. HTTP es un mecanismo de entrega, no un impulsor arquitectónico.
Responsabilidades del controlador (y SOLO estas):
Recibir y validar solicitudes entrantes
Extraer datos de parámetros de solicitud, cuerpo, encabezados
Transformar datos de solicitud en DTOs
Llamar a los servicios de aplicación apropiados con esos DTOs
Transformar las respuestas de los servicios de la aplicación en DTOs de respuesta
Devolver respuestas HTTP con códigos de estado apropiados
Los controladores no deben:
Contener lógica de negocio o reglas de dominio
Acceder directamente a bases de datos o servicios externos
Realizar transformaciones de datos complejas o cálculos
Tomar decisiones sobre lo que la aplicación debe hacer
Saber detalles de implementación del dominio
Ejemplo del patrón controlador delgado:
Versionado de API y Cambios críticos
No hay cambios críticos. Esto es crítico. Una vez que un endpoint de API es público, debe permanecer estable. Los cambios críticos destruyen la confianza del desarrollador y crean pesadillas de integración para nuestros usuarios.
Estrategias para evitar cambios críticos:
Sempre añadí novos campos como opcionales
Utiliza versionado de API cuando debes cambiar el comportamiento existente
Deprecia endpoints antiguos de manera elegante con caminos claros de migración
Mantén la compatibilidad hacia atrás durante al menos dos versiones mayores
Cuando debes hacer cambios críticos:
Crea una nueva versión de API utilizando el versionado específico por fecha en la API v2 (quizás también miremos el versionado por nombre que Stripe recientemente introdujo)
Ejecuta ambas versiones simultáneamente durante la transición (ya hacemos esto en la API v2)
Proporciona herramientas de migración automatizadas cuando sea posible
Da a los usuarios tiempo suficiente para migrarse (mínimo seis meses para API públicas)
Documenta exactamente qué cambió y por qué
Rendimiento y Complejidad Algorítmica
Construimos para grandes organizaciones y equipos. Lo que funciona bien con 10 usuarios o 50 registros puede colapsar bajo el peso de la escala empresarial. El rendimiento no es algo que optimizamos más tarde. Es algo que construimos correctamente desde el principio.
Pensar en la Escala Desde el Primer Día
Al construir características, pregúntate siempre: "¿Cómo se comporta esto con 1,000 usuarios? 10,000 registros? 100,000 operaciones?" La diferencia entre algoritmos O(n) y O(n²) puede ser imperceptible en desarrollo, pero catastrófica en producción.
Patrones comunes O(n²) a evitar:
Iteraciones anidadas de matriz (
.mapdentro de.map,.forEachdentro de.forEach)Métodos de matriz como
.some,.find, o.filterdentro de bucles o callbacksVerificar cada elemento contra cada otro elemento sin optimización
Filtros encadenados o mapeado anidados sobre listas grandes
Ejemplo del mundo real: Para 100 espacios disponibles y 50 períodos ocupados, un algoritmo O(n²) realiza 5,000 verificaciones. Aumenta eso a 500 espacios y 200 períodos ocupados, y estás realizando 100,000 operaciones. Eso es un aumento de carga computacional de 20 veces para solo un aumento de datos de 5 veces.
Elige las Estructuras de Datos y Algoritmos Correctos
La mayoría de los problemas de rendimiento se resuelven eligiendo mejores estructuras de datos y algoritmos:
Ordenado + salida temprana: Ordena tus datos una vez, luego rompe los bucles cuando sepas que los elementos restantes no coincidirán
Búsqueda binaria: Utiliza búsqueda binaria para búsquedas en matrices ordenadas en lugar de escaneos lineales
Técnicas de dos pointers: Para fusionar o intersectar secuencias ordenadas, camina a través de ambas con pointers en lugar de bucles anidados
Mapas/sets hash: Usa objetos o conjuntos para búsquedas O(1) en lugar de
.findo.includesen matricesÁrboles de intervalos: Para programación de horarios, disponibilidad y consultas de rango, usa estructuras de árbol adecuadas en lugar de comparación exhaustiva
Transformación de ejemplo:
Comprobaciones de Rendimiento Automatizadas
Implementaremos múltiples capas de defensa contra regresiones de rendimiento:
Reglas de linting que marcan:
Funciones con bucles anidados o métodos de matriz anidados
Llamadas múltiples a
.someanidadas,.find, o.filterRecursión sin memoización
Patrones conocidos anti-patrón para nuestro dominio (programación, comprobaciones de disponibilidad, etc.)
Pruebas de rendimiento en CI que:
Ejecutan algoritmos críticos sobre datos realistas y a gran escala
Comparan tiempos de ejecución contra una línea base en cada PR
Bloquean fusiones que introducen regresiones de rendimiento
Prueba con datos a nivel empresarial (miles de usuarios, decenas de miles de registros)
Monitoreo de producción que:
Rastrea el tiempo de ejecución para rutas críticas
Alerta cuando los algoritmos se desaceleran a medida que crecen los datos
Detecta regresiones antes de que los usuarios lo noten
Proporciona datos de rendimiento del mundo real para informar las optimizaciones
El Rendimiento es una Característica
El rendimiento no es opcional. No es algo que "abordamos más tarde". Para clientes empresariales reservando a través de grandes equipos, respuestas lentas significan productividad perdida y usuarios frustrados (nuestra experiencia con algunos clientes empresariales más grandes puede dar testimonio de esto).
Cada ingeniero debería:
Perfila tu código antes de optimizar, pero piensa en la complejidad desde el principio
Prueba con datos realistas a gran escala (no solo 5 registros de prueba). Ya hemos construido scripts de seed. Probablemente necesitemos extenderlos.
Elige algoritmos y estructuras de datos eficientes desde el principio
Observa las iteraciones anidadas en la revisión de código
Cuestiona cualquier algoritmo que escale con el producto de dos variables
La Dura Realidad NP de la Programación
Los problemas de programación son fundamentalmente NP-duros. Esto significa que a medida que crece el número de restricciones, participantes, o espacios de tiempo, la complejidad computacional puede explotar exponencialmente. La mayoría de los algoritmos de programación óptima tienen un peor de los casos de complejidad de tiempo exponencial, lo que hace que la elección del algoritmo sea absolutamente crítica.
Implicaciones del mundo real:
Encontrar el tiempo de reunión óptimo para 10 personas a través de 3 zonas horarias con restricciones de disponibilidad individual es computacionalmente costoso
Agregar detección de conflictos, buffers, y una multitud de otras opciones amplifica el problema
Elecciones de algoritmos pobres que funcionan bien para equipos pequeños se vuelven completamente inusuales para grandes organizaciones
Lo que toma milisegundos para 5 usuarios puede tardar muchos segundos para organizaciones
Estrategias para manejar la complejidad NP-dura:
Usa algoritmos de aproximación que encuentran soluciones "suficientemente buenas" rápidamente en lugar de soluciones perfectas lentamente
Implementa un almacenamiento en caché agresivo de programas de computación y disponibilidad
Precomputar escenarios comunes durante horas no pico
Dividir problemas de programación grandes en trozos más pequeños y manejables
Establecer límites de tiempo razonables y recurrir a algoritmos más simples cuando sea necesario
Esta es la razón por la que el rendimiento no es solo algo agradable de tener en el software de programación de horarios. Es la base que determina si tu sistema puede escalar a las necesidades empresariales o colapsa bajo patrones de uso del mundo real.
Requisitos de Cobertura de Código
Rastreo de cobertura global
Rastrearemos la cobertura total de la base de código como una métrica clave que mejora con el tiempo. Esto nos da visibilidad en nuestra madurez de pruebas y ayuda a identificar áreas que necesitan atención. El porcentaje de cobertura global se muestra destacadamente en nuestros tableros.
80%+ de cobertura para nuevo código
Cada PR debe tener un 80%+ de cobertura de pruebas para el código que introduce o modifica. Esto se aplica automáticamente en nuestra canalización de CI. Si agregas 50 líneas de nuevo código, esas 50 líneas deben estar cubiertas por pruebas. Si modificas una función existente, tus cambios deben ser probados. Esta es la cobertura general de pruebas. La cobertura de pruebas unitarias necesita estar cerca del 100%, especialmente con la capacidad de aprovechar la IA para ayudar a generar estas.
Abordando el argumento de que "la cobertura no es la historia completa": Sí, sabemos que la cobertura no garantiza pruebas perfectas. Sabemos que puedes escribir pruebas sin sentido que golpean cada línea pero no prueban nada significativo. Sabemos que la cobertura es solo una métrica entre muchas. Pero, seguramente es mejor apuntar a un porcentaje alto que no tener idea de dónde estás en absoluto.
Midiendo el Éxito
"Velocidad" (robando esto de Scrum aunque no usaremos Scrum)
Crecimiento continuo en estadísticas mensuales (características, mejoras, refactorizaciones)
Calidad
Reduce el esfuerzo de PR dedicado a arreglos del 35% actual al 20% o menos para finales de 2026 (calculado en función de cambios de archivo y adiciones/eliminaciones)
Salud arquitectónica
Métricas sobre adherencia a patrones, acoplamiento tecnológico, violaciones de límites
Eficiencia de revisión
PRs más pequeños, revisiones más rápidas, menos rondas de retroalimentación
Tiempo de actividad de la aplicación y API
¿Qué tan cerca estamos de 99.99%?

¡Comienza con Cal.com gratis hoy!
Experimenta una programación y productividad sin problemas, sin tarifas ocultas. ¡Regístrate en segundos y comienza a simplificar tu programación hoy, sin necesidad de tarjeta de crédito!

