0% found this document useful (0 votes)
134 views

Hexagonal Budapest 2023 Version

The document discusses the hexagonal architecture pattern, including its benefits of separating an application from external influences and allowing for different technologies to be used over time. It outlines the hexagonal architecture approach of defining interfaces and drivers, and using ports to connect components for testing or production. Sample code examples are provided to illustrate a tax calculator application built using this methodology.

Uploaded by

Jose Antonio
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
134 views

Hexagonal Budapest 2023 Version

The document discusses the hexagonal architecture pattern, including its benefits of separating an application from external influences and allowing for different technologies to be used over time. It outlines the hexagonal architecture approach of defining interfaces and drivers, and using ports to connect components for testing or production. Sample code examples are provided to illustrate a tax calculator application built using this methodology.

Uploaded by

Jose Antonio
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Hexagonal Architecture

( Ports & Adapters )


The 2023 version J

Alistair Cockburn

©Alistair Cockburn 2023


2

Outline

1. What’s the point?


2. Chip component analogy
3. Development sequence
4. Hexagonal Example, w code (Ruby)
5. Required interfaces, w code (Java)
6. Hexagonal example, w code (Java)
7. Juan’s Blue Zone example (Java)
8. Where do I put all the declarations & code?
9. The configurator
10. Costs and Benefits

©Alistair Cockburn 2023


3

What is the point?

Create your application to work without either a UI or a database


so you can run automated regression-tests against it,
work when the database becomes unavailable,
upgrade to new technology, and
link applications together.

©Alistair Cockburn 2023


4

Benefits

1. You get to decide the app’s driven actors at initialization, over a


period of years as technologies shift, or in real time.
2. You get to replace production connections with test harnesses, and
back again, without changing the source code.
3. You get to avoid having to change the source code and then rebuild
the system every time you make these shifts.
4. You can prevent leaks of business logic into the UI or data services,
and vice versa, prevent leaks of UI or data service logic into the
business logic.

©Alistair Cockburn 2023


5

Costs

1. You must add an instance var to hold each driven actor, or get it every
time.
2. You must add a constructor parameter or a setter function for each
driven actor, or a call to the configurator to get it.
3. You must design and add a configurator.
4. (Type-checked languages) You must declare the “required” interfaces.
5. (Type-checked languages) You must add folder structure for the port
declarations.

©Alistair Cockburn 2023


6

Why? When would it have been worth it?

Network tracing program

Network tracing
GUI
system
ow! L

ow! L

Invoicing system

Invoicing SQL
GUI
system database
ow! L

ow! L ow! L

©Alistair Cockburn 2023


7

The app is a “component”

Application

©Alistair Cockburn 2023


8

The app is a component, with ports

Driving ports
Driven ports
For configuring
e:
for thei r purpos
e p o r t s
e th
We nam g_something”. For using For notifying
in
“For_do ion
m u l t i p le funct
ave
rt can h
Each po Application
calls. For getting data

For admin

For getting other data


or
For controlling something

©Alistair Cockburn 2023


9

Hooking up the component for testing

For configuring
Test
harness For using For notifying
Mocked
receivers

Application
For getting
data Test
database
For
admin’ing
For controlling something

Mocked
devices

©Alistair Cockburn 2023


10

Hooking up the component for production

startup

For
configuring
For
using For notifying
GUI 1 actual
receivers

Application
For getting
data Production
GUI 2
database
For
admin’ing
For controlling

actual
devices

©Alistair Cockburn 2023


11

Mho’s weather warning system as components

Tests

weather service telemetry


Test/Mock receiver
For
weather service RSS feed collecting
Analog answering machines
weather
weather service web site information For notifying
subscribers Pagers

Other App(s)
Weather Email
For Warning For getting
admin’ing subscriber data
Tests System Test database

Admin GUI Production database

HTTP access

©Alistair Cockburn 2023


12

Development Sequence:
tests + mocks first

#1
Mock database
Tests
#2
For driving
the app For getting
data

production driver
App
Production database

#3

#4

©Alistair Cockburn 2023


13

Simplest example: tax calculator

For calculating taxes


Tests
“taxRate(amount)” For getting tax rates
“taxOn(amount)”
“taxRate(amount)” Mock tax rate repository

Production driver Tax


Calculator Production tax rate repository

©Alistair Cockburn 2023


14

Code for Tax Calculator (Ruby)


Tests Mock tax rate repository
For calculating taxes Tax
Calculator For getting tax rates
“taxOn(amount)” “taxRate(amount)” class FixedTaxRateRepository
def tax_rate( amount )
0.15
class TaxCalculator end
def initialize( tax_rate_repository ) end
@tax_rate_repository = tax_rate_repository
end
def tax_on( amount )
amount * @tax_rate_repository.tax_rate( amount )
end (Note: no interface
end declarations)

tax_rate_repository = FixedTaxRateRepository.new This is the work of the “configurator”


my_calculator = TaxCalculator.new( tax_rate_repository ) (aka Composition Root)
puts my_calculator.tax_rate( 100 ) This is using the system at the port

©Alistair Cockburn 2023


15

Detour for type-checked languages:


Provided & Required interfaces

B provides services. A “requires” this interface.


A uses them. B implements it.

A B A B

B “implements” the interface. A owns the interface definition.

Useful for defining a public API Useful for decoupling a component from
its receivers

©Alistair Cockburn 2023


16

The source-code dependencies


Driving ports: The app owns the interface Driven ports: The app owns the interface

Driving actor Drivenactor


actor
Driven
or adapter App App ororadapter
adapter
App API App required i/f
(Provided i/f)

