Ilustración conceptual de una maqueta, una lupa y cuatro marcadores de estado sobre documentos arquitectónicos.

Validar datos: comprobar tipos, reglas y resultados esperados

Una superficie de ocho metros cuadrados y una superficie escrita como «ocho» pueden acabar pintadas del mismo color rojo. La primera permite aplicar una condición; la segunda necesita resolver antes qué dato hemos recibido. Si además convertimos una superficie ausente en cero, habremos conseguido un informe muy uniforme a costa de mezclar tres problemas diferentes. La uniformidad tiene un precio bastante razonable cuando la paga otra persona intentando corregir los resultados.

Vamos a revisar registros de espacios con identificador, nivel y superficie. Separaremos la validez de la entrada, la posibilidad de evaluarla y el resultado de una regla didáctica: superficie mínima de 10 m². Tendremos programas completos en Python y C#, con datos equivalentes y motivos que expliquen cada estado. El umbral no procede de una norma y el ejemplo no mide geometría: sirve para construir una clasificación que no diga más de lo que ha comprobado.

Tabla de contenidos

Primero decide qué significa cada resultado

Un registro válido para este ejercicio debe ser un objeto con identificador y nivel de texto, ambos con algún carácter distinto de espacio. No comprobamos que ese identificador exista en un modelo ni que el nivel pertenezca al catálogo de un proyecto. El campo superficie_m2 representa una magnitud ya expresada en metros cuadrados; declarar ese nombre no verifica que la extracción haya aplicado correctamente las unidades. Esa responsabilidad tendrá que comprobarse donde se obtenga el dato.

Cuando la superficie esté informada, aceptaremos un número finito entre cero y un millón. Es un rango de entrada elegido para acotar el ejemplo, no un límite normativo ni una afirmación sobre todos los espacios posibles. Una cadena como "12", un valor booleano o un número negativo serán entradas inválidas. Cero, en cambio, será un número permitido que incumple nuestra condición mínima. El programa no debe decidir esas diferencias por la facilidad con la que puede convertir algo a otro tipo.

Si la superficie no aparece o su valor es nulo, devolveremos NO_EVALUABLE. Aquí agrupamos esos dos casos bajo el mismo resultado de evaluación, sin modificar la entrada ni afirmar que tengan el mismo origen. Un sistema puede necesitar investigar por separado una propiedad ausente y otra explícitamente sin valor. La explicación de nulo, vacío y ausente ayuda a conservar esa distinción en la lectura, aunque una regla concreta no pueda evaluar ninguno de los dos.

Solo después de aceptar la forma y disponer del valor aplicaremos la condición: por debajo de 10 será INCUMPLE; desde 10 será CUMPLE. INVALIDO indicará que la entrada no cumple el contrato necesario para continuar. Así tendremos cuatro estados y un motivo. Llamar a todos «error» puede simplificar la leyenda del informe, pero obliga a quien lo recibe a reconstruir la diferencia que acabamos de borrar. Yo conservaría esa información antes de empezar a elegir colores.

El orden también es una decisión: revisaremos identificador y nivel antes de la superficie, y devolveremos el primer problema detectado. Un nivel vacío seguirá siendo INVALIDO aunque tampoco haya superficie. No estamos recogiendo todas las incidencias de un registro en una sola pasada. Si necesitas un informe exhaustivo, puedes devolver una colección de hallazgos; ese cambio debe estar en la promesa de la función y en sus pruebas.

Python: devolver un estado y un motivo sin reparar la entrada

Guarda este programa como validar_espacios.py. Utiliza Python 3.10 o posterior y su biblioteca estándar. La función recibe un registro ya interpretado desde JSON y devuelve una pareja de textos. type(area) excluye expresamente los booleanos, que no queremos aceptar como superficies. La comprobación de rango ocurre antes de isfinite, de modo que un entero desmesurado también queda rechazado sin intentar convertirlo primero a un número de coma flotante.

				
					import json
import math


