ArchScan - Hallazgos e informe de calidad
ArchScan analiza tu base de código y produce un informe de paridad completa con una única puntuación de calidad ponderada por categoría.
Secciones del informe
Sección titulada «Secciones del informe»- Puntuación resumen - una única puntuación ponderada por categoría + estado, comparable entre versiones.
- Hallazgos - con fragmento de código y ubicación exacta del archivo.
- Desglose SOLID - las violaciones se desglosan según los cinco principios.
- Paquetes - dependencias y versiones.
- Proyectos - métricas por proyecto.
- Mapa de dependencias - una vista de grafo interactiva.
- Exportación - HTML/PDF compartible; eliges el idioma del informe por espacio de trabajo.
¿Cómo se calcula la puntuación?
Sección titulada «¿Cómo se calcula la puntuación?»Las categorías de arquitectura, SOLID, dependencias y métricas se reducen a una única puntuación según sus pesos. El escaneo se ejecuta en tu propio CI.
Panel analítico
Sección titulada «Panel analítico»La página de inicio de ArchScan es un panel a escala del espacio de trabajo, cargado en asíncrono:
- Proyectos auditados, puntuación media, hallazgos abiertos, auditorías del mes - tarjetas de cabecera.
- Tendencia de análisis - ejecuciones y puntuación media de las últimas 12 semanas.
- Estado del parque - anillo de notas (A-E), barras de cobertura y desenlace, indicador de ritmo.
- Desglose por lenguaje - proyectos, cuota analizada, puntuación media, fallos.
- Qué se movió - los proyectos cuya puntuación más subió o bajó recientemente.
Code Health
Sección titulada «Code Health»ArchScan → Code Health responde una pregunta distinta a la puntuación: dónde está la deuda. Lee la última ejecución de un proyecto - o, con Todos los proyectos, la última de cada proyecto analizado, fusionadas:
- Mapa de riesgo de archivos - un treemap: el tamaño de la tesela es riesgo concentrado (hallazgos ponderados por el peor método del archivo) y su color la peor severidad. Los archivos pequeños se pliegan en una tesela “otros” - nada cae en silencio.
- Distribución de complejidad - métodos por bandas de complejidad ciclomática (1-5 / 6-10 / 11-20 / 21+), más el peor método con nombre.
- Deuda de diseño por principio - hallazgos agrupados por el principio de su regla (SOLID, DRY, KISS, YAGNI).
- Componentes en la secuencia principal - cada módulo por abstracción × inestabilidad; las zonas de dolor y de inutilidad están marcadas.
- Puntos calientes - archivos donde hallazgos y complejidad coinciden.
Un proyecto cuyo runner no envía métricas se informa como no medido - nunca como cero.
Dependency Health
Sección titulada «Dependency Health»ArchScan → Dependencias invierte las listas de paquetes por proyecto en respuestas a escala del parque:
- La tabla de paquetes - por paquete, no por proyecto: qué paquete retiene a más proyectos, cuántas versiones atrás está el peor anclaje, qué proyecto usa qué versión. Un paquete anclado a varias versiones se marca dividido.
- Versiones de plataforma - el SDK/runtime que declara cada repositorio (
csproj/global.json,pyproject.toml,go.mod,pom.xml,Gemfile,composer.json,package.json) - “quién sigue en .NET 6” de un vistazo. Los siete lenguajes de collector lo informan. - Filas por proyecto - totales, mezcla de frescura y consultas sin resolver (un runner sin red no puede preguntar al registro - se informa desconocido, no al día).
SmartScan
Sección titulada «SmartScan»ArchScan → SmartScan sigue cada punto de entrada web, job de Quartz, servicio en segundo plano y consumidor de MassTransit de un proyecto .NET a través de servicios y handlers hasta el ORM (Entity Framework, Dapper) e informa los riesgos que ve en esa cadena. Es un módulo de advertencia: no baja la puntuación ni hace fallar el pipeline. Una cadena sin riesgo no envía nada.
- Registro no encontrado - una consulta (
FirstOrDefault,Find, …) puede no devolver nada y el resultado se usa sin comprobarlo. El impacto indica si la petición termina en 500 o si un catch general más arriba lo convierte en un mensaje incorrecto. - Datos escritos a medias - una petición hace commit más de una vez sin una transacción que los envuelva.
- Longitud mayor que la columna, valor obligatorio ausente, valor duplicado - un campo de la petición llega a una columna limitada,
NOT NULLo única sin una regla equivalente en el camino. - Valor de la petición que el código no puede leer (.NET, Java, Kotlin, Python, Go, Ruby, PHP) - un valor que envía la petición se lee con
int.Parse,Guid.Parse,Convert.ToInt32o similares sin comprobarlo antes, así que un valor mal formado termina en 500 en lugar de 400. Un registro que la petición nombra leído conFirst/Singlese muestra igual en Registro no encontrado: si no existe, la petición termina en 500 en lugar de “no encontrado”. - Borrado bloqueado por registros relacionados (.NET, Java, Kotlin, Python, Go, Ruby, PHP) - un registro se borra de verdad (no es un borrado lógico) mientras otros pueden seguir apuntándole con
Restrict,NoActionoClientSetNull; la base de datos rechaza el borrado con un error de clave foránea. No se informan los flujos que antes comprueban, borran o reasignan esos registros. - Valor fuera de lo que admite la columna (.NET; el caso decimal también Java, Kotlin, Python, Go, Ruby, PHP; el caso enum también Ruby, PHP) - un número mayor que el que admite su columna
decimal(p, s), una fecha que la petición puede omitir y llega a una columnadatetimede SQL Server como 0001-01-01, o un valor no definido que llega a una columna enum de PostgreSQL.
Elija un proyecto y abra una categoría: los riesgos se agrupan por capa y servicio (o por tipo de petición). Un riesgo abierto muestra la cadena paso a paso con archivo y línea, el código, una solución y un prompt para copiar en un asistente de IA. Un riesgo puede cerrarse (falso positivo, riesgo aceptado, no se corregirá) y sigue cerrado mientras se encuentre el mismo riesgo.
En un consumidor el mensaje se reintenta (o, tras un catch general, se pierde); en un job la ejecución falla. Un job no tiene petición, así que solo se revisa por datos escritos a medias.
En un frontend TypeScript (React, Next.js) la cadena empieza donde el usuario actúa o el framework renderiza - un manejador de eventos JSX, un useEffect, un renderizado en servidor (getServerSideProps, una página asíncrona), un manejador de ruta de Next.js - y recorre hooks, thunks de Redux y servicios hasta la petición (fetch, axios), incluido el salto de una petición del cliente a la propia ruta API del proyecto. Las categorías allí: Petición no gestionada (un fallo de petición que nada captura: no se avisa al usuario, o un renderizado en servidor responde con un 500), Fallo transmitido como éxito (un fallo capturado y devuelto como un valor normal, una respuesta de error de fetch leída como datos, un rechazo de thunk que nadie mira), Registro no encontrado (ese valor vacío se lee después y la pantalla lanza un error) y Datos a medio escribir (dos peticiones de escritura seguidas al propio backend). Un cliente HTTP que muestra cada fallo al usuario (un toast en un interceptor) cuenta como gestión.
Los backends de Ruby on Rails y Kotlin Spring se recorren como .NET: acciones de controlador (y endpoints de Grape), jobs y consumers hasta ActiveRecord o Spring Data / JPA, con las mismas categorías; los límites de columna salen de db/schema.rb o de las anotaciones @Column. Las apps de Android (Kotlin) e iOS (Swift) se recorren como un frontend: desde un toque, el ciclo de vida de una pantalla o un view model hasta la petición (Retrofit, OkHttp, Ktor; URLSession, Alamofire, Moya). Allí, un fallo de petición no gestionado que escapa de una corrutina, o un try!, cierra la app; un fallo convertido en nil o en un valor por defecto se informa como fallo transmitido como éxito.
Los backends de Java (Spring Data, JPA, JdbcTemplate, MyBatis), Python (Django y DRF, Flask, FastAPI, Celery; Django ORM, SQLAlchemy), Go (net/http, gin, echo, chi, fiber, gRPC; database/sql, sqlx, GORM, pgx) y PHP (Laravel, Symfony; Eloquent, Doctrine) se recorren igual, con las mismas categorías. En Go un registro inexistente es un error, no un null: un error de no encontrado que se ignora, de modo que una fila vacía se usa como si se hubiera encontrado y la petición responde con éxito, se muestra con el impacto silencioso. Go también informa de una escritura cuyo error se descarta (un db.Create(...) suelto, _ = o un error que solo se registra) mientras la petición responde con éxito: al cliente se le dice que los datos se guardaron cuando quizá no fue así.
SmartScan se activa por proyecto y está desactivado por defecto: Proyecto → Ajustes → Escaneo → Ejecutar SmartScan. Desde la siguiente ejecución del pipeline corre en los escaneos profundos de ese proyecto, sin cambiar nada en el pipeline. Requiere el módulo SmartScan, que un administrador puede desactivar en Administración → Ajustes → Módulos.