Del monolito a los microservicios
Decida qué dividir y cómo definir los límites de los servicios
Del monolito a los microservicios es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.
Del monolito a los microservicios
Los microservicios son una apuesta organizativa y operativa, no una opción predeterminada. Dividir un monolito PHP sustituye la simplicidad dentro del proceso por llamadas de red, datos distribuidos y complejidad de despliegue. Si se hace por los motivos equivocados, todo se vuelve más lento.
Esta lección trata sobre la parte más difícil: delimitar los servicios. Si define bien las uniones, lo demás es infraestructura; si las define mal, construirá un monolito distribuido: todo el coste y ninguna de las ventajas.
Por qué dividir y por qué no hacerlo
Buenos motivos para dividir:
- Desplegabilidad y responsabilidad de los equipos independientes.
- Escalado independiente de los subsistemas con mayor carga.
- Aislamiento de tecnologías y runtimes, además de contención de fallos.
Malos motivos: «el código está desordenado» (primero refactorice el monolito) o perseguir una tendencia. Si dos servicios siempre deben desplegarse juntos o compartir una tabla de base de datos, son un solo servicio con dos funciones.
Contextos delimitados
El Domain-Driven Design proporciona la herramienta más precisa para delimitar fronteras: el contexto delimitado. Dentro de un contexto, los términos tienen un único significado preciso. «Cliente» en Facturación (el destinatario de una factura) es diferente de «Cliente» en Soporte (el autor de un ticket).
Cada contexto delimitado es un candidato sólido para convertirse en un servicio. Las fronteras siguen el lenguaje del negocio y la forma en que la organización se comunica realmente: la ley de Conway en acción.
Alta cohesión, bajo acoplamiento
Una buena frontera de servicio mantiene dentro las cosas que cambian juntas y deja fuera las que cambian de forma independiente. Evalúe una posible división según:
- ¿Cuántas funcionalidades requieren tocar dos servicios a la vez? (Deberían ser pocas).
- ¿Qué tan verboso es el patrón de llamadas entre ellos? (Debería ser de grano grueso).
Si implementar una funcionalidad implica atravesar constantemente una frontera, la frontera está en el lugar equivocado.
<?php
// Chatty boundary smell: N network calls to render one view
foreach ($order->lineItems as $item) {
$product = $catalogApi->get($item->productId); // one call PER item!
$names[] = $product['name'];
}
// Coarse-grained: one batch call across the boundary
$ids = array_map(fn($i) => $i->productId, $order->lineItems);
$names = $catalogApi->getMany($ids); // single round-trip
echo count($names) . " products in one call\n";Una base de datos por servicio
La regla innegociable: cada servicio es propietario de sus datos y ningún otro servicio accede a sus tablas. Las bases de datos compartidas recrean el acoplamiento que intentaba eliminar al dividir el sistema; un cambio de esquema rompe servicios no relacionados.
Esto significa que las consultas entre servicios que en el monolito eran un SQL JOIN se convierten en llamadas a API o modelos de lectura replicados. Ese es el precio, y precisamente ese es el objetivo.
<?php
// In the monolith: one JOIN across domains
$sql = 'SELECT o.id, c.email
FROM orders o JOIN customers c ON c.id = o.customer_id';
// After split: Orders service holds only the foreign id;
// it asks the Customers service for the rest (or keeps a local read model).
$order = $orderRepo->find($id); // local
$customer = $customersApi->get($order->customerId); // network call
echo $order->id . ' / ' . $customer->email . "\n";El patrón Strangler Fig
Nunca reescriba un monolito de una sola vez. El patrón Strangler Fig extrae funcionalidades de forma incremental: dirija una parte del tráfico a un servicio nuevo mediante una fachada o un proxy, amplíelo y retire la ruta de código antigua solo cuando la nueva la cubra por completo.
Un proxy inverso (o una API gateway) se sitúa delante y decide, para cada ruta, si debe dirigirse al monolito heredado o al servicio nuevo. La migración avanza una capacidad cada vez y siempre se puede desplegar.
<?php
// Facade routing: peel off one capability at a time
function route(string $path): string {
$migrated = ['/invoices', '/invoices/pdf']; // moved to billing-svc
foreach ($migrated as $prefix) {
if (str_starts_with($path, $prefix)) {
return 'http://billing-svc' . $path;
}
}
return 'http://legacy-monolith' . $path; // everything else, for now
}
echo route('/invoices/pdf'), "\n";
echo route('/users/42'), "\n";Extraer un módulo
Un orden de extracción práctico:
- Encuentre un módulo con pocas dependencias entrantes y una propiedad clara de los datos.
- En primer lugar, envuelva sus llamadas dentro del proceso detrás de una interfaz en el monolito.
- Mueva los datos de los que es propietario a su propio esquema o base de datos.
- Sustituya la implementación de la interfaz por un cliente de red.
- Cambie el tráfico mediante la fachada y elimine el código antiguo.
Envolver primero la interfaz dentro del monolito reduce el riesgo del paso a la red.
<?php
// Step 2: hide the implementation behind a port the monolith calls
interface InvoiceService {
public function generate(string $orderId): string; // returns invoice id
}
// Today: local class. Tomorrow: HTTP client to billing-svc.
// The monolith's calling code never changes.
final class LocalInvoiceService implements InvoiceService {
public function generate(string $orderId): string { return 'inv-1'; }
}Consistencia de datos distribuidos
Una vez divididos los datos, se pierden las transacciones ACID entre servicios. Adopte la consistencia eventual: los servicios publican eventos sobre sus propios datos y los demás construyen modelos de lectura locales a partir de esos eventos.
El servicio Orders no consulta Customers en cada solicitud; mantiene una proyección pequeña (solo los campos que necesita), actualizada mediante eventos CustomerUpdated. Esto elimina una dependencia en tiempo de ejecución y un salto de latencia.
<?php
// Orders service keeps a tiny local projection of customer data
function onCustomerUpdated(PDO $db, array $evt): void {
$db->prepare(
'INSERT INTO customer_read_model (id, email)
VALUES (:id, :email)
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email'
)->execute(['id' => $evt['id'], 'email' => $evt['email']]);
}Realidad operativa
Los microservicios trasladan la complejidad del código a las operaciones. Antes de dividir el sistema, necesita:
- Registros centralizados y trazabilidad distribuida (identificadores de correlación entre saltos).
- CI/CD por servicio y despliegues independientes con versiones.
- Comprobaciones de estado, tiempos de espera, reintentos y circuit breakers en cada llamada.
- Pruebas de contrato para que un proveedor no pueda romper silenciosamente a un consumidor.
Si su equipo no puede operar bien un servicio, operar diez será diez veces peor.
Dimensionamiento adecuado de los servicios
«Micro» puede inducir a error: dimensione los servicios según la capacidad de negocio y la responsabilidad del equipo, no según las líneas de código. Si son demasiado granulares (nanoservicios), una sola funcionalidad se dispersa en una avalancha de llamadas de red; si son demasiado grandes, volverá a tener un monolito.
Una regla práctica saludable: un servicio debe poder ser gestionado por un solo equipo, desplegarse por separado y satisfacer sus casos de uso principales sin una cadena síncrona que atraviese muchos servicios pares.
La alternativa del monolito modular
Antes de pasar a un sistema distribuido, considere el monolito modular: un único artefacto desplegable, dividido internamente en módulos con fronteras explícitas y sus propios esquemas, que se comunican únicamente mediante interfaces publicadas; no hay acceso a tablas de otros módulos.
Obtiene fronteras limpias y refactorización sencilla sin pagar el coste de los sistemas distribuidos. Cuando un módulo realmente necesita escalarse o tener una responsabilidad independiente, ya está preparado para extraerse mediante el patrón Strangler Fig. Para la mayoría de los equipos, este es el primer paso adecuado.
<?php
// Modules talk only through interfaces, never each other's tables.
namespace App\Billing; // owns billing_* tables
interface BillingFacade {
public function invoiceForOrder(string $orderId): string;
}
namespace App\Sales; // owns sales_* tables
final class Checkout {
public function __construct(private \App\Billing\BillingFacade $billing) {}
// Sales never SELECTs from billing_* directly - only via the facade.
}Comprobación rápida
Reconocer una división incorrecta.
Resumen
Delimitar bien los servicios:
- Divida por desplegabilidad, escalado y responsabilidad, no porque el código esté desordenado.
- Alinee las fronteras con los contextos delimitados; busque alta cohesión y bajo acoplamiento.
- Una base de datos por servicio: no comparta tablas; sustituya los JOIN por API o modelos de lectura.
- Realice la migración de forma incremental mediante el patrón Strangler Fig.
- Acepte la consistencia eventual e invierta en operaciones antes de escalar horizontalmente.
A continuación: cómo se comunican realmente esos servicios: REST y gRPC.
Preguntas frecuentes
¿La lección «Del monolito a los microservicios» es gratis?
Sí — el texto completo de «Del monolito a los microservicios» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Del monolito a los microservicios»?
Decida qué dividir y cómo definir los límites de los servicios Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar PHP Academy?
No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Del monolito a los microservicios»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de PHP Academy?
Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Del monolito a los microservicios
- Comunicación entre servicios: REST y gRPC
- Puertas de enlace de API y descubrimiento de servicios
- Resiliencia: circuit breakers y reintentos