liveBook · Manning

Hexagonal architecture

As explained in gRPC Microservices in Go

Hexagonal architecture is an architectural pattern that isolates application business logic behind ports and connects external actors and dependencies through adapters.

Hexagonal architecture structures a microservice so its business logic is not tied to an external interface or dependency. The application core connects through ports, which define contracts; adapters implement those contracts for callers and services such as databases. This ports-and-adapters arrangement helps keep components loosely coupled and testable. section 4.1 section 4.3

An incoming adapter translates an actor’s technology-specific request into a call the application understands. An outgoing adapter translates an application request into an operation on an external dependency. A web or CLI interface can call the core, while a database adapter can persist its data. The core works through port contracts rather than the adapters’ implementation details. section 4.1.4 section 4.2.1

A practical Go project can make these boundaries visible in its folders:

  • application holds the domain model and API that implement core behavior. section 4.2.1
  • ports holds contracts for accessing the core or an external service, such as a database. section 4.2.1
  • adapters holds concrete implementations of those contracts, such as a gRPC request handler. section 4.2.1

Build the application core first, then add outer layers that depend on it. Folder names are a convention, not a rule: application, ports, and adapters may sit under internal, while cmd provides the entry point and wires dependencies such as a database connection into the application. section 4.2.3 section 4.2.1

Placing an order without binding the core to a database

Define an Order domain object and an application API with PlaceOrder. Give the application a ports.DBPort when constructing it; PlaceOrder calls that port to save the order and returns an error if saving fails. A database adapter supplies the concrete implementation, so the application API need not know its internals. section 4.2.3

package api
 
import (
    "github.com/huseyinbabal/microservices/order/internal/application/core/
      domain"                                                    #1
    "github.com/huseyinbabal/microservices/order/internal/ports"   #2
)
 
type Application struct {
    db ports.DBPort                                                #3
}
 
func NewApplication(db ports.DBPort) *Application {
    return &Application{
        db: db,                                                    #4
    }
}
 
func (a Application) PlaceOrder(order domain.Order) (domain.Order, error) {
    err := a.db.Save(&order)                                       #5
    if err != nil {
        return domain.Order{}, err
    }
    return order, nil
}

The Go listing shows constructor injection of DBPort and the PlaceOrder call through that interface, including propagation of a save error. section 4.2.3

How gRPC Microservices in Go covers it

How deep it goes
Defines the pattern and its components, then works through project folders and a Go application core with an injected database port.
Examples
Uses a Go order service whose PlaceOrder method saves an Order through DBPort, alongside gRPC adapter and project-folder examples.
What it assumes
Assumes a Go microservice project context while defining ports, adapters, and their folder responsibilities before implementing the core.
What you can do after
Build it from scratch by defining the application core and port contracts, then injecting concrete adapters into outer layers.
How it connects
Connects ports and adapters to domain models, dependency injection, database persistence, and gRPC interfaces.

Also explained in

Compare how 6 books explain hexagonal architecture →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of gRPC Microservices in Go. The section links point to the parts of the book it draws on.