1. Programar sin entender el problema
El error
Comenzar a escribir código inmediatamente sin analizar completamente el requerimiento.
# Junior salta directo a código sin analizar:
def calcular_descuento(precio):
return precio * 0.1 # ¿10% siempre? ¿Diferentes tipos de cliente?
Cómo evitarlo
Antes de escribir código, responda: ¿Qué entradas recibe? ¿Qué salidas produce? ¿Qué casos edge existen? ¿Cuáles son las reglas de negocio?
from enum import Enum
from dataclasses import dataclass
class CustomerType(Enum):
REGULAR = "regular"
PREMIUM = "premium"
@dataclass
class DiscountRule:
customer_type: CustomerType
discount_percentage: float
max_discount: float = float('inf')
class DiscountCalculator:
def __init__(self, rules: list[DiscountRule]):
self.rules = rules
def calculate(self, price: float, customer_type: CustomerType) -> float:
applicable_rules = [r for r in self.rules if r.customer_type == customer_type]
if not applicable_rules:
return 0
discount = price * applicable_rules[0].discount_percentage
return min(discount, applicable_rules[0].max_discount)
2. No manejar errores adecuadamente
El error
Asumir que todo funcionará perfectamente o usar try-catch genérico.
// Error: No manejar casos nulos
function getUser(userId) {
const user = database.find(userId);
return user.name; // ¿Qué pasa si user es null?
}
// Error: Tragar excepciones
try {
paymentGateway.charge(amount);
} catch (error) {
return false; // ¿Por qué falló?
}
Cómo evitarlo
class UserNotFoundError extends Error {
constructor(userId) {
super(`User with ID ${userId} not found`);
this.userId = userId;
}
}
function getUser(userId) {
const user = database.find(userId);
if (!user) {
throw new UserNotFoundError(userId);
}
return user;
}
async function processPayment(amount) {
try {
const result = await paymentGateway.charge(amount);
logger.info(`Payment successful: ${amount}`, { result });
return { success: true, transactionId: result.id };
} catch (error) {
logger.error('Payment failed', { amount, error: error.message });
throw new PaymentError(`Failed to process payment of ${amount}`, error.code);
}
}
3. No escribir código testeable
El error
Crear código tan acoplado que es imposible de probar sin dependencias externas.
public class OrderService {
public void createOrder(OrderRequest request) {
// Acoplado a implementaciones concretas
Database db = new MySQLDatabase();
EmailService email = new GmailService();
Order order = new Order();
db.save(order);
email.send(request.getCustomerEmail(), "Order confirmed");
}
}
Cómo evitarlo
// Código testeable con inyección de dependencias
public class OrderService {
private final IDatabase database;
private final IEmailService emailService;
public OrderService(IDatabase database, IEmailService emailService) {
this.database = database;
this.emailService = emailService;
}
public OrderResult createOrder(OrderRequest request) {
if (!isValidRequest(request)) {
return OrderResult.invalid("Invalid request");
}
Order order = buildOrder(request);
database.save(order);
emailService.send(request.getCustomerEmail(), "Order confirmed");
return OrderResult.success(order);
}
}
// Test ahora es trivial con mocks
@Test
public void testCreateOrder_Success() {
IDatabase mockDb = mock(IDatabase.class);
IEmailService mockEmail = mock(IEmailService.class);
OrderService service = new OrderService(mockDb, mockEmail);
OrderResult result = service.createOrder(validRequest);
assertTrue(result.isSuccess());
verify(mockDb, times(1)).save(any(Order.class));
}
4. Copiar y pegar código sin entender
El error
Tomar código de Stack Overflow o IA sin comprender qué hace o sus riesgos de seguridad.
# Copiado sin entender - PELIGROSO
import pickle
def load_data(filename):
with open(filename, 'rb') as f:
return pickle.load(f) # Vulnerabilidad: ejecución de código arbitrario
user_data = load_data(request.files['upload']) # ¡NUNCA hacer esto!
Cómo evitarlo
Antes de usar código copiado: lea cada línea, busque las funciones en la documentación oficial, identifique riesgos, verifique alternativas y pruebe casos edge.
import json
from pathlib import Path
def load_data(filename: str) -> dict:
"""Carga datos desde archivo JSON de forma segura."""
if not Path(filename).exists():
raise FileNotFoundError(f"File not found: {filename}")
try:
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in {filename}: {e}")
5. Ignorar convenciones del equipo
El error
Cada desarrollador usa su propio estilo, haciendo el código inconsistente y difícil de mantener.
Cómo evitarlo
Configure herramientas de linting y formateo automático desde el inicio del proyecto:
// .eslintrc.json
{
"extends": ["airbnb-base", "prettier"],
"rules": {
"no-console": "warn",
"no-unused-vars": "error",
"prefer-const": "error"
}
}
# Pre-commit hooks
npm run lint
npm run format
npm test
6. No usar control de versiones correctamente
El error
Commits gigantes sin descripción: "fix", "changes", "final version 2".
Cómo evitarlo
Use commits atómicos con convención semántica:
# Formato: <tipo>(<alcance>): <descripción>
git commit -m "feat(auth): add email validation to login form
- Validate email format before submission
- Display inline error for invalid emails
- Add unit tests for validation logic
Closes #123"
# Tipos: feat, fix, docs, style, refactor, test, chore
7. Optimización prematura
El error
Intentar optimizar código antes de que sea necesario, sacrificando legibilidad.
// Sobre-optimización innecesaria
func processUsers(users []User) []ProcessedUser {
result := make([]ProcessedUser, 0, len(users))
// Usar bits para flags (confuso sin beneficio medido)
const (
FLAG_ACTIVE = 1 << 0
FLAG_VERIFIED = 1 << 1
)
// ... código complejo innecesario
}
Cómo evitarlo
Escriba código legible primero, optimice solo cuando haya datos que lo justifiquen.
// Versión clara y mantenible
func processUsers(users []User) []ProcessedUser {
result := make([]ProcessedUser, 0, len(users))
for _, user := range users {
result = append(result, ProcessedUser{
ID: user.ID,
Active: user.Active,
Verified: user.Verified,
})
}
return result
}
// Solo optimizar después de benchmark si es necesario
Regla de oro: "Make it work, make it right, make it fast" — en ese orden.
8. No leer la documentación oficial
El error
Depender exclusivamente de tutoriales o respuestas de IA sin verificar con fuentes oficiales.
Cómo evitarlo
Consulte la documentación oficial primero. Ejemplo después de leer los docs de requests:
import requests
from typing import Dict, Any
def fetch_api(url: str, timeout: int = 10) -> Dict[str, Any]:
"""Fetch data from API endpoint de forma segura."""
if not url.startswith(('http://', 'https://')):
raise ValueError(f"Invalid URL: {url}")
try:
response = requests.get(
url,
timeout=timeout,
verify=True, # Siempre verificar SSL
headers={'Accept': 'application/json'}
)
response.raise_for_status()
return response.json()
except requests.Timeout:
raise RequestException(f"Request timed out after {timeout}s")
except requests.RequestException as e:
raise RequestException(f"Request failed: {e}")
9. No hacer code reviews efectivos
El error
Aprobar PRs sin leer o escribir "LGTM 👍" sin comentarios útiles.
Cómo evitarlo
Como autor del PR:
## Pull Request: Implement User Authentication
### Cambios
- ✅ Add JWT token generation and validation
- ✅ Implement refresh token rotation
- ✅ Add rate limiting to login endpoint
### Testing
- Unit tests (coverage: 95%)
- Integration tests para login flow
### Checklist
- [x] Tests passing
- [x] Documentation updated
- [x] No console.logs
Closes #234
Como reviewer:
### Bloquea merge:
**Security:** `src/auth/login.js:45`
❌ Password se está loggeando — nunca loggear contraseñas
**Bug:** `src/api/users.js:123`
❌ Race condition — falta await en sendWelcomeEmail
### Sugerencias:
Considera usar bcrypt en lugar de SHA256 para passwords
### Positivo:
✅ Excelente manejo de errores
✅ Tests muy completos
10. Sobre-ingenierizar soluciones simples
El error
Aplicar patrones complejos a problemas que requieren soluciones directas.
// Complejidad innecesaria para app simple
interface IUserFactoryStrategy { }
class UserFactoryProvider { }
// ... 50 líneas más para crear un usuario
Cómo evitarlo
// Solución directa
class User {
public static User fromDTO(UserDTO dto) {
return new User(dto.getName(), dto.getEmail());
}
}
// Uso simple
User user = User.fromDTO(userDTO);
Principio: Comience simple. Agregue complejidad solo cuando los requerimientos lo demanden.
11. No pedir ayuda cuando están atascados
El error
Pasar horas luchando con un problema por miedo a parecer incompetente.
Cómo evitarlo
Regla de los 30 minutos: Si estás atascado por 30+ minutos sin progreso real, pide ayuda. Cómo hacerlo efectivamente:
## Problema
JWT token no se valida en middleware — recibo error 401 "Invalid token"
## Comportamiento esperado vs actual
- Esperado: Token válido permite acceso
- Actual: Token falla validación
## Lo que ya intenté
1. Verifiqué que el secret es igual en generación y validación ✅
2. Confirmé que el token se envía en el header correcto ✅
3. Probé con jwt.io — token es válido ✅
## Código relevante
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET);
const decoded = jwt.verify(token, process.env.JWT_SECRET); // Falla aquí
## Error exacto
JsonWebTokenError: invalid signature at verify.js:123
## Pregunta específica
¿Hay casos donde el secret podría diferir entre procesos?
Conclusión
La diferencia entre un junior que progresa rápidamente y uno que se estanca está en:
- Reconocer los errores cuando los cometes
- Entender por qué son problemáticos
- Aplicar las soluciones conscientemente
- Pedir feedback regularmente
En 2026, con IA generando código, el valor del desarrollador está en saber qué preguntar, cómo revisar críticamente y diseñar arquitecturas sólidas.


