Patrón MVC
Separa la aplicación en componentes Modelo, Vista y Controlador. Patrón de diseño arquitectural para código organizado y mantenible.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Patrón MVC
Visión general
El Patrón Modelo-Vista-Controlador (MVC) es un patrón de diseño arquitectural que separa una aplicación en tres componentes interconectados: Modelo (datos y lógica de negocio), Vista (presentación) y Controlador (manejo de entrada y coordinación).
Es la base de muchos frameworks web (Django, Ruby on Rails, ASP.NET MVC) y arquitecturas de aplicaciones de escritorio.
Cuándo usarlo
Usa el Patrón MVC cuando:
- Quieres una separación limpia entre datos, UI y lógica de interacción de usuario
- Múltiples vistas necesitan mostrar los mismos datos (ej. web y móvil)
- La UI cambia frecuentemente pero el modelo de datos subyacente permanece estable
- Necesitas soportar diferentes mecanismos de entrada (web, CLI, API)
- Múltiples desarrolladores trabajan en diferentes capas simultáneamente
Solución
Python
class UserModel:
def __init__(self, name: str, email: str):
self.name = name
self.email = email
class UserView:
def display(self, user: UserModel):
print(f"User: {user.name} ({user.email})")
class UserController:
def __init__(self, model: UserModel, view: UserView):
self.model = model
self.view = view
def update_name(self, name: str):
self.model.name = name
self.view.display(self.model)
# Uso
controller = UserController(UserModel("Alice", "alice@example.com"), UserView())
controller.update_name("Alicia")
JavaScript
class UserModel {
constructor(name, email) {
this.name = name;
this.email = email;
}
}
class UserView {
display(user) {
console.log(`User: ${user.name} (${user.email})`);
}
}
class UserController {
constructor(model, view) {
this.model = model;
this.view = view;
}
updateName(name) {
this.model.name = name;
this.view.display(this.model);
}
}
// Uso
const controller = new UserController(
new UserModel("Alice", "alice@example.com"),
new UserView()
);
controller.updateName("Alicia");
Java
class UserModel {
String name;
String email;
UserModel(String name, String email) {
this.name = name;
this.email = email;
}
}
class UserView {
void display(UserModel user) {
System.out.println("User: " + user.name + " (" + user.email + ")");
}
}
class UserController {
private UserModel model;
private UserView view;
UserController(UserModel model, UserView view) {
this.model = model;
this.view = view;
}
void updateName(String name) {
model.name = name;
view.display(model);
}
}
// Uso
UserController controller = new UserController(
new UserModel("Alice", "alice@example.com"),
new UserView()
);
controller.updateName("Alicia");
Explicación
MVC divide la responsabilidad en tres capas:
- Modelo: Gestiona datos y reglas de negocio. Notifica a las vistas cuando los datos cambian.
- Vista: Renderiza los datos del modelo. En aplicaciones modernas, esto suele ser una plantilla o componente.
- Controlador: Acepta entrada de usuario, la procesa y actualiza el modelo o la vista según corresponda.
En frameworks web modernos, el Controlador suele mapear rutas HTTP a operaciones del Modelo, mientras que la Vista se renderiza del lado del servidor o como aplicación de página única.
Variantes
| Variante | Caso de uso | Compromiso |
|---|---|---|
| MVC clásico | Aplicaciones de escritorio (estilo Smalltalk) | Acoplamiento fuerte vista-modelo |
| MVP | Capas de UI testeables | El Presenter se convierte en “god class” |
| MVVM | Frameworks frontend (Vue, Angular) | El binding bidireccional añade complejidad |
Lo que funciona
- Mantén los Modelos ignorantes de las Vistas: Los modelos no deben saber cómo se muestran
- Haz las Vistas de solo lectura desde el Modelo: Las vistas observan modelos, pero no los modifican directamente
- Mantén los Controladores delgados: La lógica de negocio pertenece al Modelo, no al Controlador
- Usa el Patrón Observer para actualizaciones Modelo-a-Vista y reducir acoplamiento
- Evita acceso directo al Modelo desde Vistas: Siempre pasa por el Controlador o un ViewModel
Errores comunes
- Controladores gordos: Poner lógica de negocio en controladores en lugar de modelos
- Modelos guiados por vistas: Cambiar la estructura del modelo para satisfacer las necesidades de una vista específica
- Acoplamiento fuerte: Las vistas llamando directamente a métodos del modelo en lugar de usar eventos
- Sobre-ingeniería: Usar MVC completo para un script simple donde la separación no aporta valor
- Ignorar el flujo de datos: Permitir que las vistas modifiquen modelos directamente, saltándose el controlador
Preguntas frecuentes
P: ¿Sigue siendo relevante MVC con frameworks frontend modernos? R: Sí, aunque a menudo en formas evolucionadas. React usa un flujo de datos unidireccional que separa preocupaciones de forma similar. Angular implementa MVVM, que es un descendiente directo.
P: ¿Cuál es la diferencia entre MVC y MVVM? R: MVVM reemplaza el Controlador con un ViewModel que se vincula directamente a la Vista mediante binding bidireccional de datos. Es más común en frameworks frontend.
P: ¿Puedo usar MVC en una arquitectura serverless? R: Sí, aunque el “Controlador” puede ser un API Gateway o función Lambda, el “Modelo” es tu capa de datos y la “Vista” es la respuesta JSON o plantilla renderizada.
¿Es este patrón adecuado para proyectos pequeños?
Para proyectos pequeños con pocos componentes, este patrón puede añadir complejidad innecesaria. Empieza simple e introduce el patrón cuando sientas el problema que resuelve.
¿Cómo se compara este patrón con alternativas?
Cada patrón hace diferentes trade-offs. Revisa la tabla de variantes arriba y considera tus restricciones específicas: tamaño del equipo, requisitos de rendimiento y planes de escalado.
¿Puedo aplicar este patrón parcialmente?
Sí. Muchos equipos adoptan patrones incrementalmente. Empieza con la idea central y añade sofisticación según sea necesario. El patrón es una guía, no un blueprint estricto.
Temas Avanzados
Escenario: MVC para Dashboard Web
// MVC pattern: Model, View, Controller
// Model: datos y logica de negocio
class DashboardModel {
private metrics: Metric[] = [];
private subscribers: (() => void)[] = [];
addMetric(metric: Metric) {
this.metrics.push(metric);
this.notify();
}
getMetrics(): Metric[] { return [...this.metrics]; }
subscribe(cb: () => void) { this.subscribers.push(cb); }
private notify() { this.subscribers.forEach(cb => cb()); }
}
// View: renderiza la UI
class DashboardView {
constructor(private container: HTMLElement) {}
render(metrics: Metric[]) {
this.container.innerHTML = metrics.map(m =>
`<div class="metric-card">`,
`<h3>${m.name}</h3>`,
`<span class="value">${m.value}</span>`,
`</div>`
).join("");
}
}
// Controller: orquesta Model y View
class DashboardController {
constructor(private model: DashboardModel, private view: DashboardView) {
this.model.subscribe(() => this.updateView());
}
async loadMetrics() {
const data = await fetch("/api/metrics").then(r => r.json());
data.forEach((m: Metric) => this.model.addMetric(m));
}
private updateView() {
this.view.render(this.model.getMetrics());
}
}
// Uso
const model = new DashboardModel();
const view = new DashboardView(document.getElementById("dashboard")!);
const controller = new DashboardController(model, view);
controller.loadMetrics();
// Comparacion MVC vs MVP vs MVVM
| Patron | View conoce Model? | Acoplamiento | Data binding |
|--------|-------------------|-------------|--------------|
| MVC | Si (directamente) | Alto | Manual |
| MVP | No (via Presenter) | Medio | Manual |
| MVVM | No (via ViewModel) | Bajo | Automatico (Observable) |
Lecciones:
- MVC separa datos (Model), UI (View) y logica (Controller)
- El Controller es el unico que toca Model y View
- Model notifica cambios a traves de observers
- MVC es simple pero View puede acoplarse al Model
- Para apps modernas, MVVM con data binding es preferible
### MVC vs MVVM: cual uso en frontend?
Usa MVC para apps simples donde la View es estatica y el Controller maneja todo. Usa MVVM (Model-View-ViewModel) para apps con data binding: la View se actualiza automaticamente cuando el ViewModel cambia. React usa un patron similar a MVVM (state + JSX). Angular usa MVVM con Change Detection. Vue usa MVVM con reactivity. MVC es mas comun en backend (Spring MVC, Express MVC).
End of document. Review and update quarterly. Recursos Relacionados
Repository Pattern
Abstract data access logic behind a clean interface. An architectural design pattern for testable, maintainable data layers.
PatternObserver Pattern
Define a subscription mechanism to notify multiple objects about events. A behavioral design pattern for event-driven communication.
GuideREST API Design Guide
A thorough guide to designing clean, scalable, and maintainable REST APIs.
RecipeDependency Injection
Implement dependency injection to write testable, decoupled code across languages and frameworks.
DocADR Template
A reusable template for Architecture Decision Records that capture context, decision, and consequences.
GuideSoftware Architecture Guide
A guide to designing software architecture: monoliths vs microservices, layered architecture, data flow, and technology selection criteria.