Una de las diferencias más notables entre código de junior y senior no es solo CÓMO escribes el código, sino CÓMO lo organizas. Una buena estructura desde el principio te ahorrará horas de refactoring y hará que tu código sea más mantenible.
¿Por Qué Importa la Organización?
Imagina buscar un archivo especĂfico en una carpeta con 50 archivos sin nombres claros ni organizaciĂłn. ¡Frustrante! Lo mismo pasa con el cĂłdigo mal organizado. Una buena estructura mejora:
-
Velocidad de desarrollo: Encuentras archivos rápidamente
-
Mantenibilidad: Es fácil hacer cambios sin romper otras partes
-
Colaboración: Tu equipo entiende dónde está cada cosa
-
Escalabilidad: Puedes agregar funcionalidades sin crear caos
Estructura Básica de Proyecto Frontend
mi-proyecto/
├── index.html
├── README.md
├── package.json
├── .gitignore
├── css/
│ ├── main.css
│ ├── components.css
│ └── responsive.css
├── js/
│ ├── main.js
│ ├── utils.js
│ ├── api.js
│ └── components/
│ ├── header.js
│ ├── footer.js
│ └── sidebar.js
├── assets/
│ ├── images/
│ ├── icons/
│ └── fonts/
└── docs/
└── project-info.md
Principios de OrganizaciĂłn por Funcionalidad
SeparaciĂłn por Responsabilidades
// ❌ Todo en un solo archivo (main.js)
function validateEmail(email) { /* validaciĂłn */ }
function fetchUsers() { /* API call */ }
function showNotification(message) { /* UI */ }
function calculatePrice(items) { /* lĂłgica de negocio */ }
// âś… Separado por responsabilidades
// utils/validation.js
export function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
export function validateRequired(value) {
return value && value.trim().length > 0;
}
// services/api.js
export async function fetchUsers() {
try {
const response = await fetch('/api/usuarios');
return await response.json();
} catch (error) {
console.error('Error fetching users:', error);
throw error;
}
}
// ui/notifications.js
export function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
document.body.appendChild(notification);
}
// business/pricing.js
export function calculatePrice(items) {
return items.reduce((total, item) => {
return total + (item.price * item.quantity);
}, 0);
}
OrganizaciĂłn de CSS por Componentes
/* css/main.css - Estilos globales */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
color: #333;
}
/* css/components.css - Componentes reutilizables */
.btn {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 1.5rem;
}
/* css/responsive.css - Media queries */
@media (max-width: 768px) {
.btn {
width: 100%;
margin-bottom: 0.5rem;
}
.card {
padding: 1rem;
}
}
PatrĂłn de MĂłdulos JavaScript
Crear MĂłdulos Reutilizables
// modules/UserManager.js
class UserManager {
constructor() {
this.users = [];
this.currentUser = null;
}
async loadUsers() {
try {
this.users = await fetchUsers();
return this.users;
} catch (error) {
showNotification('Error al cargar usuarios', 'error');
return [];
}
}
setCurrentUser(userId) {
this.currentUser = this.users.find(user => user.id === userId);
if (this.currentUser) {
showNotification(`Bienvenido ${this.currentUser.name}`, 'success');
}
}
getCurrentUser() {
return this.currentUser;
}
}
export default UserManager;
// main.js - Uso del mĂłdulo
import UserManager from './modules/UserManager.js';
import { validateEmail } from './utils/validation.js';
const userManager = new UserManager();
document.addEventListener('DOMContentLoaded', async () => {
await userManager.loadUsers();
const loginForm = document.getElementById('login-form');
loginForm.addEventListener('submit', handleLogin);
});
function handleLogin(event) {
event.preventDefault();
const email = document.getElementById('email').value;
if (!validateEmail(email)) {
showNotification('Email inválido', 'error');
return;
}
// LĂłgica de login...
}
ConfiguraciĂłn y Constantes
Centralizar Configuraciones
// config/constants.js
export const API_ENDPOINTS = {
USERS: '/api/usuarios',
PRODUCTS: '/api/productos',
ORDERS: '/api/pedidos'
};
export const UI_MESSAGES = {
LOADING: 'Cargando...',
ERROR_GENERIC: 'Algo saliĂł mal, intenta de nuevo',
SUCCESS_SAVE: 'Guardado exitosamente',
CONFIRM_DELETE: '¿Estás seguro de eliminar este elemento?'
};
export const VALIDATION_RULES = {
MIN_PASSWORD_LENGTH: 6,
MAX_EMAIL_LENGTH: 100,
ALLOWED_FILE_TYPES: ['jpg', 'png', 'gif']
};
// config/environment.js
export const ENV = {
development: {
API_BASE_URL: 'http://localhost:3000',
DEBUG: true
},
production: {
API_BASE_URL: 'https://api.miapp.com',
DEBUG: false
}
};
export const getCurrentEnv = () => {
return window.location.hostname === 'localhost'
? ENV.development
: ENV.production;
};
Arquitectura por CaracterĂsticas
Para proyectos más grandes, organiza por features en lugar de por tipo de archivo:
src/
├── shared/
│ ├── utils/
│ ├── components/
│ └── constants/
├── features/
│ ├── authentication/
│ │ ├── login.js
│ │ ├── register.js
│ │ ├── auth.css
│ │ └── authService.js
│ ├── user-profile/
│ │ ├── profile.js
│ │ ├── profileSettings.js
│ │ ├── profile.css
│ │ └── profileService.js
│ └── products/
│ ├── productList.js
│ ├── productDetails.js
│ ├── products.css
│ └── productService.js
└── main.js
Mejores Prácticas de Naming
Archivos y Carpetas
// âś… Buenos nombres
userService.js // Claro qué hace
productValidation.js // EspecĂfico
orderCalculator.js // Descriptivo
// ❌ Nombres confusos
data.js // ¿Qué datos?
functions.js // ¿Qué funciones?
stuff.js // ¿Qué contiene?
Variables y Funciones
// âś… Descriptivos
const isUserLoggedIn = checkUserSession();
const calculateOrderTotal = (items) => { /* ... */ };
const formatCurrencyValue = (amount) => { /* ... */ };
// ❌ Poco claros
const flag = checkSession();
const calc = (items) => { /* ... */ };
const format = (amount) => { /* ... */ };
DocumentaciĂłn Interna
README.md Básico pero Completo
# Mi Proyecto Web
## DescripciĂłn
AplicaciĂłn web para gestiĂłn de usuarios y productos.
## Estructura del Proyecto
- `/css` - Estilos organizados por componentes
- `/js` - LĂłgica de la aplicaciĂłn
- `/assets` - Recursos estáticos
- `/docs` - DocumentaciĂłn adicional
## InstalaciĂłn
1. Clonar repositorio: `git clone [url]`
2. Abrir `index.html` en el navegador
## Funcionalidades
- Login/registro de usuarios
- Listado de productos
- Carrito de compras
- Panel de administraciĂłn
## TecnologĂas
- HTML5, CSS3, JavaScript ES6
- API REST
- LocalStorage para persistencia
Consejos Prácticos
1. Empieza Simple, Escala Gradualmente
// Fase 1: Todo en main.js (proyecto pequeño)
// Fase 2: Separa en archivos por funcionalidad
// Fase 3: Introduce mĂłdulos y clases
// Fase 4: Arquitectura por caracterĂsticas
2. Usa Comentarios Estratégicos
// âś… Comentarios Ăştiles
/**
* Calcula el precio total incluyendo impuestos y descuentos
* @param {Array} items - Lista de productos en el carrito
* @param {number} taxRate - Tasa de impuesto (ej: 0.19 para 19%)
* @param {number} discountPercent - Descuento en porcentaje
* @returns {number} Precio total final
*/
function calculateFinalPrice(items, taxRate, discountPercent) {
// ImplementaciĂłn...
}
// ❌ Comentarios obvios
// Incrementa i en 1
i++;
3. Mantén Consistencia
// âś… Consistent naming pattern
getUserById()
getProductById()
getOrderById()
// ❌ Inconsistent
getUserById()
fetchProduct()
retrieveOrderData()
Ejercicio Práctico
Reorganiza un proyecto existente siguiendo estos principios:
-
Identifica responsabilidades: ¿Qué hace cada función?
-
Agrupa por funcionalidad: Archivos que trabajan juntos
-
Extrae constantes: URLs, mensajes, configuraciĂłn
-
Separa UI de lĂłgica: ManipulaciĂłn DOM vs lĂłgica de negocio
-
Documenta la estructura: README.md actualizado
Señales de Buena Organización
-
Encuentras archivos rápidamente
-
Sabes dĂłnde agregar nueva funcionalidad
-
Puedes modificar una parte sin afectar otras
-
Un nuevo desarrollador entiende la estructura
-
Los bugs son fáciles de localizar
ÂżCuál es tu mayor desafĂo organizando cĂłdigo? ÂżHas tenido que refactorizar algĂşn proyecto por mala organizaciĂłn inicial?
Compartamos experiencias y aprendamos juntos. Recuerden: una buena organización no se logra de la noche a la mañana, ¡es un proceso iterativo!
Próxima semana: “APIs para Juniors: Cómo consumir y manejar datos externos”
juniordev #CleanCode codeorganization webdev bestpractices javascript