Introducción · Introducción
API-Driven Development: diseñar cada módulo como una API
Del origen del término API a una perspectiva centrada en módulos y conversaciones.
En este capítulo
De dónde viene API#
API abrevia Application Programming Interface. El término es anterior a la Web y su idea central es aún más antigua: permitir que un programa use una capacidad sin depender de cómo está construida.
| Año | Hito | Idea que permanece |
|---|---|---|
| 1951 | Wilkes, Wheeler y Gill describen una biblioteca de subrutinas para EDSAC | El consumidor necesita una forma conocida de invocar comportamiento reutilizable |
| 1968 | Cotton y Greatorex emplean application program interface en un sistema de gráficos remotos | Una interfaz estable puede separar al programa de terminales y mecanismos diferentes |
| 1974 | Date y Codd comparan interfaces de programación para bases de datos | El diseño de la interfaz repercute en el diseño del sistema completo |
La API, por tanto, no nació como sinónimo de endpoint HTTP ni de servicio público. Esos son mecanismos posteriores para expresar una interfaz. También son APIs las funciones de una biblioteca, las llamadas de un sistema operativo o cualquier protocolo que permita colaborar con una capacidad encapsulada.
Cómo lo reinterpreta API-DD#
API-DD conserva esa función histórica de la interfaz: separar al consumidor del mecanismo. La amplía con una idea de Alan Kay: en un sistema capaz de crecer importa más diseñar cómo se comunican sus módulos que fijar sus propiedades internas. Kay situó el intercambio de mensajes en el núcleo de Smalltalk, pero su observación sobre módulos y comunicación puede aplicarse fuera de la orientación a objetos (mensaje original de 1998).
API-DD lleva la API desde el límite exterior de una aplicación hasta cada relación modular que merezca un contrato. La conversación puede ser local o remota y expresarse con funciones, métodos, eventos o HTTP. El mecanismo cambia; la separación entre consumidor e implementación permanece.
Esta es una reinterpretación deliberada, no la afirmación de que API haya significado siempre exactamente lo mismo. De su historia tomamos la separación entre uso e implementación; de Kay, el foco en los mensajes entre módulos. De ahí surge API-Driven Development.
Manifiesto#
El software cambia. Sus contratos permiten que cambie sin obligar a cada consumidor a conocer de nuevo su interior.
- Las interacciones importan más que la forma interna. Un módulo se entiende por las conversaciones que ofrece y consume.
- El vocabulario forma parte del diseño. Los nombres expresan intenciones, resultados y hechos que otros módulos pueden comprender.
- Lo visible crea acoplamiento. La API muestra lo necesario y mantiene reemplazables algoritmos, coordinación y representación.
- La autonomía llega hasta cada resultado. Un módulo completo y válido cumple su contrato sin pedir al consumidor que repare su estado, y entrega resultados que no comparten referencias mutables.
- El contrato puede verificarse desde fuera. Los tests actúan como consumidores y observan resultados, estado o mensajes públicos.
Estos fundamentos pueden aplicarse de forma recursiva cuando un módulo se descompone en otros módulos con contratos propios. API-DD no prescribe una arquitectura, un paradigma ni un orden de trabajo. Ofrece una perspectiva para diseñar las conversaciones que mantienen unido el sistema.
Definición#
API-Driven Development (API-DD) propone diseñar cada módulo como una API: hacer visibles los mensajes que acepta, las garantías que conserva, los detalles que oculta y las APIs que necesita.
El punto de partida no es la clase, la carpeta ni el patrón que vamos a utilizar. Es el contrato mediante el que un módulo colabora con los demás. Antes de resolver su interior, aclaramos qué API ofrece y qué compromisos deben sobrevivir a cualquier implementación correcta. Es una perspectiva de diseño, no una arquitectura ni un conjunto de reglas obligatorias.
En este libro, módulo no significa necesariamente un módulo del lenguaje, un paquete, un servicio desplegable ni un archivo. Es una parte encapsulada del software que otros utilizan mediante un contrato. Según la escala, puede materializarse como un conjunto de funciones, un tipo, un paquete, un proceso o una combinación de ellos.
| Término | Uso en API-DD |
|---|---|
| Módulo | Parte encapsulada del software que ofrece comportamiento a otros |
| Consumidor | Actor, sistema o módulo que depende de ese comportamiento |
| API | Protocolo mediante el que un módulo se relaciona con sus consumidores |
| Mensaje | Petición, respuesta o hecho que cruza esa API |
| Proveedor | Implementación que satisface el contrato |
Una API puede expresarse con funciones, métodos, eventos, endpoints o cualquier otro mecanismo. Lo importante es la conversación, no su sintaxis.
Diseñar la API#
Mirar un módulo como una API vuelve visibles pocas preguntas, pero concretas:
- ¿Quién lo consume y para qué?
- ¿Qué mensajes puede enviarle?
- ¿Qué resultados, errores, estado o efectos puede observar?
- ¿Qué garantías se mantienen entre llamadas?
- ¿Qué detalles deben permanecer ocultos?
- ¿Qué otras APIs consume el módulo?
Estas respuestas forman el contrato. La firma es solo su representación más visible.
Un ejemplo pequeño#
Supongamos un módulo que aplica un estilo a un texto:
Formatter.Format(Text, Style) → FormattedText | UnsupportedStyleFormatter es el módulo y Format es un mensaje de su API. Text, Style, FormattedText y UnsupportedStyle forman el vocabulario del contrato. Conviene precisar qué significan y qué puede hacer el consumidor con ellos, pero no son APIs independientes por el mero hecho de aparecer en la firma.
El contrato puede prometer que:
- un estilo admitido produce un texto formateado;
- un estilo desconocido devuelve un error distinguible;
- el texto original no cambia;
- el resultado no revela la librería utilizada internamente.
El consumidor no necesita conocer si el proveedor usa una plantilla, un árbol intermedio o una librería externa. Esas decisiones pueden cambiar mientras se conserven las garantías.
Ejemplo en Go#
Go puede expresar la conversación mediante una interfaz y un error distinguible.
import "errors"
type Text string
type Style string
type FormattedText string
var ErrUnsupportedStyle = errors.New("unsupported style")
type Formatter interface {
Format(Text, Style) (FormattedText, error)
}La representación podría cambiar mientras Formatter, Format y el significado de ErrUnsupportedStyle conserven el contrato.
Una forma de aplicarlo#
Una secuencia posible para diseñar un cambio con API-DD:
- Identifica los módulos afectados y sus consumidores.
- Describe la conversación que cada consumidor necesita.
- Define mensajes, vocabulario y garantías observables.
- Separa el contrato de las decisiones internas.
- Repite el análisis solo para los módulos internos con relaciones propias.
- Implementa y prueba el contrato sin fijar un recorrido interno innecesario.
API-DD no sustituye el modelado del dominio, la arquitectura ni TDD. Ayuda a concretar cómo colaboran los módulos que esas disciplinas descubren.
API-DD permite mirar cada módulo como una API y conservar libre su implementación.