Apariencia
🎤 Preguntas de entrevista — Python para Backend
Preguntas típicas de examen/entrevista relacionadas a los temas del curso, con respuesta corta para repasar rápido.
Comunicación entre microservicios (Clase 7)
1. ¿Qué opción genera menos acoplamiento entre orders_service y products_service?
A.
from products.models import ProductB. Consultar Products DB C.GET /api/v1/products/{id}D. Copiar Products Service dentro de Orders
| Alternativa | Qué es realmente | ¿Por qué sí / no? |
|---|---|---|
A. from products.models import Product | Importar directamente la clase de modelo (ORM) del OTRO servicio en el propio código. | ❌ Acoplamiento fuertísimo: para que compile, orders_service necesitaría acceso al código fuente de products_service en el mismo proceso — deja de ser un microservicio independiente y pasa a ser un monolito con carpetas. Un cambio en el modelo Product rompe orders_service en tiempo de importación. |
| B. Consultar Products DB | Conectarse directo a la base de datos de products_service desde orders_service. | ❌ Rompe el principio "database per service" (visto en Clase 5/Clase 6): cada servicio es dueño de su base y nadie más la toca directo. Acopla a orders_service al esquema físico de tablas de products_service — si ese esquema cambia, orders_service se rompe sin haber tocado su propio código. |
C. GET /api/v1/products/{id} | Llamar al endpoint REST público de products_service — exactamente lo que hace get_product() en app/clients/products_client.py (Clase 7). | ✅ Es la respuesta correcta: la comunicación pasa por un contrato (la API), no por detalles internos. products_service puede cambiar su modelo, su base de datos o hasta su lenguaje por dentro, y mientras el contrato del endpoint no cambie, orders_service sigue funcionando igual. |
| D. Copiar Products Service dentro de Orders | Duplicar el código completo de products_service dentro de orders_service. | ❌ Es la peor opción: no reduce el acoplamiento, lo cambia por duplicación — quedan dos copias de la misma lógica que hay que mantener sincronizadas a mano para siempre; cualquier fix de negocio en productos hay que aplicarlo dos veces. |
💡 La idea de fondo: acoplamiento no es "cuánto código comparten dos servicios", es "cuánto tiene que cambiar A si cambia B por dentro". Un contrato HTTP (opción C) es el punto de acoplamiento más débil posible entre dos servicios — justo lo que implementa
app/clients/products_client.pyen el proyecto de la Clase 7.
🧪 Variante típica de esta pregunta: te la pueden reformular como "¿cuál es la ventaja principal de comunicarse por REST/API en vez de compartir base de datos entre microservicios?" — la respuesta apunta a lo mismo: cada servicio expone un contrato estable y oculta su implementación interna (su modelo, su esquema, su lenguaje).
2. Clasificar: ¿cada responsabilidad es del Gateway o de un microservicio?
Routing · Correlation ID · Calcular total de pedido · Regla de stock · Validar token · Crear producto
| Responsabilidad | ¿Es del Gateway? | Por qué |
|---|---|---|
| Routing | ✅ Sí | Es literalmente la función proxy() de api_gateway/app/main.py: decide a qué base_url (users_url, products_url, orders_url) reenviar según la ruta que llegó. |
| Correlation ID | ✅ Sí | Lo genera y propaga correlation_id_middleware: si el request no trae X-Correlation-ID, el gateway lo crea con uuid4() — nace ahí, no en los microservicios. |
| Calcular total de pedido | ❌ No — orders_service | Es OrderService.create() (unit_price = Decimal(...); total = unit_price * data.quantity): una regla de negocio de pedidos, no de ruteo. |
| Regla de stock | ❌ No — orders_service | También en OrderService.create() (if stock < quantity: raise HTTPException(409, ...)): decide si SE PUEDE crear el pedido, es negocio puro. |
| Validar token | ✅ Sí — Gateway (conceptualmente) | Verificar que el JWT sea válido (firma correcta, no expirado) es un chequeo transversal a todas las rutas protegidas — igual que el correlation ID, no depende del dominio de negocio de ningún servicio en particular. Al validarlo en el gateway, una petición con token inválido se rechaza ahí mismo, sin gastar recursos de users_service/products_service/orders_service procesándola. |
| Crear producto | ❌ No — products_service | El gateway reenvía el POST /api/v1/products, pero quien de verdad inserta el producto es products_service — el gateway no "crea" nada, solo entrega la petición. |
⚠️ Ojo con la sutileza: validar el token (¿es un JWT válido, con firma correcta y no vencido?) es del Gateway. Validar el rol/permiso (¿ESTE usuario puede ver ESTE pedido puntual?) sigue siendo de cada microservicio — es exactamente lo que hace
OrderService.get_authorized()conuser["role"] != "admin"en la Clase 7. El gateway confirma "sos quien decís ser"; el microservicio decide "¿podés hacer ESTO en particular?".
💡 Regla general para clasificar cualquier responsabilidad nueva: si es routing, trazabilidad (correlation ID) o un chequeo de seguridad transversal (¿el token es válido?) → es del Gateway. Si es una regla, un cálculo o una decisión de negocio (incluido "¿este usuario puntual puede hacer esto?") → es del microservicio dueño de ese dominio. Es la misma idea que "el gateway es un traductor, no tiene lógica de negocio" — ver Clase 7 → API Gateway Pattern.
📝 Actualización con el código real: ya se vio
users_service/app/security.py(Clase 7 → sección 4) y ahí es donde realmente viveget_current_user()(eljwt.decodeque valida firma y expiración) — NO enapi_gateway. Elproxy()del gateway, tal como está hoy, solo reenvía el headerAuthorizationsin tocarlo. Es decir: la respuesta "Validar token = Gateway" es la correcta a nivel conceptual/de diseño (y la que dio el profe), pero el código de ESTE proyecto puntual todavía no la implementa así — quien de verdad valida el JWT esusers_service, el dueño del secreto (settings.jwt_secret). Vale la pena tenerlo claro para no memorizar "el gateway valida tokens" como un hecho de este código específico, sino como el ideal hacia el que apunta el patrón.
3. Clasificar: ¿cada situación es Autenticación o Autorización?
Verificar usuario y contraseña · Comprobar rol ADMIN · Validar token · Decidir si puede eliminar
| Situación | ¿Autenticación o Autorización? | Por qué |
|---|---|---|
| Verificar usuario y contraseña | 🔑 Autenticación | Confirma la identidad: "¿sos quien decís ser?" — verify_password() en POST /auth/login. |
| Comprobar rol ADMIN | 🔒 Autorización | Ya se sabe quién es (viene de un token válido); ahora se decide qué le está permitido hacer según su rol. |
| Validar token | 🔑 Autenticación | El JWT es la prueba de identidad en cada request posterior al login — get_current_user() decodificando el token es re-confirmar "sos quien decís ser", no decidir permisos. |
| Decidir si puede eliminar | 🔒 Autorización | Es una decisión de permiso sobre UNA acción puntual — el mismo patrón que OrderService.get_authorized() con user["role"] != "admin". |
💡 Regla mnemotécnica: Autenticación = identidad (login, password, "¿el token es válido?"). Autorización = permisos (rol, "¿puede hacer ESTO?"). Siempre pasa primero la autenticación — no tiene sentido preguntar "¿puede eliminar?" de alguien cuya identidad ni se confirmó todavía.
🧪 Variante típica: en inglés se abrevian AuthN (autenticación) y AuthZ (autorización) — útil para no confundirlas en documentación en inglés.