Microkernel

Qué organiza

Microkernel, como patrón de aplicaciones, organiza capacidades alrededor de un núcleo relativamente pequeño y estable que extensiones conectadas mediante contratos pueden ampliar. El núcleo conserva lo esencial para operar; los plugins aportan procesamiento especializado o funcionalidades seleccionables. Mark Richards describe esta estructura y también usa el nombre plug-in architecture en Software Architecture Patterns, capítulo Microkernel.

Aquí Microkernel no designa el microkernel de un sistema operativo. Ese uso organiza servicios del OS respecto de su kernel; compartir el término no exige implementar un kernel de OS ni heredar sus garantías de aislamiento. Este canonical se limita al patrón arquitectónico de software de aplicación.

Qué pertenece al core

«Pequeño» expresa una decisión sobre responsabilidades, no un umbral de líneas. El núcleo puede contener coordinación, contratos de extensión, registro de capacidades y políticas comunes que deben conservarse al agregar comportamiento.

En este ejemplo propio, una aplicación de revisión documental ofrece un flujo de recepción, evaluación y publicación de resultados. Su núcleo conserva identidad de la revisión, estados válidos, autoridad para aprobar y registro de qué verificaciones se ejecutaron. Extensiones aportan validadores de formatos, comprobaciones especializadas y exportadores.

Colaboraciones conceptuales, no aislamiento de procesos:
 
Format validator ─┐
Policy checker  ──┼── Core de revisión
Report exporter ──┘

Un core que incorpora cada excepción de cada formato acaba cambiando con todas las extensiones. Uno que solo llama código externo sin conservar estados, errores o autoridad obliga a los plugins a inventar coordinación y a conocer detalles de sus vecinos. El límite se elige según qué invariantes deben ser comunes y qué comportamiento necesita variar.

El núcleo no tiene que ser trivial: debe ser suficientemente completo para sostener las obligaciones que promete. «Todo es plugin» puede dejar escondida la política esencial entre extensiones cuyo orden accidental decide el resultado.

Extension points y contratos

En nuestro ejemplo, un extension point permite evaluar un documento y producir observaciones estructuradas. Otro permite exportar una revisión terminada. No son la misma interacción: necesitan entradas, resultados, errores y condiciones de ejecución diferentes.

El contrato define más que una firma. Debe aclarar qué puede modificar la extensión, cuándo se la invoca, si puede ejecutar varias veces y qué sucede si no está disponible. Una validación opcional puede omitirse con un resultado explícito; una comprobación obligatoria para cierto flujo no puede desaparecer silenciosamente.

La descripción del modelo de plugins de Eclipse distingue relaciones de dependencia y de extensión. El ejemplo ilustra por qué agregar capacidades no equivale simplemente a importar una biblioteca: un host reconoce una contribución a un punto que controla.

En una variante con contratos compartidos, plugins y core conocen esos contratos; el núcleo evita depender de la implementación de cada extensión. La relación runtime core→plugin no implica importar el tipo concreto de todos los plugins. Un registro y un punto de composición pueden seleccionar implementaciones.

Discovery, registration y lifecycle

Discovery identifica extensiones candidatas; registration declara qué capacidades ofrecen. Loading pone su código o artefactos disponibles; activation prepara la extensión para cumplir su función. Es posible conocer contribuciones sin activar toda su implementación.

Para la aplicación del ejemplo, el registro puede incluir identidad, versión de contrato, formatos atendidos y dependencias requeridas. El host debe decidir si admite dos validadores del mismo formato y qué orden o selección aplica. «Encontrar todos los archivos de una carpeta» no resuelve esas decisiones.

El lifecycle también incluye desactivación y liberación de recursos. Si una extensión conserva tareas en vuelo, deshabilitarla requiere decidir si terminan, se cancelan o impiden el cierre. No se deduce hot loading, unloading seguro ni actualización sin reinicio por usar este patrón.

Las funciones pueden ser opcionales en la distribución del producto y obligatorias en una configuración particular. Conviene distinguir «no instalado», «incompatible», «desactivado» y «falló»: todos pueden impedir una capacidad, pero exigen respuestas diferentes.

Estabilidad y evolución

Un core estable tiene contratos que evolucionan deliberadamente, no un compromiso de nunca cambiar. Si el host introduce una nueva callback obligatoria, plugins existentes pueden no implementar la nueva obligación aunque su comportamiento anterior siga siendo útil.

Versiones declaradas, rangos compatibles, adaptadores de transición y negociación de capacidades permiten explicitar qué combinaciones se aceptan. El documento plugin-architecture profundiza API evolution, compatibilidad source/binary y lifecycle. Un número de versión no prueba que las implementaciones respeten las mismas semánticas.

En nuestro ejemplo, agregar información opcional al resultado no equivale a cambiar «sin observaciones» de aprobación a resultado desconocido. Ese cambio semántico puede afectar decisiones del core sin cambiar la forma de los datos. Las pruebas de contrato deberían ejercitar plugins antiguos con el host nuevo y los estados que requieren decisiones de negocio.

Aislamiento y failure containment

Una frontera lógica separa responsabilidades; no reserva automáticamente CPU o memoria. Un plugin in-process puede bloquear al host, consumir recursos, lanzar excepciones o acceder a recursos compartidos. Microsoft advierte que un contexto de carga de assemblies no permite ejecutar código no confiable con seguridad dentro de un proceso .NET confiable en su guía de plugin support.

En nuestro ejemplo, capturar una excepción puede recuperar un fallo controlado, pero no deshacer corrupción compartida ni rescatar un proceso que agotó memoria. Pools y límites por extensión, como bulkhead, pueden proteger ciertos recursos. Procesos separados con controles adecuados pueden contener otros fallos, a cambio de comunicación, supervisión y operación.

blast-radius ayuda a revisar qué sigue compartido. Ejecutar todos los plugins dentro de un único proceso auxiliar puede proteger la UI y conservar propagación entre extensiones. Ninguna de esas elecciones garantiza por sí sola una frontera de seguridad: autoridad y permisos deben aplicarse efectivamente.

Deployment, composición y límites

Un producto puede entregar core y plugins juntos, distribuir extensiones por separado o invocarlas mediante procesos o servicios externos. Extensibilidad no implica deployment independiente: compatibilidad, dependencias y rollback deben comprobarse para la topología elegida.

Un modular-monolith puede tener un kernel y módulos extensibles de reporting; no todos sus módulos son plugins. Modular Monolith enfatiza límites modulares en una entrega común; Microkernel enfatiza núcleo estable y ampliación por contratos. Ambos pueden describir decisiones compatibles del mismo sistema.

También puede existir un subsistema Microkernel dentro de una aplicación layered-architecture. El patrón no decide todos los ejes de un architecture-profile. En internal-structure, compararlo con Plugin Architecture permite conservar la superposición terminológica sin declarar identidad universal.

Es útil cuando variantes reales necesitan extender capacidades sin modificar continuamente la política común. Resulta costoso cuando las supuestas extensiones cambian siempre junto al core, dependen íntimamente entre sí o exigen contratos generales antes de tener usos concretos. La revisión debe identificar qué cambio quedará localizado y qué garantía mantendrá el núcleo.