def evaluar(registro):
    if not isinstance(registro, dict):
        return "INVALIDO", "objeto requerido"
    for campo in ("id", "nivel"):
        valor = registro.get(campo)
        if not isinstance(valor, str) or not valor.strip():
            return "INVALIDO", f"{campo} requerido"
    area = registro.get("superficie_m2")
    if area is None:
        return "NO_EVALUABLE", "superficie sin informar"
    if type(area) not in (int, float):
        return "INVALIDO", "superficie debe ser numero"
    if not 0 <= area <= 1_000_000 or not math.isfinite(area):
        return "INVALIDO", "superficie fuera de rango"
    if area < 10:
        return "INCUMPLE", "superficie menor que 10 m2"
    return "CUMPLE", "superficie al menos 10 m2"


texto = '''[
  {"id":"A","nivel":"N00","superficie_m2":12},
  {"id":"B","nivel":"N00","superficie_m2":8},
  {"id":"C","nivel":"N00","superficie_m2":"12"},
  {"id":"D","nivel":"N01","superficie_m2":null},
  {"id":"E","nivel":"","superficie_m2":12}
]'''
registros = json.loads(texto)
for numero, registro in enumerate(registros, start=1):
    estado, motivo = evaluar(registro)
    print(f"{numero} | {registro['id']} | {estado} | {motivo}")
				
			

Ejecuta desde su carpeta:

				
					python validar_espacios.py
				
			

Los estados de A a E serán CUMPLE, INCUMPLE, INVALIDO, NO_EVALUABLE e INVALIDO. C contiene una cadena y E carece de un nivel utilizable: sus motivos son diferentes aunque compartan estado. D no recibe un cero inventado. La posición de cada registro se muestra junto al identificador para localizar la entrada del ejemplo; no es una identidad persistente del objeto.

La función no altera los campos ni intenta interpretar "12" por su cuenta. Una conversión puede ser adecuada en una fase de normalización, pero entonces hay que definir qué formatos acepta, conservar lo recibido y registrar qué se ha hecho. Introducir una reparación silenciosa dentro de una función llamada evaluar añade una responsabilidad que el nombre no anuncia. Después resulta difícil saber si un resultado describe el dato original o una versión arreglada por el programa con bastante iniciativa.

La biblioteca json interpreta el documento; nuestra función revisa los valores que recibe. Un JSON con sintaxis inválida provoca un fallo de lectura antes de llegar a esa función. Y que un número se haya podido leer tampoco garantiza que sea finito: math.isfinite permite comprobar esa condición explícitamente. Son capas diferentes, aunque el usuario vea un único botón de «Validar».

C#: comprobar el tipo JSON antes de leer el número

Crea el proyecto con .NET 8:

				
					dotnet new console --framework net8.0 -n ValidarEspacios
				
			

Sustituye ValidarEspacios/Program.cs por el programa completo siguiente. ValueKind permite distinguir un número de una cadena, un booleano o un nulo antes de intentar extraerlo. TryGetProperty diferencia una propiedad que falta y TryGetDouble intenta obtener el número; después se revisan finitud y rango.

				
					using System;
using System.Text.Json;

static (string Estado, string Motivo) Evaluar(JsonElement registro)
{
    if (registro.ValueKind != JsonValueKind.Object)
        return ("INVALIDO", "objeto requerido");
    foreach (string campo in new[] { "id", "nivel" })
    {
        if (!registro.TryGetProperty(campo, out var valor) ||
            valor.ValueKind != JsonValueKind.String ||
            string.IsNullOrWhiteSpace(valor.GetString()))
            return ("INVALIDO", $"{campo} requerido");
    }
    if (!registro.TryGetProperty("superficie_m2", out var dato) ||
        dato.ValueKind == JsonValueKind.Null)
        return ("NO_EVALUABLE", "superficie sin informar");
    if (dato.ValueKind != JsonValueKind.Number)
        return ("INVALIDO", "superficie debe ser numero");
    if (!dato.TryGetDouble(out double area) || !double.IsFinite(area) ||
        area < 0 || area > 1_000_000)
        return ("INVALIDO", "superficie fuera de rango");
    return area < 10
        ? ("INCUMPLE", "superficie menor que 10 m2")
        : ("CUMPLE", "superficie al menos 10 m2");
}

