Refactorización de Variables y Alcance
Optimización del alcance, inicialización y gestión de variables
Introducción¶
La gestión apropiada de variables es fundamental para escribir código claro, seguro y mantenible. Este apunte cubre técnicas de refactorización enfocadas en mejorar el uso de variables: reducir su alcance, mejorar la inicialización, eliminar variables temporales innecesarias, y aplicar el principio de inmutabilidad cuando sea posible.
Un buen manejo de variables no solo hace el código más legible, sino que también previene errores sutiles relacionados con el estado mutable y reduce la carga cognitiva al leer el código.
Reglas de estilo que resuelve¶
Esta refactorización ataca, de manera conjunta, los problemas que modelan varias reglas de la cátedra: declaraciones lejanas a su uso, variables sin inicializar, reutilización de un mismo nombre para propósitos distintos, bloques de declaraciones y asignaciones desalineados, y operaciones que conviene separar. Cada técnica de las que siguen resuelve uno o más de esos problemas; la tabla los mapea de forma explícita para que puedas ir de la regla a la técnica.
| Regla | Problema que modela | Cómo lo resuelve esta refactorización |
|---|---|---|
| 0x7001h: Siempre debés inicializar las variables a un valor conocido | Variables locales que se leen antes de recibir un valor conocido. | Se inicializan en el punto de declaración o se valida y retorna temprano antes de usarlas. |
| 0x6003h: Declará cada variable lo más cerca posible de su primer uso | Declaraciones agrupadas al inicio, lejos de donde se usan. | Se mueve cada declaración al punto más cercano a su primer uso. |
| 0x2006h: Mantené el alcance de las variables al mínimo posible | Variables con un alcance más amplio que el necesario. | Se limita el alcance con bloques, variables de lazo y extracción de funciones. |
| 0x6004h: No reutilices una variable para propósitos distintos | Una misma variable usada para propósitos distintos. | Se separa en variables independientes con nombres descriptivos. |
| 0x301Ch: Detector de variables locales no inicializadas con modificador const | Variables locales declaradas con const y sin inicializar. | Se les asigna un valor inmediato que el compilador puede verificar. |
| 0x7005h: Inicializá todos los campos de estructuras y arreglos | Campos de estructuras o arreglos que quedan sin inicializar. | Se usa inicialización designada ({0} o .campo = valor) para cubrir todos los campos. |
| 0x3003h: No mezcles operaciones de asignación y comparación en una sola línea | Asignación y comparación mezcladas en una sola línea. | Se parte la expresión en pasos separados y legibles. |
| 0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store) | Asignaciones múltiples sin lectura intermedia (dead store). | Se elimina el temporal o se escribe directamente el resultado calculado. |
| 0x0002h: Una declaración de variable por línea | Varias declaraciones en una misma línea (int i, j, k;). | Se declara una variable por línea. |
| 0x0008h: Alineación vertical consistente en asignaciones y declaraciones consecutivas | Declaraciones y asignaciones consecutivas sin alinear. | Se alinean verticalmente para que el bloque se lea de un vistazo. |
Problemas Comunes con Variables¶
1. Alcance Innecesariamente Amplio¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17// Problemático: variables declaradas al inicio de funciones largas void procesar_datos() { int i, j, k; int resultado; double temporal; char buffer[256]; // ... muchas líneas de código ... // i solo se usa aquí for (i = 0; i < 10; i++) { printf("%d\n", i); } // ... más código ... // temporal solo se usa aquí temporal = calcular_algo(); }
2. Variables sin Inicializar¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14// Peligroso: variables no inicializadas int calcular_suma(int *arr, int n) { int suma; // ¡Valor indeterminado! if (n > 0) { suma = 0; for (int i = 0; i < n; i++) { suma += arr[i]; } } return suma; // Puede retornar basura si n <= 0 }
3. Variables Temporales Innecesarias¶
1 2 3 4 5 6 7 8 9 10 11 12// Verboso: temporales que no agregan claridad int obtener_edad() { int edad_temporal = 25; return edad_temporal; } double calcular_precio(double base, double descuento) { double precio_con_descuento = base * (1 - descuento); double precio_final = precio_con_descuento; return precio_final; }
4. Reutilización Inapropiada de Variables¶
1 2 3 4 5 6 7 8 9 10 11 12 13// Confuso: misma variable para propósitos diferentes void procesar() { int temp; temp = leer_entrada(); validar(temp); // temp reutilizada para algo diferente temp = calcular_resultado(); guardar(temp); // temp reutilizada nuevamente temp = contar_elementos(); mostrar(temp); }
Técnicas de Refactorización¶
1. Reducir Alcance de Variables¶
Declarar variables en el punto más cercano a su primer uso, tal como piden 0x6003h: Declará cada variable lo más cerca posible de su primer uso y 0x2006h: Mantené el alcance de las variables al mínimo posible.
Antes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24void procesar_archivo(const char *ruta) { FILE *archivo; char linea[256]; int contador; int i; archivo = fopen(ruta, "r"); if (archivo == NULL) { return; } contador = 0; while (fgets(linea, sizeof(linea), archivo)) { contador++; } printf("Líneas: %d\n", contador); fclose(archivo); // i solo se usa aquí for (i = 0; i < 10; i++) { printf("%d\n", i); } }
Después:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21void procesar_archivo(const char *ruta) { FILE *archivo = fopen(ruta, "r"); if (archivo == NULL) { return; } int contador = 0; char linea[256]; while (fgets(linea, sizeof(linea), archivo)) { contador++; } printf("Líneas: %d\n", contador); fclose(archivo); // i declarada en el lazo for (int i = 0; i < 10; i++) { printf("%d\n", i); } }
Beneficios:
Más claro dónde se usa cada variable
Menos espacio mental para rastrear estado
Inicialización en el punto de declaración
2. Inicialización Segura¶
Siempre inicializar variables en el punto de declaración, como exige 0x7001h: Siempre debés inicializar las variables a un valor conocido. Cuando el valor depende del flujo, conviene validar y retornar temprano antes que arrastrar una variable sin inicializar.
Antes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22int procesar_datos(int *arr, int n) { int suma; int maximo; int contador; if (n > 0) { suma = 0; maximo = arr[0]; contador = 0; for (int i = 0; i < n; i++) { suma += arr[i]; if (arr[i] > maximo) { maximo = arr[i]; } contador++; } } return suma; // ¡Peligro! }
Después:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20int procesar_datos(const int *arr, int n) { int suma = 0; int maximo = 0; int contador = 0; if (n > 0) { maximo = arr[0]; for (int i = 0; i < n; i++) { suma += arr[i]; if (arr[i] > maximo) { maximo = arr[i]; } contador++; } } return suma; }
Mejor aún (con validación temprana):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18int procesar_datos(const int *arr, int n) { if (n <= 0) { return 0; } int suma = 0; int maximo = arr[0]; for (int i = 0; i < n; i++) { suma += arr[i]; if (arr[i] > maximo) { maximo = arr[i]; } } return suma; }
3. Eliminar Variables Temporales Innecesarias¶
Una temporal que solo se copia una vez suele ser un dead store encubierto: se asigna y nunca se lee con un propósito propio. Eliminarla resuelve lo que modela 0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store) y, de paso, mantiene la inicialización en la declaración (0x7001h: Siempre debés inicializar las variables a un valor conocido).
Antes:
1 2 3 4 5 6 7 8 9 10 11 12 13double calcular_total(double precio, double cantidad, double impuesto) { double subtotal = precio * cantidad; double monto_impuesto = subtotal * impuesto; double total = subtotal + monto_impuesto; return total; } int es_par(int n) { int resto = n % 2; int resultado = (resto == 0); return resultado; }
Después:
1 2 3 4 5 6 7 8 9double calcular_total(double precio, double cantidad, double impuesto) { double subtotal = precio * cantidad; return subtotal * (1 + impuesto); } int es_par(int n) { return n % 2 == 0; }
Cuando las temporales SÍ agregan valor:
1 2 3 4 5 6 7 8 9 10// Temporales útiles para claridad double calcular_factura(const item_t *items, int n, double tasa_iva) { double subtotal = calcular_subtotal(items, n); double descuento = calcular_descuento_aplicable(subtotal); double subtotal_con_descuento = subtotal - descuento; double iva = subtotal_con_descuento * tasa_iva; double total = subtotal_con_descuento + iva; return total; }
4. Separar Variables con Propósitos Diferentes¶
No reutilizar variables para diferentes propósitos (0x6004h: No reutilices una variable para propósitos distintos): cada variable nueva se declara en su propia línea, una por línea (0x0002h: Una declaración de variable por línea), en lugar de agruparlas al inicio.
Antes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20void procesar() { int valor; // Primer uso: entrada valor = leer_entrada(); validar(valor); // Segundo uso: resultado intermedio (diferente significado) valor = calcular_resultado(valor); transformar(valor); // Tercer uso: contador (totalmente diferente) valor = 0; for (int i = 0; i < 10; i++) { if (condicion(i)) { valor++; } } printf("Contados: %d\n", valor); }
Después:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16void procesar() { int entrada = leer_entrada(); validar(entrada); int resultado = calcular_resultado(entrada); transformar(resultado); int elementos_contados = 0; for (int i = 0; i < 10; i++) { if (condicion(i)) { elementos_contados++; } } printf("Contados: %d\n", elementos_contados); }
Beneficios:
Cada variable tiene un propósito claro
Nombres descriptivos autodocumentan el código
Más fácil rastrear el flujo de datos
5. Usar const para Valores Inmutables¶
Aplicar const a variables que no deben cambiar. Recordá que el detector de
0x301Ch: Detector de variables locales no inicializadas con modificador const exige que esas variables locales con const estén inicializadas:
el valor debe quedar fijo en la misma declaración.
Antes:
1 2 3 4 5 6 7 8void procesar_pedido(pedido_t *pedido) { double tasa_iva = 0.21; double descuento_vip = 0.15; int max_intentos = 3; // ... código que NO debería modificar estas variables tasa_iva = 0.10; // ¡Bug! Cambio accidental }
Después:
1 2 3 4 5 6 7 8 9void procesar_pedido(pedido_t *pedido) { const double TASA_IVA = 0.21; const double DESCUENTO_VIP = 0.15; const int MAX_INTENTOS = 3; // ... código // TASA_IVA = 0.10; // Error de compilación: assignment of read-only // variable }
Aplicar const a parámetros que no se modifican:
1 2 3 4 5 6 7 8 9 10// Antes void procesar_datos(int *arr, int n, configuracion_t *config) { // ... } // Después void procesar_datos(const int *arr, int n, const configuracion_t *config) { // Garantiza que no modificamos arr ni config }
6. Extracción a Variables con Nombre¶
Dar nombres significativos a expresiones complejas. Al extraer, declarás una variable por línea (0x0002h: Una declaración de variable por línea) y podés alinear el bloque de asignaciones consecutivas para facilitar el escaneo (0x0008h: Alineación vertical consistente en asignaciones y declaraciones consecutivas).
Antes:
1 2 3 4 5 6 7if ((usuario->edad >= 18 && usuario->edad <= 65) && (usuario->saldo > 1000 || usuario->credito > 500) && !usuario->bloqueado) { procesar_transaccion(usuario); } // Cálculo complejo sin contexto double total = precio * cantidad * (1 - (cantidad > 10 ? 0.15 : 0.05)) * 1.21;
Después:
1 2 3 4 5 6 7 8 9 10 11 12 13bool es_edad_valida = usuario->edad >= 18 && usuario->edad <= 65; bool tiene_fondos = usuario->saldo > 1000 || usuario->credito > 500; bool puede_operar = es_edad_valida && tiene_fondos && !usuario->bloqueado; if (puede_operar) { procesar_transaccion(usuario); } // Cálculo con variables intermedias const double TASA_IVA = 0.21; double descuento = (cantidad > 10) ? 0.15 : 0.05; double subtotal = precio * cantidad; double subtotal_con_descuento = subtotal * (1 - descuento); double total = subtotal_con_descuento * (1 + TASA_IVA);
7. Variables de Lazo en el Alcance Mínimo¶
Antes (estilo C89):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16void procesar() { int i, j; for (i = 0; i < 10; i++) { printf("%d\n", i); } // i todavía existe y tiene valor 10 for (j = 0; j < 5; j++) { for (i = 0; i < 3; i++) { // Reutiliza i printf("%d,%d\n", i, j); } } }
Después (C99+):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15void procesar() { for (int i = 0; i < 10; i++) { printf("%d\n", i); } // i ya no existe aquí for (int j = 0; j < 5; j++) { for (int i = 0; i < 3; i++) { // Nueva i, no confusión printf("%d,%d\n", i, j); } } }
Casos Prácticos Completos¶
Caso 1: Análisis de Texto¶
Código Original:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38void analizar_texto(const char *texto) { int i, j, k; int longitud, palabras, lineas, caracteres_especiales; char caracter_actual, caracter_anterior; int en_palabra; longitud = strlen(texto); palabras = 0; lineas = 1; caracteres_especiales = 0; en_palabra = 0; caracter_anterior = ' '; for (i = 0; i < longitud; i++) { caracter_actual = texto[i]; if (caracter_actual == '\n') { lineas++; } if (!isalnum(caracter_actual) && !isspace(caracter_actual)) { caracteres_especiales++; } if (isspace(caracter_actual)) { en_palabra = 0; } else if (!en_palabra) { en_palabra = 1; palabras++; } caracter_anterior = caracter_actual; } printf("Palabras: %d\n", palabras); printf("Líneas: %d\n", lineas); printf("Caracteres especiales: %d\n", caracteres_especiales); }
Código Refactorizado:
La estructura stats se inicializa de forma designada, cubriendo todos los
campos aunque algunos arranquen en cero (0x7005h: Inicializá todos los campos de estructuras y arreglos).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45typedef struct { int palabras; int lineas; int caracteres_especiales; } estadisticas_texto_t; bool es_caracter_especial(char c) { return !isalnum(c) && !isspace(c); } estadisticas_texto_t analizar_texto(const char *texto) { estadisticas_texto_t stats = { .palabras = 0, .lineas = 1, .caracteres_especiales = 0}; bool en_palabra = false; const int longitud = strlen(texto); for (int i = 0; i < longitud; i++) { const char caracter_actual = texto[i]; if (caracter_actual == '\n') { stats.lineas++; } if (es_caracter_especial(caracter_actual)) { stats.caracteres_especiales++; } if (isspace(caracter_actual)) { en_palabra = false; } else if (!en_palabra) { en_palabra = true; stats.palabras++; } } return stats; } void mostrar_estadisticas(estadisticas_texto_t stats) { printf("Palabras: %d\n", stats.palabras); printf("Líneas: %d\n", stats.lineas); printf("Caracteres especiales: %d\n", stats.caracteres_especiales); }
Mejoras aplicadas:
Variables declaradas cerca de su uso
Inicialización en la declaración
Variables de lazo con alcance reducido
Uso de
constpara valores inmutablesNombres descriptivos
Separación de lógica de cálculo y presentación
Caso 2: Procesamiento de Transacciones¶
Código Original:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58int procesar_transacciones(transaccion_t *trans, int n) { int i, j; double total, subtotal, impuesto, descuento; int aprobadas, rechazadas, pendientes; int resultado; char estado; total = 0; aprobadas = 0; rechazadas = 0; pendientes = 0; for (i = 0; i < n; i++) { subtotal = trans[i].monto; // Calcular descuento if (trans[i].tipo == VIP) { descuento = 0.15; } else if (trans[i].tipo == REGULAR) { descuento = 0.05; } else { descuento = 0; } subtotal = subtotal * (1 - descuento); impuesto = subtotal * 0.21; total = subtotal + impuesto; trans[i].total = total; // Validar if (trans[i].cuenta_origen == NULL) { estado = 'R'; } else if (trans[i].cuenta_origen->saldo < total) { estado = 'R'; } else { estado = 'A'; } if (estado == 'A') { aprobadas++; } else if (estado == 'R') { rechazadas++; } trans[i].estado = estado; } printf("Aprobadas: %d, Rechazadas: %d\n", aprobadas, rechazadas); resultado = (rechazadas == 0) ? 0 : -1; return resultado; }
Código Refactorizado:
El resumen se inicializa con {0} para no dejar ningún campo con basura
(0x7005h: Inicializá todos los campos de estructuras y arreglos).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59typedef struct { int aprobadas; int rechazadas; } resumen_procesamiento_t; double calcular_descuento_tipo(tipo_cliente_t tipo) { switch (tipo) { case VIP: return 0.15; case REGULAR: return 0.05; default: return 0.0; } } double calcular_total_transaccion(double monto, tipo_cliente_t tipo) { const double TASA_IVA = 0.21; double descuento = calcular_descuento_tipo(tipo); double subtotal = monto * (1 - descuento); double impuesto = subtotal * TASA_IVA; return subtotal + impuesto; } bool validar_transaccion(const transaccion_t *trans) { if (trans->cuenta_origen == NULL) { return false; } if (trans->cuenta_origen->saldo < trans->total) { return false; } return true; } resumen_procesamiento_t procesar_transacciones(transaccion_t *trans, int n) { resumen_procesamiento_t resumen = {0}; for (int i = 0; i < n; i++) { trans[i].total = calcular_total_transaccion(trans[i].monto, trans[i].tipo); bool aprobada = validar_transaccion(&trans[i]); trans[i].estado = aprobada ? 'A' : 'R'; if (aprobada) { resumen.aprobadas++; } else { resumen.rechazadas++; } } printf("Aprobadas: %d, Rechazadas: %d\n", resumen.aprobadas, resumen.rechazadas); return resumen; }
Mejoras aplicadas:
Extracción de funciones para cálculos
Variables con alcance reducido
Uso de
constpara parámetros de solo lecturaNombres descriptivos
Eliminación de variables temporales innecesarias
Estructura para retornar múltiples valores
Patrones Avanzados¶
Patrón: Computed Variables (Variables Calculadas)¶
Antes:
1 2 3 4 5 6 7void mostrar_info_usuario(usuario_t *u) { printf("Nombre: %s %s\n", u->nombre, u->apellido); printf("Edad: %d\n", calcular_edad(u->fecha_nacimiento)); printf("Categoría: %s\n", es_premium(u) ? "Premium" : "Regular"); printf("Estado: %s\n", u->activo && !u->bloqueado ? "Activo" : "Inactivo"); }
Después:
1 2 3 4 5 6 7 8 9 10 11 12void mostrar_info_usuario(const usuario_t *u) { const char *nombre_completo = formatear_nombre(u->nombre, u->apellido); const int edad = calcular_edad(u->fecha_nacimiento); const char *categoria = es_premium(u) ? "Premium" : "Regular"; const bool operativo = u->activo && !u->bloqueado; const char *estado = operativo ? "Activo" : "Inactivo"; printf("Nombre: %s\n", nombre_completo); printf("Edad: %d\n", edad); printf("Categoría: %s\n", categoria); printf("Estado: %s\n", estado); }
Patrón: Replacement of Temp with Query¶
Antes:
1 2 3 4 5 6 7 8 9 10 11 12double calcular_precio(item_t *item) { double precio_base = item->precio * item->cantidad; if (precio_base > 1000) { return precio_base * 0.95; } else { return precio_base * 0.98; } }
Después:
1 2 3 4 5 6 7 8 9 10double obtener_precio_base(const item_t *item) { return item->precio * item->cantidad; } double calcular_precio(const item_t *item) { const double precio_base = obtener_precio_base(item); const double descuento = (precio_base > 1000) ? 0.95 : 0.98; return precio_base * descuento; }
Antipatrones a Evitar¶
1. Variables Globales Innecesarias¶
1 2 3 4 5 6 7// Problemático int contador_global = 0; void procesar_item(item_t *item) { contador_global++; // ... }
Mejor:
1 2 3 4 5 6 7 8 9 10typedef struct { int items_procesados; // ... otros datos de contexto } contexto_procesamiento_t; void procesar_item(item_t *item, contexto_procesamiento_t *ctx) { ctx->items_procesados++; // ... }
2. Variables “God” (Demasiado Propósito)¶
Además de violar 0x6004h: No reutilices una variable para propósitos distintos, esta variable encadena asignaciones que nunca se leen antes de la siguiente: cada línea pisa el valor anterior, un dead store que modela 0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store).
1 2 3 4 5 6// Problemático int datos; // Usado para todo datos = leer_archivo(); datos = procesar(datos); datos = validar(datos); datos = contar_elementos(datos);
3. Variables con Nombres No Descriptivos¶
// Problemático
int d; // días? dinero? datos?
int tmp;
int x, y, z;4. Asignación y Comparación Mezcladas¶
Mezclar una asignación con una comparación dentro de una misma expresión produce
errores difíciles de ver, como el clásico if (estado = 'A'). La regla
0x3003h: No mezcles operaciones de asignación y comparación en una sola línea pide no combinar ambas operaciones en una sola línea.
1 2 3 4 5 6// Problemático: asigna 'A' en lugar de comparar char estado = leer_estado(); if (estado = 'A') { procesar(); }
Mejor:
1 2 3 4 5char estado = leer_estado(); if (estado == 'A') { procesar(); }
Ejemplo integrador¶
En este ejemplo resolvemos varias reglas a la vez. El código original declara
todo al inicio (0x0002h: Una declaración de variable por línea, 0x6003h: Declará cada variable lo más cerca posible de su primer uso), deja variables sin inicializar
(0x7001h: Siempre debés inicializar las variables a un valor conocido), mezcla asignación con comparación (0x3003h: No mezcles operaciones de asignación y comparación en una sola línea), reutiliza
total para la suma y para el promedio (0x6004h: No reutilices una variable para propósitos distintos, 0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store)) y
mantiene un alcance amplio para i y j (0x2006h: Mantené el alcance de las variables al mínimo posible).
❌ Antes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21double promedio_activos(pedido_t *pedidos, int n) { int i, j; double total; int cantidad; total = 0; cantidad = 0; for (i = 0; i < n; i++) { if (pedidos[i].estado = 'A') { total = total + pedidos[i].monto; cantidad = cantidad + 1; } } if (cantidad > 0) { total = total / cantidad; // total cambia de significado } return total; }
✅ Después:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30typedef struct { double suma; int cantidad; } acumulado_t; acumulado_t acumular_activos(const pedido_t *pedidos, int n) { acumulado_t acc = {.suma = 0.0, .cantidad = 0}; for (int i = 0; i < n; i++) { const bool activo = pedidos[i].estado == 'A'; if (activo) { acc.suma += pedidos[i].monto; acc.cantidad++; } } return acc; } double promedio_activos(const pedido_t *pedidos, int n) { const acumulado_t acc = acumular_activos(pedidos, n); if (acc.cantidad == 0) { return 0.0; } return acc.suma / acc.cantidad; }
Cada variable nace cerca de su uso (0x6003h: Declará cada variable lo más cerca posible de su primer uso), arranca con un valor
conocido (0x7001h: Siempre debés inicializar las variables a un valor conocido) y la estructura se inicializa campo a campo cubriendo
todos sus miembros (0x7005h: Inicializá todos los campos de estructuras y arreglos). El resultado de la comparación se guarda en
un const bool (0x301Ch: Detector de variables locales no inicializadas con modificador const), el acumulador tiene un único propósito
(0x6004h: No reutilices una variable para propósitos distintos) y su alcance queda acotado a cada función (0x2006h: Mantené el alcance de las variables al mínimo posible). Las
declaraciones consecutivas se declaran una por línea (0x0002h: Una declaración de variable por línea) y se
alinean (0x0008h: Alineación vertical consistente en asignaciones y declaraciones consecutivas).
Diagnóstico y refactorización¶
Usá esta tabla como guía rápida: ubicá el síntoma en tu código y saltá a la técnica de esta guía que lo resuelve.
| Regla | Síntoma en el código | Técnica de esta guía |
|---|---|---|
| 0x7001h: Siempre debés inicializar las variables a un valor conocido | Una variable local se lee sin haber recibido nunca un valor. | Inicialización Segura |
| 0x6003h: Declará cada variable lo más cerca posible de su primer uso | Las declaraciones están amontonadas al inicio y el uso queda lejos. | Reducir Alcance de Variables |
| 0x2006h: Mantené el alcance de las variables al mínimo posible | Un índice o acumulador vive más allá del bloque que lo necesita. | Reducir Alcance de Variables / Variables de Lazo en el Alcance Mínimo |
| 0x6004h: No reutilices una variable para propósitos distintos | El mismo nombre guarda primero una entrada y luego un contador. | Separar Variables con Propósitos Diferentes |
| 0x301Ch: Detector de variables locales no inicializadas con modificador const | Hay const locales sin inicializar o inicializados tarde. | Usar const para Valores Inmutables |
| 0x7005h: Inicializá todos los campos de estructuras y arreglos | Una estructura o arreglo se declara y solo se llenan algunos campos. | Ejemplo integrador / Casos Prácticos Completos |
| 0x3003h: No mezcles operaciones de asignación y comparación en una sola línea | Aparece if (x = y) donde se quería comparar. | Antipatrón 4: Asignación y Comparación Mezcladas |
| 0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store) | Se asigna dos veces a la misma variable sin leer la primera. | Eliminar Variables Temporales Innecesarias |
| 0x0002h: Una declaración de variable por línea | Una línea declara int i, j, k;. | Separar Variables con Propósitos Diferentes / Ejemplo integrador |
| 0x0008h: Alineación vertical consistente en asignaciones y declaraciones consecutivas | Declaraciones o asignaciones consecutivas quedan desalineadas. | Extracción a Variables con Nombre / Ejemplo integrador |
Resumen¶
Técnicas para mejorar el manejo de variables:
Alcance Mínimo: Declarar variables lo más cerca posible de su uso
Inicialización Segura: Siempre inicializar en la declaración
Eliminar Temporales: Remover variables que no agregan claridad
Una Variable, Un Propósito: No reutilizar variables
Inmutabilidad: Usar
constsiempre que sea posibleNombres Significativos: Variables que autodocumentan
Variables Calculadas: Dar nombres a expresiones complejas
Principios clave:
Minimizar alcance reduce complejidad
La inicialización previene bugs sutiles
constcomunica intención y previene erroresNombres descriptivos son documentación
Cada variable debe tener un propósito claro y único
El manejo apropiado de variables es fundamental para código seguro, claro y mantenible.
Checklist de verificación¶
Pasá esta lista antes de dar por cerrada una refactorización de variables:
Toda variable local arranca con un valor conocido (0x7001h: Siempre debés inicializar las variables a un valor conocido).
Cada variable se declara lo más cerca posible de su primer uso (0x6003h: Declará cada variable lo más cerca posible de su primer uso).
El alcance de cada variable es el mínimo necesario (0x2006h: Mantené el alcance de las variables al mínimo posible).
Ninguna variable se reutiliza para propósitos distintos (0x6004h: No reutilices una variable para propósitos distintos).
Las variables
constlocales están inicializadas en su declaración (0x301Ch: Detector de variables locales no inicializadas con modificador const).Los campos de estructuras y los arreglos quedan todos inicializados (0x7005h: Inicializá todos los campos de estructuras y arreglos).
No queda ninguna asignación mezclada con una comparación (0x3003h: No mezcles operaciones de asignación y comparación en una sola línea).
No hay asignaciones múltiples sin lectura intermedia (0x2011h: Prohibición de asignaciones múltiples a una variable sin lectura intermedia (dead store)).
Hay una sola declaración por línea (0x0002h: Una declaración de variable por línea).
Las declaraciones y asignaciones consecutivas están alineadas (0x0008h: Alineación vertical consistente en asignaciones y declaraciones consecutivas).