Regla 0x2014h: Cada función debe caber en una sola idea y en 25 líneas
Funciones, contratos y modularizacion (0x20XX)
0x2014h: Cada función debe caber en una sola idea y en 25 líneas¶
Enunciado normativo¶
DEBE escribirse cada función para resolver una sola idea y NO DEBE superar las 25 líneas de cuerpo (sin contar llaves, comentarios ni líneas en blanco). Si la función no cabe, se la divide.
¿Por qué existe esta regla?¶
El problema¶
Una función larga es una función que hace varias cosas a la vez. Cuando hay que modificarla, el lector no puede abarcarla de una sola mirada; tiene que recordar en qué punto del recorrido está y qué variables ya cambió. Cada variable local extra multiplica las combinaciones de estado que hay que retener en la cabeza, y con ellas los errores por efecto colateral.
La longitud es el síntoma medible de la falta de responsabilidad única (0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única)). No es que las líneas sean malas por sí mismas: son la señal de que conviven demasiados niveles de abstracción en el mismo lugar.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Bug silencioso | Variables reutilizadas que arrastran valores entre bloques lógicos distintos. |
| Testing | No se puede probar una parte sin arrastrar todo el contexto. |
| Anidación | La función larga suele venir acompañada de 4, 5 o 6 niveles de if. |
| Mantenibilidad | Cambiar un requisito obliga a reentender decenas de líneas. |
Fundamento en la cátedra¶
Es una especialización cuantitativa de 0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) (responsabilidad única). El umbral de 25 líneas es el mismo que usa 0x200Dh: Comentarios de cierre explicativos en bloques de control extensos (> 25 líneas) para exigir comentarios de cierre: por encima de ese tamaño, el lector pierde la noción del bloque. El número no es sagrado; es un disparador de revisión.
Alcance y excepciones¶
Cuenta el cuerpo entre la llave de apertura y la de cierre, excluyendo
comentarios y líneas en blanco. Las funciones switch muy extensas pueden
justificar excepción, pero en un curso introductorio es raro: si hay más de
cinco casos, cada caso suele merecer su propia función.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Cálculo, validación y presentación en una sola función¶
void procesar(void)
{
int edades[100];
int n = 0;
printf("Ingrese edades (-1 para terminar):\n");
int x;
while (1) {
scanf("%d", &x);
if (x == -1) {
break;
}
if (x < 0 || x > 120) {
printf("Edad invalida\n");
continue;
}
edades[n] = x;
n++;
}
double suma = 0;
for (int i = 0; i < n; i++) {
suma += edades[i];
}
double promedio = n > 0 ? suma / n : 0;
printf("Promedio: %.2f\n", promedio);
int mayores = 0;
for (int i = 0; i < n; i++) {
if (edades[i] >= 18) {
mayores++;
}
}
printf("Mayores de edad: %d\n", mayores);
}Por qué falla: hace cuatro cosas (leer, validar, promediar, contar) y tiene más de 25 líneas. No se puede probar el promedio sin simular la entrada por teclado. Viola además 0x2002h: Las funciones no deben contener printf o scanf, a menos que ese sea su propósito explícito (I/O mezclada con lógica).
❌ Contraejemplo 2 — Función “navaja suiza” con parámetros bandera¶
int calcular(int a, int b, int modo)
{
int r = 0;
for (int i = 0; i < 100; i++) {
if (modo == 1) {
r += a * i;
} else if (modo == 2) {
r -= b * i;
} else if (modo == 3) {
r += (a + b) * i;
}
/* ... 40 líneas más ... */
}
return r;
}Por qué falla: el parámetro modo es en realidad tres funciones distintas
disfrazadas de una (ver 0x7007h: Evitá los parámetros bandera de tipo bool). La longitud es la consecuencia.
✅ Ejemplo conforme 1 — Una idea por función¶
static bool edad_valida(int edad)
{
return edad >= 0 && edad <= 120;
}
static double promedio(const int edades[], size_t n)
{
if (n == 0) {
return 0.0;
}
int suma = 0;
for (size_t i = 0; i < n; i++) {
suma += edades[i];
}
return (double)suma / (double)n;
}Cada función mide menos de 15 líneas, tiene un único punto de verdad y se
puede probar con un assert aislado.
✅ Ejemplo conforme 2 — Cuerpo que cabe en una pantalla¶
static size_t contar_mayores(const int edades[], size_t n)
{
size_t mayores = 0;
for (size_t i = 0; i < n; i++) {
if (edades[i] >= 18) {
mayores++;
}
}
return mayores;
}El nombre describe la única idea; el cuerpo completo entra en una pantalla sin desplazamiento.
⚠️ Casos límite¶
Funciones con muchos
case: evaluar si cadacaseno es, en realidad, una operación independiente.Inicialización de estructuras grandes: puede ser legítimamente larga, pero conviene aislarla en una función constructora.
El límite de 25 no justifica extraer funciones artificiales: extraer una función de una línea sólo para bajar el conteo es ruido, no diseño.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
giger | análisis de call graph | Funciones con cuerpo desproporcionado respecto de sus pares. |
gaff | gaff check archivo.c | Regla 0x2005h (responsabilidad única). |
| Conteo manual | — | Más de ~25 líneas efectivas o más de 3 niveles de anidación. |
Checklist de autocontrol¶
¿Puedo describir la función con una sola frase sin usar “y”?
¿El cuerpo cabe en una pantalla de editor?
¿Cada variable local sirve a una única idea?
Si extraje una función, ¿tiene nombre significativo y se prueba sola?
Reglas relacionadas¶
0x2005h: Cada función debe tener una única responsabilidad (Principio de Responsabilidad Única) — responsabilidad única; la presente es su expresión cuantitativa.
0x200Dh: Comentarios de cierre explicativos en bloques de control extensos (> 25 líneas) — comentarios de cierre para bloques extensos.
0x7007h: Evitá los parámetros bandera de tipo bool — los parámetros bandera suelen delatar funciones múltiples.
0x200Ah: Modularización: una función no debe exceder 4 parámetros de entrada — demasiados parámetros es otro síntoma de la misma enfermedad.