string texto = """
[
  {"id":"A","nivel":"N00","superficie_m2":12},
  {"id":"B","nivel":"N00","superficie_m2":8},
  {"id":"C","nivel":"N00","superficie_m2":"12"},
  {"id":"D","nivel":"N01","superficie_m2":null},
  {"id":"E","nivel":"","superficie_m2":12}
]
""";
using var documento = JsonDocument.Parse(texto);
int numero = 0;
foreach (var registro in documento.RootElement.EnumerateArray())
{
    numero++;
    var (estado, motivo) = Evaluar(registro);
    string id = registro.GetProperty("id").GetString()!;
    Console.WriteLine($"{numero} | {id} | {estado} | {motivo}");
}
				
			

Ejecuta:

				
					dotnet run --project ValidarEspacios
				
			

Los estados y los motivos coinciden con Python. La documentación de TryGetDouble aclara que no interpreta el contenido de una cadena JSON y que un valor numérico demasiado grande puede producir infinito. Por eso comprobar la clase de dato y aceptar una conversión no sustituye al control de finitud. Los cinco registros del ejemplo incluyen identificador para presentar la salida; si conectas entradas arbitrarias, la capa que imprime el informe debe poder localizar también un registro cuyo identificador falte.

La comparación utiliza los números de coma flotante de estos ejemplos, sin redondear para decidir. No se ha establecido una tolerancia geométrica ni una política de precisión para una entrega real. Si un valor está en la frontera de una condición profesional, tendrá que justificarse su representación, su precisión y su unidad. El artículo de números, unidades y precisión desarrolla esa decisión. El hecho de que ahora podamos producir cuatro estados no nos concede autoridad para elegir un umbral normativo.

Las pruebas deben comprobar también cuánto se ha evaluado

Empieza por el límite: nueve debe incumplir, diez debe cumplir y once también. Prueba cero y un negativo: cero incumple la condición, mientras que el negativo es una entrada inválida bajo nuestro rango. Cambia después el número por el texto "10" y por un booleano. Deben rechazarse como tipos incorrectos, sin convertirse respectivamente a diez y uno. Son casos pequeños, pero impiden que una conversión conveniente haga pasar por evaluado un dato que no aceptaba el contrato.

Quita la superficie y repite con nulo: ambos resultados serán no evaluables por esta regla. Quita el nivel o déjalo vacío y comprueba el motivo de entrada inválida. Combina nivel vacío y superficie ausente para verificar la prioridad acordada; no atribuyas el resultado al orden casual en que alguien escribió las propiedades JSON. Una prueba automatizada útil debe fijar la expectativa, incluido el motivo, antes de comparar lo que devuelve la función.

Conserva una copia de la entrada para comprobar que evaluar no ha modificado los datos. Añade una colección vacía: el recorrido no imprimirá resultados, pero eso no permite afirmar que el proyecto no tenga problemas. Puede que no hubiese espacios en el alcance o que ni siquiera se haya obtenido la colección esperada. Nuestra función clasifica un registro; no acredita integridad de una exportación, correspondencia de modelos ni cobertura de una API. Cada afirmación necesita el control que le corresponde.

En los cinco registros originales solo dos llegan a la regla de superficie: uno cumple y otro incumple. Los otros tres requieren resolver una entrada inválida o conseguir información. Puedes decir que uno de los dos evaluados cumple, pero presentar «50 % de cumplimiento del proyecto» añadiría una conclusión que el ejemplo no sostiene. Tampoco sería correcto contar las dos entradas inválidas y la no evaluable como tres incumplimientos de superficie. Un informe debería mostrar el total recibido y el reparto completo antes de anunciar un porcentaje especialmente satisfecho de sí mismo.

La decisión que importa aquí es conservar la diferencia entre «puedo evaluar y no cumple» y «todavía no puedo evaluar». Esa diferencia cambia quién tiene que actuar y qué necesita corregir: el dato, su obtención o el elemento que incumple la condición. Si hoy tu informe reduce todo a válido o error, revisa una de sus filas rojas y trata de explicar qué evidencia permite clasificarla. Ese pequeño ejercicio suele encontrar más trabajo útil que añadir otra casilla verde al panel.

Artículos relacionados

Respuestas

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *