Calcular dos veces lo mismo y otras condiciones difíciles de leer
La misma expresión repetida en tres ramas de un condicional, una condición con cinco cláusulas y un ternario anidado. No es rendimiento: son las tres formas más comunes de esconder un caso que nadie contempló.
Un comentario de review que suena a manía: «esto lo estás calculando dos veces». La respuesta mental es que el navegador lo resuelve en microsegundos y es verdad.
El problema no es el costo. Es que dos cálculos idénticos hoy son dos cálculos que pueden dejar de
ser idénticos mañana, cuando alguien corrija uno solo. Y una expresión repetida en tres ramas
significa que el if está partido por el lugar equivocado.
El cálculo repetido
| Lo que se ve | Lo que suele indicar | Qué hacer |
|---|---|---|
| La misma expresión en dos ramas del condicional | La condición no separa lo que parece separar | Sacarla arriba, con nombre |
| Un cálculo dentro de un ciclo que no depende del ciclo | Se escribió donde se necesitó, no donde corresponde | Subirlo fuera del ciclo |
| La misma derivación en la vista y en el servicio | Falta un dato derivado en el origen | Calcularlo una vez, idealmente en el backend |
El tercero es el caso grave en un producto con varias plataformas: si el total, el descuento o la elegibilidad se derivan en cada cliente, cada cliente va a dar un número apenas distinto y la diferencia va a aparecer en un reclamo, no en un test.
La condición con cinco cláusulas
Una condición larga es difícil de leer y, sobre todo, difícil de verificar: nadie puede decir de memoria qué casos cubre.
Cómo se desarma
- Nombrar las partes. Tres booleanos con nombre —
isEligible,hasActiveCard,isWithinWindow— y una condición que se lee como una oración. - Preguntar por el caso que falta. Con las partes nombradas se vuelve evidente qué combinación no está contemplada. Con la condición larga, no.
- Salir temprano. Las guardas al principio de la función achatan el anidamiento y dejan el camino feliz sin sangría.
- Si son reglas de negocio, que se vean como reglas. Cuando la condición codifica una política —quién accede a qué—, conviene que esté en un solo lugar con nombre, no repartida en tres vistas.
La evaluación en corto que esconde una decisión
La otra forma de esconder un caso es la evaluación en corto: usuario && usuario.perfil && usuario.perfil.nombre. Funciona, y lo que oculta es qué se supone que pase cuando falta cada una de
esas piezas.
Antes de seguir, predecí
Es el mismo mecanismo que el default silencioso: el código sigue andando y nadie decidió qué debía pasar.
Cuándo la repetición está bien
No toda duplicación local hay que extraerla. Extraer por reflejo produce funciones con nombres genéricos y parámetros booleanos que son peores de leer que las dos líneas repetidas.
La prueba es la misma que con los helpers: ¿si cambia una, tiene que cambiar la otra? Si la respuesta es sí, se extrae. Si las dos expresiones coinciden por casualidad —dos reglas distintas que hoy dan el mismo número—, unificarlas va a obligar a separarlas de nuevo, con más trabajo.
Más a fondo · nivel seniorExtraer con nombre es documentación que no se desactualiza
El beneficio más grande de sacar una expresión a una constante con nombre no es evitar el cálculo:
es que el nombre explica la intención en el lugar donde se usa. const isWithinGracePeriod = ...
dice por qué existe esa comparación de fechas, cosa que un comentario también haría, con la
diferencia de que el nombre no puede quedar desactualizado sin que alguien lo note.
El cálculo que se repite en dos ramas
Hay 4 problemas en este cambio. Tocá la línea donde creas que está.
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | |||
| 10 | |||
| 11 | |||
| 9 | |||
| 10 | |||
| 11 | |||
| 12 | |||
BloqueaLas dos ramas del condicional hacen exactamente lo mismo La expresión es idéntica en el if y en el else, así que la condición no separa nada. O falta la diferencia que debía haber para premium —y entonces esto es un bug—, o el condicional sobra. Una expresión repetida en las dos ramas casi siempre significa que el if está partido por el lugar equivocado. | |||
| 13 | |||
PreguntaY un detalle que este código deja ver Si el descuento y el impuesto se calculan acá, en el cliente, es muy probable que también se calculen en el backend al confirmar el pedido. Dos derivaciones del mismo número en dos lugares terminan dando resultados apenas distintos, y ese es el caso grave: el total que se muestra deja de coincidir con el que se cobra. | |||
| 14 | |||
| 15 | |||
SugerenciaEl 1.21 aparece dos veces y no dice qué es Es el IVA, y está escrito dos veces como número suelto. El día que cambie hay que acordarse de las dos, y el día que alguien lo lea va a tener que deducir qué significa. Una constante con nombre resuelve las dos cosas. | |||
| 16 | |||
| 17 | |||
| 12 | 18 | ||
| 13 | 19 | ||
| 14 | 20 | ||
Cuatro comentarios sobre once líneas, y ninguno es sobre rendimiento.
Cuándo repetir está bien
Cierre
Autoevaluación
¿Lo entendiste?
Práctica
BloqueaEl nivel del usuario se recalcula una vez por ítem
getUserTier no depende del ítem: depende del usuario, que no cambia adentro del ciclo. Está escrito donde se necesitó, no donde corresponde. Con cien ítems son cien llamadas iguales, y si alguna vez esa función va a la base, es un problema de rendimiento de los caros.