Convenciones de nombres
Aprende a nombrar variables, funciones, clases y módulos con nombres que revelan la intención, evitando la desinformación
Nombrar es uno de los dos problemas más difíciles de la informática (junto con la invalidación de caché y los errores off-by-one). Los buenos nombres reducen la necesidad de comentarios, hacen el código autodocumentado y previenen malentendidos.
Phil Karlton dijo célebremente: "Solo hay dos cosas difíciles en la informática: invalidar la caché y poner nombres a las cosas." Una buena nomenclatura requiere empatía con quien lee el código.
Por qué importan los nombres
El código se escribe una vez, pero se lee decenas de veces. Un nombre bien elegido comunica la intención al instante. Un mal nombre obliga a quien lee a rastrear mentalmente cada uso para entender qué representa la variable.
# Bad naming
def proc(lst):
for i in lst:
if i[3] > 0:
print(i[0], i[1])
# Good naming
def print_active_users(users: list) -> None:
for user in users:
if user["is_active"]:
print(user["name"], user["email"])Principios de una buena nomenclatura
1. Nombres que revelan la intención
Un nombre debe responder tres preguntas: ¿Por qué existe? ¿Qué hace? ¿Cómo se usa?
# Bad
d = 5 # elapsed time in days
# Good
days_since_last_login = 5# Bad
def get_them(the_list):
result = []
for x in the_list:
if x[0] == 4:
result.append(x)
return result
# Good
def get_active_orders(order_rows: list) -> list:
active_orders = []
for row in order_rows:
if row["status"] == OrderStatus.ACTIVE:
active_orders.append(row)
return active_orders2. Evita la desinformación
No uses nombres que dejen pistas falsas. Evita variaciones que se parezcan visualmente.
# Disinformation: Hungarian notation without purpose
str_name = "Alice" # It's a string, clearly
int_count = 5 # The type is obvious
# Better: no misleading prefix
user_name = "Alice"
item_count = 5# Confusing: visually similar names
l = 1 # lowercase L
O = 2 # uppercase O
result = l + O # Is this 1+2 or something else?
# Clean
left_operand = 1
right_operand = 2
result = left_operand + right_operand3. Haz distinciones con significado
Si los nombres deben diferir, deben significar cosas diferentes.
# Meaningless distinction
def process_data(a1, a2):
pass
def process_data_v2(a1, a2):
pass
# Meaningful distinction
def process_monthly_report(raw_data: dict) -> dict:
pass
def process_monthly_report_with_totals(raw_data: dict) -> dict:
pass# Noise words
product_info = {} # What is "info" vs just product?
product_data = {} # Same as above?
product_object = {} # Of course it's an object
# Clean
product = {}
product_summary = {}
product_details = {}Nomenclatura según el tipo de elemento
Variables
Las variables deben ser sustantivos o frases nominales que describan los datos que contienen.
# Bad
t = "2024-01-15"
n = 42
x = ["Alice", "Bob"]
# Good
current_date = "2024-01-15"
max_retry_count = 42
team_members = ["Alice", "Bob"]Variables booleanas
Las variables booleanas deben leerse como predicados: is_, has_, can_, should_.
# Unclear
flag = True
status = False
# Clear
is_verified = True
has_permission = False
can_edit = has_permission and is_verified
should_retry = error_count < max_retriesFunciones
Las funciones deben ser verbos o frases verbales que describen la acción que realizan.
# Bad
def data():
pass
def stuff(x, y):
pass
# Good
def fetch_user_preferences(user_id: int) -> dict:
pass
def calculate_distance(point_a: tuple, point_b: tuple) -> float:
pass
def validate_email_address(email: str) -> bool:
passClases
Las clases son sustantivos o frases nominales que representan un concepto o una entidad.
# Bad
class Manager:
pass
class Thing:
pass
class Data:
pass
# Good
class OrderProcessor:
pass
class CustomerRepository:
pass
class EmailService:
passMódulos y paquetes
Los módulos deben ser cortos, en minúsculas y con significado. Evita nombres genéricos.
# Bad module names
utils.py
helpers.py
common.py
misc.py
# Good module names
email_validator.py
order_calculator.py
user_auth.py
payment_gateway.pyConvenciones específicas del lenguaje (Python)
Elemento | Convención | Ejemplo |
|---|---|---|
Variable | snake_case | user_name, total_price |
Constante | UPPER_SNAKE_CASE | MAX_CONNECTIONS, API_KEY |
Función | snake_case | get_user_by_id() |
Clase | PascalCase | OrderProcessor, EmailService |
Módulo | snake_case | email_validator.py |
Privado | _leading_underscore | _internal_helper() |
Mágico | __dunder__ | __init__, __str__ |
El PEP 8 es la guía de estilo oficial de Python. Usa snake_case para funciones y variables, PascalCase para clases y UPPER_SNAKE_CASE para constantes.
Antipatrones de nombres
1. Nombres codificados
# Anti-pattern: encoding type in name
strFirstName = "Alice" # Hungarian notation in Python
intAge = 30 # We already have type hints
arrItems = [1, 2, 3] # Unnecessary prefix
# Clean
first_name = "Alice"
age = 30
items = [1, 2, 3]2. Abreviaturas
# Anti-pattern: unclear abbreviations
def calc_avg_rt(u_ids, p_ids):
pass
# Clean
def calculate_average_rating(user_ids: list, product_ids: list) -> float:
pass3. Nombres de una sola letra (excepto los índices de bucle)
# Anti-pattern: single letters
def validate(c, u, p):
return c > 0 and u and len(p) >= 8
# Clean
def is_input_valid(count: int, username: str, password: str) -> bool:
return count > 0 and bool(username) and len(password) >= 8Ejemplo del mundo real: refactorizar nombres
Antes de refactorizar:
class emp:
def __init__(self, n, a, s):
self.n = n
self.a = a
self.s = s
def calc(self):
if self.a >= 5:
return self.s * 1.10
return self.s
def disp(self):
print(f"Name: {self.n}, Salary: {self.calc()}")Después de refactorizar:
class Employee:
BONUS_THRESHOLD_YEARS = 5
BONUS_MULTIPLIER = 1.10
def __init__(self, full_name: str, years_of_service: int, base_salary: float):
self.full_name = full_name
self.years_of_service = years_of_service
self.base_salary = base_salary
def calculate_total_compensation(self) -> float:
if self.years_of_service >= self.BONUS_THRESHOLD_YEARS:
return self.base_salary * self.BONUS_MULTIPLIER
return self.base_salary
def display_employee_info(self) -> None:
total_salary = self.calculate_total_compensation()
print(f"Name: {self.full_name}, Salary: {total_salary}")El contexto importa
Los nombres existen dentro de un contexto. Una variable llamada name tiene todo el sentido dentro de una clase Customer, pero confunde en el ámbito global.
# Without context
name = "Alice"
address = "123 Main St"
email = "alice@example.com"
# Are these related? Is this a customer, an employee, a vendor?
# With context (class)
class Customer:
def __init__(self, name: str, address: str, email: str):
self.name = name
self.address = address
self.email = email# Without context
def print_report():
name = "Monthly Sales"
data = [100, 200, 300]
# name of what? data of what?
# With context
def print_sales_report():
report_title = "Monthly Sales"
sales_data = [100, 200, 300]Flujo de decisión para nombrar
Una buena nomenclatura es la práctica más impactante para el mantenimiento del código. Dedicar tiempo a elegir el nombre correcto: tu yo del futuro te lo agradecerá.
Ejercicios prácticos
-
Renombra el desastre: Refactoriza estos nombres:
d(días de retraso),lst(catálogo de productos),tmp(almacenamiento temporal),x(porcentaje de impuestos). -
Nomenclatura de booleanos: Una variable indica si un usuario ha completado la incorporación. Nómbrala. Una función comprueba si un correo electrónico es entregable. Nómbrala.
-
Nomenclatura de clases: Estás modelando un sistema con: procesamiento de pagos, autenticación de usuarios, generación de informes. Nombra cada clase.
-
Auditoría de módulos: Mira los nombres de los módulos de tu proyecto. Reemplaza
utils.pyyhelpers.pypor nombres específicos del dominio. -
Caza de desinformación: Encuentra 3 nombres engañosos en código de código abierto y sugiere mejores alternativas.
-
Ejercicio de contexto: Tienes las variables
email,phone,address. Sin una clase, ¿a qué concepto de dominio pertenecen? Envuélvelas en una clase apropiada. -
Expansión de abreviaturas: Escribe una función que expanda las abreviaturas del código:
calc_avg_rt→calculate_average_rating,get_usrs→get_users. -
Revisión entre pares: Pide a un colega que revise 100 líneas de tu código y que señale cualquier nombre que no le quede claro. Refactoriza en consecuencia.