API-DD

Capítulo del manifiesto

API-Driven Development

Una perspectiva para diseñar las conversaciones entre módulos y consumidores.

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.

  1. Las interacciones importan más que la forma interna. Un módulo se entiende por las conversaciones que ofrece y consume.
  2. El vocabulario forma parte del diseño. Los nombres expresan intenciones, resultados y hechos que otros módulos pueden comprender.
  3. Lo visible crea acoplamiento. La API muestra lo necesario y mantiene reemplazables algoritmos, coordinación y representación.
  4. 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.
  5. 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#

Diseñar la API exige identificar al consumidor, los mensajes que necesita, lo que puede observar y las garantías que deben conservarse. También separa los detalles ocultos y las APIs que el módulo necesita. Esas decisiones 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 | UnsupportedStyle

Formatter 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 promete que un estilo admitido produce texto formateado, uno desconocido devuelve un error distinguible y el original no cambia. La librería utilizada permanece oculta.

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 aplicación mínima de API-DD tiene tres pasos:

  1. Identifica al consumidor y la conversación que necesita.
  2. Fija mensajes y garantías observables, dejando fuera el mecanismo.
  3. Implementa y prueba el contrato; repite el análisis solo si aparece otra relación con contrato propio.

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.