Nombres negados, ambiguos o atados a un experimento
«¿Qué significa que esté en false?» es un comentario de review que no se puede contestar bien. Tres familias de nombres que generan trabajo mental en cada lectura, y qué se hace con los que quedaron atados a un experimento que ya terminó.
Un nombre se escribe una vez y se lee cientos. Es la única parte del código donde el costo se paga del lado de quien lee, y por eso es el comentario de review que más se repite después del de las constantes.
No son todos iguales: hay tres familias de nombres problemáticos, y cada una molesta de una forma distinta.
Los negados
Un booleano negado obliga a una traducción mental en cada lectura, y la traducción se rompe apenas aparece una negación alrededor.
| El nombre | Cómo se lee en la condición | La versión que no cansa |
|---|---|---|
| `isNotAvailable` | `if (!isNotAvailable)`: doble negación | `isAvailable` |
| `hideBanner` | `hideBanner === false` para mostrarlo | `showBanner` |
| `disableValidation` | Mezcla con `!disable...` en otro módulo | `validationEnabled` |
Lo mismo vale para los parámetros booleanos en una llamada: render(true, false) no se entiende sin
ir a la firma. Un objeto con nombres o dos funciones distintas resuelven eso, y aparece seguido como
comentario.
Los ambiguos
El segundo grupo son nombres correctos que no dicen lo suficiente. data, info, item, value,
handleClick, process. No están mal: están vacíos.
Las preguntas que los arreglan
- ¿De qué es?
data→orderSummary. El tipo lo dice, pero el nombre es lo que se lee en el uso, veinte líneas después. - ¿En qué unidad o formato?
duration→durationMinutes.date→expiresAt. La mitad de los bugs de fechas y de tiempos son dos partes que asumieron unidades distintas. - ¿Qué hace exactamente? Un nombre que dice
validatey además guarda está mintiendo. Si el nombre honesto queda feo —validateAndSave—, eso es información: probablemente sean dos funciones. - ¿Es el singular o el plural correcto?
userque en realidad es una lista genera errores reales, no sólo confusión.
Los atados a un experimento
Esta familia es propia de los productos que hacen pruebas A/B, y deja una marca larga. Nombres como
newCheckoutVariantB, testHomeV2, expNavbar2024.
Nacen bien: durante el experimento, ese nombre es exactamente lo que el equipo usa para hablar. El problema empieza el día que el experimento gana y la variante se vuelve el producto: el código queda lleno de referencias a un test que ya no existe, y nadie sabe si se puede borrar.
Antes de seguir, predecí
Ese cambio de limpieza tiene una condición: hay que estar seguro de que la rama perdedora no la usa nadie más. Es el mismo problema que el de borrar código que todavía sirve, y se resuelve igual: buscando referencias fuera del propio módulo antes de borrar.
Un detalle que aparece en equipos que trabajan en dos idiomas
En un equipo donde se conversa en un idioma y se programa en otro, la mezcla se cuela en los nombres: mitad y mitad dentro de la misma función, o un término del dominio traducido en un módulo y sin traducir en otro.
El costo no es estético: es que buscar deja de funcionar. Si el mismo concepto aparece con dos nombres, nadie encuentra todos los lugares donde se usa, y ahí vuelve el problema del principio. Lo que resuelve esto no es una discusión de gustos sino un glosario chico del dominio, acordado una vez.
Más a fondo · nivel seniorCuándo un nombre justifica romper cosas
Renombrar algo público —un campo de una API, una clave de almacenamiento, un evento de analítica— no es refactor: es un cambio de contrato con consumidores que no controlás. Ahí el nombre malo a veces se queda, y lo correcto es acotar el daño: que el nombre feo viva sólo en el borde y que adentro se use el bueno, con una traducción en un solo lugar.
Los tres tipos, en un diff
Hay 4 problemas en este cambio. Tocá la línea donde creas que está.
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | |||
| 6 | |||
| 7 | |||
Sugerencia«data» no dice nada Es el nombre más común y el menos informativo que existe: todo es datos. Acá son permisos, y llamarlo permissions ahorra tener que subir tres líneas para saber qué contiene. El nombre existe justamente para no tener que ir a buscar. | |||
| 8 | |||
SugerenciaEl nombre queda atado a un experimento que va a terminar Dentro de tres meses el experimento B se decide, la bandera se saca y este nombre no va a significar nada para nadie. Conviene nombrar lo que la bandera habilita —hasFullInvoiceAccess— y no el experimento que hoy la enciende. El experimento es temporal; la capacidad, no. | |||
| 9 | |||
| 10 | |||
PreguntaY la consecuencia de los tres juntos Leé la condición en voz alta con los nombres actuales. Cuesta decidir si un usuario del experimento B ve facturas de otras cuentas, que es exactamente lo que esta línea decide. Los nombres no son cosmética: acá son la diferencia entre revisar bien un control de acceso y aprobarlo porque parecía razonable. | |||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | |||
| 7 | 15 | ||
Tres nombres y una función de permisos que ya no se puede leer de corrido.
El costo de un nombre
Cierre
Autoevaluación
¿Lo entendiste?
Práctica
BloqueaNegado, y usado con otra negación encima
«si no no propietario» hay que traducirlo dos veces en cada lectura, y en una función de permisos eso es caro. Con isOwner la condición se lee «si es propietario o está en el experimento». Mismo comportamiento, la mitad de las lecturas equivocadas.