Driving actor
or adapter App provided i/f App App required i/f

App
Driven actor
Driven actor
or adapter
or adapter

©Alistair Cockburn 2023


17

What a required interface looks like in code (Java)


For getting tax rates
“taxRate(amount)”
taxCalculator FixedTaxRateRepository

interface ForGettingTaxRates { Make sure the required interface’s


double taxRate(double amount); } definition belongs to the calculator,
not to the repository!

class TaxCalculator {
private ForGettingTaxRates taxRateRepository;
class FixedTaxRateRepository
public TaxCalculator(ForGettingTaxRates taxRateRepository) { implements ForGettingTaxRates {
this.taxRateRepository = taxRateRepository; public double taxRate(double amount) {
} return 0.15; }
}
public double taxOn(double amount) {
return amount * taxRateRepository. taxRate( amount );
}
}

©Alistair Cockburn 2023


18
Code for Tax Calculator (Java)
Main Mock tax rate repository
For calculating taxes Tax For getting tax rates
“taxOn(amount)” Calculator
“taxRate(amount)”
class FixedTaxRateRepository
implements ForGettingTaxRates {
interface ForCalculatingTaxes {
double taxOn(double amount); public double taxRate(double amount) {
return 0.15;
}
interface ForGettingTaxRates { }
double taxRate(double amount); }
}
class TaxCalculator implements ForCalculatingTaxes {
private ForGettingTaxRates taxRateRepository;
public TaxCalculator(ForGettingTaxRates taxRateRepository) {
this.taxRateRepository = taxRateRepository;
}
public double taxOn(double amount) {
return amount * taxRateRepository. taxRate( amount );
}
}
class Main {
public static void main(String[] args) {
ForGettingTaxRates taxRateRepository = new FixedTaxRateRepository(); the “configurator”
TaxCalculator myCalculator = new TaxCalculator( taxRateRepository );
System.out.println( myCalculator.taxOn( 100 ) ); using the system at the port
}
©Alistair Cockburn 2023
19

A more complex example: Juan’s “Blue Zone”


BlueZone allows car drivers to pay remotely for parking cars at zones in a city,
instead of paying with coins using parking meters

Juan Manuel Garrido de Paz:


https://github.com/jmgarridopaz/bluezone ©Alistair Cockburn 2023
20

Juan’s “Blue Zone” example


BlueZone allows car drivers to pay remotely for parking cars at zones in a city,
instead of paying with coins using parking meters

Juan Manuel Garrido de Paz:


https://github.com/jmgarridopaz/bluezone ©Alistair Cockburn 2023
21

Juan’s “Blue Zone” example


BlueZone allows car drivers to pay remotely for parking cars at zones in a city,
instead of paying with coins using parking meters

Car web ui
Driver adapter

For
tests in Cucumber parking
cars For obtaining
rates Test Double
For configuring
BlueZone
File adapter
Blue
tests in TestNG
Zone For storing
tickets
Test Double

For DB adapter
Parking CLI checking
cars For paying
Inspector adapter
Test Double

Wallet Adapter

Juan Manuel Garrido de Paz:


https://github.com/jmgarridopaz/bluezone ©Alistair Cockburn 2023
22

Juan’s “Blue Zone” example


Ports https://github.com/jmgarridopaz/bluezone

Adapters

©Alistair Cockburn 2023


23

The folders: Port declarations and Adapters

Port declaration folders Adapter folders


in the app outside the app

©Alistair Cockburn 2023


24

How do we design the configurator?

configurator
configurator

mock repo A
App

repo B

repo C

©Alistair Cockburn 2023


25

Configurator design #1: setter method


(Dependency Injection)

set
tax rate
repository
tax test
Main or calculator tax rate repository
test case
get get
tax tax rate production
tax rate repository

©Alistair Cockburn 2023


26

Configurator design #2: repository broker


(Dependency Lookup)

get
test
set tax rate rate repository broker
tax rate repository
repository
broker production
tax rate repository broker
main or calculator
test case
get test
tax
tax rate repository

get
tax rate
repository for country A

repository for country B

©Alistair Cockburn 2023


27

Benefits

1. You get to set the app’s driven actors during execution --


at initialization, over a period of years as technologies shift,
or in real time.
2. You get to replace production connections with test harnesses, and
back again, without changing the source code.
3. You get to avoid having to change the source code and then rebuild
the system every time you make these shifts.
4. You can prevent leaks of business logic into the UI or data services,
and vice versa, prevent leaks of UI or data service logic into the
business logic.
©Alistair Cockburn 2023
28

Costs

1. You must add an instance var to hold each driven actor, or get it every
time.
2. You must add a constructor parameter or a setter function for each
driven actor, or a call to the configurator to get it.
3. You must design and add a configurator.
4. (Type-checked languages) You must declare the “required” interfaces.
5. (Type-checked languages) You must add folder structure for the port
declarations.

©Alistair Cockburn 2023


29

Ports & Adapters Pattern


(aka Hexagonal Architecture)
Create your application to work without either a UI or a database
so you can run automated regression-tests against the application,
work when the database becomes unavailable,
upgrade to new technology, and
link applications together. Tests
weather service
Test/Mock receiver
telemetry For
weather service RSS collecting
feed For Analog answering
weather service web site weather notifying machines
informati subscribers Pagers
on
Other App(s)
Weather Email
For getting
With many thanks to For Warning subscriber
admin’ing
Juan Manuel Garrido de Paz data
Tests System Test database
for continual close reading,
Admin Production database
exactness, and code.
GUI
HTTP access

©Alistair Cockburn 2023

You might also like