What is Hexagonal Architecture?
Hexagonal Architecture = Ports and Adapters (Alistair Cockburn).
A software architecture pattern that decouples your application core from external concerns—databases, APIs, UIs, frameworks—by defining narrow interface boundaries called ports and interchangeable implementations called adapters.
Why "Hexagonal"?
The visual metaphor. The application sits at the center of a hexagon; each flat side exposes a Port (interface contract) without preference for "left" (UI) vs. "right" (database) vs. "top" (external service). The symmetry emphasizes that all dependencies are equivalent—no "primary" vs. "secondary" distinction as in layered architecture.
The Anatomy
Port
An interface—the what. Defines "I need append-only storage with offset tracking" without specifying Kafka, PostgreSQL, or S3. In BSFG: StoreBuffer, ForwardBuffer, CursorTracker interfaces.
Adapter
The implementation—the how. Satisfies the port using concrete technology. In BSFG: Kafka adapter, PostgreSQL adapter, S3 adapter, Redis adapter.
Application Core
Your BSFG logic (handoff protocol, cursor advancement). It knows only the Ports, never the Adapters. This isolation enables testing without infrastructure and deployment flexibility.
Hexagonal in BSFG
Your four buffers (ISB, IFB, ESB, EFB) are Ports (abstract contracts). The "Fast swappability" objective requires that swapping PostgreSQL for Kafka (or SQLite for S3) means changing only the Adapter outside the hexagon, not the core logic inside.
Visual Model
Producer"] subgraph CORE ["BSFG CORE LOGIC"] Handoff["Handoff Protocol
Cursor Advancement"] end subgraph ISBPort ["Port: ISB
(interface)"] ISBSpec["append()
truncateBefore()
replay()"] end subgraph IFBPort ["Port: IFB
(interface)"] IFBSpec["putIfAbsent()
get()
queryByTimeRange()"] end subgraph KafkaAdapt ["Kafka
Adapter"] KA["append log"] end subgraph PGAdapt ["PostgreSQL
Adapter"] PA["table+offset"] end subgraph RedisAdapt ["Redis
Adapter"] RA["SET NX"] end subgraph S3Adapt ["S3
Adapter"] SA["conditional PUT"] end OPC -->|produce| CORE CORE -->|via| ISBPort CORE -->|via| IFBPort ISBPort -->|implements| KafkaAdapt ISBPort -->|implements| PGAdapt IFBPort -->|implements| RedisAdapt IFBPort -->|implements| S3Adapt KafkaAdapt -->|concrete| Consumer["Consumer Apps"] RedisAdapt -->|concrete| Consumer
The hexagon is the boundary; the ports are the flat edges where external concerns plug in without the core knowing which specific technology is outside.
Benefits Applied to BSFG
Testability: Mock the ports. No need for a running Kafka or PostgreSQL to test the handoff protocol.
- Write tests against the
StoreBufferinterface; inject a simple in-memory adapter - Verify cursor advancement logic without any external system
Deployment Flexibility: Choose backends for each buffer independently. Use Redis for IFB in dev, PostgreSQL in production.
- Different cost/performance tradeoffs per environment
- Swap without recompiling or changing protocol logic
Fast Swappability: A new backend technology? Implement the StoreBuffer interface and wire it in.
- No need to redesign the handoff protocol
- Emerging technologies can be integrated without architecture disruption
Resilience: If your ISB adapter (e.g., Kafka) fails, you can:
- Switch to a different backend without modifying BSFG core logic
- Maintain data consistency and protocol guarantees
Clarity: The architecture explicitly documents dependencies.
- "We need something that can append and replay"—that's the port contract
- Technology choices are isolated decisions, not entangled with business logic
Application to BSFG Interfaces
BSFG defines three narrow ports:
StoreBuffer: Append-only log. Adapters: Kafka, PostgreSQL, S3, filesystem.ForwardBuffer: Idempotent staging with atomic insert-if-absent. Adapters: Redis, PostgreSQL, etcd, S3.CursorTracker: State management for acknowledgment frontier. Adapters: etcd, PostgreSQL, S3 metadata.
By defining these contracts, BSFG achieves maximum flexibility: the same core protocol runs against any combination of backends. The application cares about the guarantees (append, idempotency, durability), not the technology.
Key Insight
Hexagonal architecture is not just about swapping databases. It's about decoupling concerns. BSFG's handoff protocol is independent of whether you store in Kafka or PostgreSQL. The protocol is the core; the storage is an implementation detail. This separation makes BSFG maintainable, testable, and adaptable to future requirements without redesign.