Model Tension
Heuristics
Preventing Accidental Design Debt
@julientopcu.com

@josianchevalier.bsky.social















CHAPTER I
When model exploration
Whirlpool
turns into model sinking
TODo
Current Quest
Done

Overlapping ships can be selected
Bug

[Paid Option] Wireless pidgin connexion
Feature
JIRA



Ships departing in the past appear in the Search

Bug

Add cancellation insurance

Feature
TODo
Current Quest
Done

Overlapping ships can be selected
Bug

[Paid Option] Wireless pidgin connexion
Feature
JIRA




Bug

Add cancellation insurance

Feature
Ships departing in the past appear in the Search

{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW", "LOUNGE" ],
"deckOptions": [ "ANY", "UPPER_DECK", "MIDDLE_DECK", "LOWER_DECK" ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
},
{
"comfortClass" : "SECOND",
"price": "50€",
"seatOptions": [ "ANY", "AISLE", "WINDOW" ],
"deckOptions": [ "ANY", "MIDDLE_DECK", "LOWER_DECK" ],
"selected": false,
"booked" : false
}
]
},
{
"number": "B",
"bound": "outbound",
"departureDate": "2025-10-06T15:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "80€",
"selected": false,
"booked" : false
}
]
},
{
"number": "C",
"bound": "inbound",
"departureDate": "2025-10-16T12:00",
"fares": [
{
"comfortClass" : "FIRST",
"price": "90€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW" ],
"deckOptions": [ "ANY", "UPPER_DECK", "LOWER_DECK" ],
"preferences": {
"seat": "PANORAMIC_VIEW",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked": true
}
]
},
{
"number": "D",
"bound": "inbound",
"departureDate": "2025-10-16T14:00",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW" ],
"deckOptions": [ "ANY", "UPPER_DECK", "LOWER_DECK" ],
"selected": false,
"booked" : false
},
{
"comfortClass" : "SECOND",
"price": "50€",
"seatOptions": [ "ANY", "AISLE", "WINDOW" ],
"deckOptions": [ "ANY", "LOWER_DECK" ],
"selected": false,
"booked" : false
}
]
}
]
}
}



{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW", "LOUNGE" ],
"deckOptions": [ "ANY", "UPPER_DECK", "MIDDLE_DECK", "LOWER_DECK" ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
},
{
"comfortClass" : "SECOND",
"price": "50€",
"seatOptions": [ "ANY", "AISLE", "WINDOW" ],
"deckOptions": [ "ANY", "MIDDLE_DECK", "LOWER_DECK" ],
"selected": false,
"booked" : false
}
]
},
{
"number": "B",
"bound": "outbound",
"departureDate": "2025-10-06T15:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "80€",
"selected": false,
"booked" : false
}
]
},
{
"number": "C",
"bound": "inbound",
"departureDate": "2025-10-16T12:00",
"fares": [
{
"comfortClass" : "FIRST",
"price": "90€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW" ],
"deckOptions": [ "ANY", "UPPER_DECK", "LOWER_DECK" ],
"preferences": {
"seat": "PANORAMIC_VIEW",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked": true
}
]
},
{
"number": "D",
"bound": "inbound",
"departureDate": "2025-10-16T14:00",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "AISLE", "WINDOW", "PANORAMIC_VIEW" ],
"deckOptions": [ "ANY", "UPPER_DECK", "LOWER_DECK" ],
"selected": false,
"booked" : false
},
{
"comfortClass" : "SECOND",
"price": "50€",
"seatOptions": [ "ANY", "AISLE", "WINDOW" ],
"deckOptions": [ "ANY", "LOWER_DECK" ],
"selected": false,
"booked" : false
}
]
}
]
}
}






public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships) {
public Search {
+ if(!hasBookedShips()){
assert ships.stream()
.noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
+ }
}
}Fix Booking history regression #2097
Josian merged 10 commits into
cruising:main
+ 532

- 385




public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships) {
public Search {
- if(!hasBookedShips()){
- assert ships.stream()
- .noneMatch(ship -> ship.departureDate().isBefore(now()))
- : "Some ships are departing in the past";
}
}
}Fix "Previous Days Ships" feature #2099
Josian merged 57 commits into
cruising:main

+ 1278
- 843














The Mighty
Big Ball Of Mud




drives
Exploration
&
Experimentation
Business Need
Search for Ship




drives
Exploration
&
Experimentation
Business Need
shape
Search for Ship
Model




drives
Exploration
&
Experimentation
Business Need
shape
Model
needs to account for new
Selection of a Ship's Fare




drives
Exploration
&
Experimentation
Business Need
shape
Whirlpool
needs to account for new
Selection of a Ship's Fare
Model
Model Exploration




drives
Exploration
&
Experimentation
Business Need
expand
needs to account for new
Model
Whirlpool
Model Exploration




drives
Business Need
Exploration
&
Experimentation
Sinking
Model
Model
expand
needs to account for new




drives
Exploration
&
Experimentation
Business Need
Model
needs to account for new
expand
focuses on
Solution-Push




drives
Exploration
&
Experimentation
Business Need
Solution-Push
focuses on
Obsolete
Model
needs to account for new
expand




drives
Exploration
&
Experimentation
Business Need
shape
Model
$$$
needs to account for new




No model is Inherently extensible !




Exploration
&
Experimentation
Business Need
Model
needs to account for new
Whirlpool
Model Exploration




Business Need
Model
challenged by new
Not a confirmation bias
Exploration
&
Experimentation
needs to account for new
Whirlpool
Model Exploration




Business Need
by shaping
Model
New Model
may
depreciate
Exploration
&
Experimentation
challenged by new
Accidental Design Debt:
the invisible engine of BBOMs














One does not simply
challenge the model




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
}
]
}
]
}
Search ships




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
}
]
}
],
"selectionComplete" : true,
"totalPrice" : "230€",
}Search ships
Select ships




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"ships": [{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true,
}]
}],
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
}
Search ships
Select ships
Book ships














Accidental
Design Debt
The Ruthless




Accidental Design Debt
Model
Accidental
Design Debt
generates through
misguided decisions
manifests
as complexity in
lower their cohesion and flexibility,
increase their complexity,
and erode their correctness.
introduce coupling in models,
from decisions that inadvertently




Model
Accidental
Design Debt
generates through
misguided decisions
manifests
as complexity in
More bugs in unrelated parts of the model?




Simple change causing widespread model updates?
Model
Accidental
Design Debt
generates through
misguided decisions
manifests
as complexity in
More bugs in unrelated parts of the model?




Features taking longer to develop?
More bugs in unrelated parts of the model?
Simple change causing widespread model updates?
Model
Accidental
Design Debt
generates through
misguided decisions
manifests
as complexity in














The Unyielding
Model entropy
Features taking longer to develop?
More bugs in unrelated parts of the model?
Simple change causing widespread model updates?




Model entropy
High Entropy
Design effort is dissipated on navigating accidental complexity
Degree of design disorder
low coherency, consistency, cohesiveness
unclear outcomes
unexpected regressions




dissipates the structure
and clarity of
Model
Entropy
produces through accumulation
Model
Accidental
Design Debt
generates through
misguided decisions




dissolves the model into a
BBOM
Model
Entropy
produces through accumulation
dissipates the structure
and clarity of
Model
Sclerosis
hardens into
locking the model into
Model
Accidental
Design Debt
generates through
misguided decisions
Spork Effect:
unveiling the roots of model fragility and rigidity















{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true



Booking
Search
manifests as




KISS
DRY
YAGNI
Refactoring
Habits




KISS
DRY
YAGNI
Refactoring
Habits
Sunk Cost
Fallacies
Deadlines
Pressure
Intrinsic
Coupling
{}
fosters
fosters




Booking
Search
Intrinsic
Coupling
{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
Booking
Search
Booking
Spork effect




Intrinsic
Coupling
manifests as
strong
Accidental
Design Debt
Responsibilities
Coupling
may induce
"Spork Effect"




"Spork Effect"
causes
Model
Fragility
Intrinsic
Coupling
manifests as
strong
Accidental
Design Debt
Responsibilities
Coupling
may induce
Model
Rigidity
leads to
Model
Entropy
increases
produces
through accumulation
{}




Booking
Search
Intrinsic
Coupling
{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
Booking
Search
Booking




Search
Booking
Distinct Models!
Search
Booking
Booking
Model tension as signals of accidental design debt


















{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true














ModelTension
The Fearsome




Model Tension
is a structural stress within a model that signals it is being stretched beyond its conceptual integrity.
conceptual integrity
Model
Tension
is the result
of
Accidental
Design Debt
Intrinsic
Coupling
may
induce




Conceptual Integrity
is the degree to which a model maintains clarity, coherency, cohesion
and its purpose.
is the result
of
Accidental
Design Debt
Model
Tension
Conceptual
Integrity
erodes
prevents




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
Model
Tension




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
Model
Tension




Booking
Search
{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true
Booking
Search
Booking
Selection
Selection
Model
Tension














Crystallized
ModelTension
The Unstoppable




compromises
"fibrosing"
left unresolved
leads to
Model
Tension
Conceptual
Integrity
erodes
Crystallized
Model Tension
Model
Entropy
raises
Model
Sclerosis
hardens into
shapes




left unresolved
leads to
Model
Tension
Crystallized
Model Tension
Model
Obsolescence
signals






ModelTension
as signal of accidental design debt
The Fearsome














ModelTension
as signal of accidental design debt
The Fearsome








invisible










Exploring (intrinsic)
model tensions heuristics
















visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Check Selected Fares
Completion












visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Check Selected Fares
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Selected Fares












visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Check Selected Fares
Completion












visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Check Selected Fares
Completion

Selected Fares












visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Check Selected Fares
Completion














Linguistic Tension
Salience Bias
Salience Bias
Linguistic Tension
A cognitive bias that predisposes people to focus on information that are more prominent or visible
















visual elements © Alberto Brandolini

Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Check Selected Fares
Completion














Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship
Ancillaries
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship
visual elements © Alberto Brandolini

Check Selected Fares
Completion

Selected
Fares +
Ancillaries














Concepts Relationship Tension
Cognitive Binding Effect

Selected
Fares +
Ancillaries
The contextual association of seemingly independent concepts hides a cohesive concept
Concepts Relationship Tension
Cognitive Binding Effect





Selected
Fares +
Ancillaries
The contextual association of seemingly independent concepts hides a cohesive concept
Concepts Relationship Tension
Cognitive Binding Effect





Selection













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship

Selection
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Price
Selection

Total Price Computation

Selection
Priced

Check
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship

Selection

Priced
Selection
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Check
Completion

Fares Selection
COmpleted

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship


Price
Selection

Total Price Computation

Selection
Priced

Priced
Selection
Selection
visual elements © Alberto Brandolini

Check Selected Fares
Completion













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Check
Selection
Completion

Check
Selection
Completion

Selection
COmpleted

Selection

Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship

Incomplete
Selection

complete
Selection


Price
Selection

Total Price Computation

Selection
Priced

Priced
Selection
Selection
visual elements © Alberto Brandolini













Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Check
Selection
Completion

Check
Selection
Completion

Selection
COmpleted

Selection

Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship

Incomplete
Selection

complete
Selection


Price
Selection

Total Price Computation

Selection
Priced

Priced
Selection
Selection
visual elements © Alberto Brandolini














Search
Bound

Select
a Fare on a Ship


Ship + Fare
Selected On Bound

Compute Total Price

Total Price Computation

Total Price Computed

Check
Completion

Fares Selection
COmpleted

Selected Fares

Selected Fares

Fares Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Incomplete
Selection

complete
Selection

Priced
Selection
visual elements © Alberto Brandolini

Check Selected Fares
Completion














Lifecycle Tension
Implicit Lifecycle
The lifecycle of a concept is derived from the states of other concepts or from false cognates
Lifecycle Tension
Implicit Lifecycle

















Ancillary
Ship

Select
Ancillary

Ancillary
Selected



Search
Bound


Ship + Fare
Selected On Bound

Check
Selection
Completion

Check
Selection
Completion

Selection
COmpleted


Selection Found Incomplete

Ancillaries
Retrieval

List
Ancillaries

Ship
Fare

Ancillaries
Listed

Ancillaries

Select
a Fare on a Ship

Incomplete
Selection

complete
Selection


Price
Selection

Total Price Computation

Selection
Priced

Priced
Selection
Selection
visual elements © Alberto Brandolini
Selection













Select
Ancillary


Check
Selection
Completion

Selection
COmpleted

Selection Found Incomplete

Price
Selection

Selection
Priced

Select
a Fare on a Ship
Ancillary
Selected


Ship + Fare
Selected On Bound

SELECTION
visual elements © Alberto Brandolini




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"selected": true,
"booked" : true




{
"search": {
"id": "XXX",
"ships": [
{
"number": "A",
"bound": "outbound",
"fares": [
{
"comfortClass": "FIRST",
"price": "100€"
},
{
"comfortClass": "SECOND",
"price": "50€"
}
]
},
{
"number": "B",
"bound": "outbound",
"fares": [
{
"comfortClass": "FIRST",
"price": "80€"
}
]
},
{
"number": "C",
"bound": "inbound",
"fares": [
{
"comfortClass": "FIRST",
"price": "90€"
}
]
},
{
"number": "D",
"bound": "inbound",
"fares": [
{
"comfortClass": "FIRST",
"price": "100€"
},
{
"comfortClass": "SECOND",
"price": "50€"
}
]
}
]
}
}{
"selection": {
"id": "YYYY",
"isComplete": true,
"totalPrice": "190€",
"outbound": {
"number": "A",
"fare": {
"comfortClass": "FIRST",
"price": "100€"
}
},
"inbound": {
"number": "C",
"fare": {
"comfortClass": "FIRST",
"price": "90€"
}
}
}
}




class Selection {
TripType tripType;
Map<Bound, Fare> selectedFares = new HashMap();
void selectFare(Bound bound, Fare selectedFare) {
selectedFares.put(bound, selectedFare);
}
Price totalPrice() {
return selectedFares.values().stream()
.reduce(Fare::add)
.get();
}
boolean isSelectionComplete() {
if (tripType == ONEWAY){
return selectedFares.size() == 1;
} else {
return selectedFares.size() == 2;
}
}
}



public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships, PaymentMean paymentMean) {
public Search {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
/*...*/
}




public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships, PaymentMean paymentMean) {
public Search {
if (!hasBookedShips()) {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
}
}




public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships, PaymentMean paymentMean) {
public Search {
if (!hasBookedShips()) {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
}
public boolean hasBookedShips() {
Map<Bound, Long> bookedShipsPerBound =
ships.stream()
.flatMap(ship -> ship.fares().stream().filter(Fare::booked).map(_ -> ship))
.collect(groupingBy(Ship::bound, counting()));
if (searchType == SearchType.ONEWAY) {
return bookedShipsPerBound.get(OUTBOUND) == 1;
} else { //RoundTrip
return bookedShipsPerBound.get(OUTBOUND) == 1 && bookedShipsPerBound.get(INBOUND) == 1;
}
}
public List<Ship> getBookedShips() {
var bookedShips = ships.stream().filter(ship -> ship.fares().stream().anyMatch(Fare::booked)).toList();
if (bookedShips.isEmpty()) {
return Collections.emptyList();
}
List<Ship> cleanedShips = new ArrayList<>();
for (var bookedShip : bookedShips) {
Fare bookedFare = getBookedFare(bookedShip);
Ship cleanedShip = new Ship(bookedShip.number(), bookedShip.bound(), bookedShip.departureDate(), asList(bookedFare));
cleanedShips.add(cleanedShip);
}
return cleanedShips;
}
private Fare getBookedFare(Ship bookedShip) {
Fare bookedFare = null;
int i = 0;
while(i < bookedShip.fares().size()) {
Fare fare = bookedShip.fares().get(i);
if(fare.booked()){
bookedFare = fare;
}
i++;
}
return bookedFare;
}
public void book() {
if(paymentMean == null) {
throw new IllegalStateException("Payment mean is missing");
}
if (hasBookedShips()) {
throw new IllegalStateException("Ships are already booked");
}
var selectedFaresPerBound = new ArrayList<Entry<Bound, Fare>>();
for (Ship ship : ships) {
for (Fare fare : ship.fares()) {
if (fare.selected()) {
selectedFaresPerBound.add(entry(ship.bound(), fare));
}
}
}
if (selectedFaresPerBound.isEmpty()) {
throw new IllegalStateException("Ships must be selected before booking");
}
var numberOfSelectedFarePerBound = selectedFaresPerBound.stream().collect(groupingBy(Entry::getKey, counting()));
if (searchType == SearchType.ONEWAY) {
assert numberOfSelectedFarePerBound.get(OUTBOUND) == 1 && numberOfSelectedFarePerBound.get(INBOUND) == 0 : "Inconsistent number of selected fares";
} else { //RoundTrip
assert numberOfSelectedFarePerBound.get(OUTBOUND) == 1 && numberOfSelectedFarePerBound.get(INBOUND) == 1 : "Inconsistent number of selected fares";
}
for (Entry<Bound, Fare> selectedFare : selectedFaresPerBound) {
selectedFare.getValue().book();
}
}
public boolean isSelectionComplete() {
Map<Bound, Long> selectedFaresPerBound = ships.stream().flatMap(ship -> ship.fares().stream().filter(Fare::selected).map(_ -> ship)).collect(groupingBy(Ship::bound, counting()));
var selectedOutBounds = selectedFaresPerBound.get(OUTBOUND);
var selectedInBounds = selectedFaresPerBound.get(INBOUND);
if (searchType == SearchType.ONEWAY) {
//This should never happen 👇
assert selectedOutBounds <= 1 && selectedInBounds <= 0 : "Too many fares are selected";
return selectedOutBounds == 1;
} else { //RoundTrip
//This should never happen 👇
assert selectedOutBounds <= 1 && selectedInBounds <= 1 : "Too many fares are selected";
return selectedOutBounds == 1 && selectedInBounds == 1;
}
}
public Price getTotalPrice() {
return ships.stream().flatMap(ship -> ship.fares().stream().filter(Fare::selected).map(Fare::price)).reduce(Price::add).orElse(Price.ZERO);
}
public void selectFareOfShip(Bound bound, String shipNumber, ComfortClass comfortClass) {
var fareToSelect = ships.stream().filter(ship -> ship.number().equals(shipNumber) && ship.bound() == bound).flatMap(ship -> ship.fares().stream().filter(fare -> fare.comfortClass() == comfortClass)).findFirst().orElseThrow();
var previousSelectionOnBound = ships.stream().filter(ship -> ship.bound() == bound).flatMap(ship -> ship.fares().stream()).filter(Fare::selected).findFirst();
previousSelectionOnBound.ifPresent(fare -> fare.setSelected(false));
fareToSelect.setSelected(true);
}
}




{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"selected": true,
"booked" : true




public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships) {
public Search {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
/*...*/
}
public record Booking(UUID id, List<Ship> ships, PaymentMean paymentMean, Boolean finalized) {
public Booking {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
}




public record Search(UUID id, Criteria criteria, SearchType searchType, List<Ship> ships) {
public Search {
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
/*...*/
}
public record Booking(UUID id, List<Ship> ships, PaymentMean paymentMean, Boolean finalized) {
public Booking {
if(!finalized){
assert ships.stream().noneMatch(ship -> ship.departureDate().isBefore(now()))
: "Some ships are departing in the past";
}
}
}














CHAPTER 2
When model sclerosis
turns into model
Fragmentation












CRUISING
POST-BOOKING




Text
works around
Sclerosed
Model
Outgrowth
Model
Cruising
Post-Booking
Pursued Lead
Investigative Case

Our respective systems actually form a distributed big ball of mud












POST-BOOKING
CRUISING
Search
Exchange
Cancellation
Search
Booking
Selection












POST-BOOKING
CRUISING
Search
Exchange
Cancellation
Booking
Selection
Search












Selection
Booking
POST-BOOKING
CRUISING
Search
Exchange
Cancellation
Search
Booking
Selection












Selection
Booking
POST-BOOKING
CRUISING
Search
Exchange
Cancellation
Search
Booking
Selection












Selection
Booking
Search
Exchange
Cancellation
noDepartureInThePast()
noDepartureInThePast()
POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
POST-BOOKING
CRUISING












Selection
Booking
Search
Exchange
Cancellation














Architectural Tension
Business Logic Leaks
Behaviors, invariants, lifecycles, etc. are scattered across bounded-contexts
Architectural Tension
Business Logic Leaks




POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange












Selection
Booking
Search
Exchange
Cancellation
Cancellation
Booking
Exchanged
Booking
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Cancelled
Booking












Selection
Booking
Search
Exchange
Cancellation
POST-BOOKING
CRUISING
Booking
Exchanged
Booking
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Cancelled
Booking
Completed
Booking












Selection
Booking
Search
Exchange
Cancellation
POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Created
Completed
Exchanged
Cancelled












Selection
Booking
Search
Exchange
Cancellation
POST-BOOKING
CRUISING












Cart
SHOPPING
Order
ORDER
Parcel
DELIVERY
Booking Lifecycle
Created
Completed
Exchanged
Cancelled
POST-BOOKING
CRUISING












Booking Lifecycle
Exchanged
Cancelled
POST-BOOKING
CRUISING












fix ship departing in the past
Created
Completed














Architectural Tension
Fragmented Lifecycle
When separate bounded-contexts handle different states of the same aggregate, while sharing many concepts, personae, and rules.
Architectural Tension
Fragmented Lifecycle




POST-BOOKING
CRUISING












MOBILE APP
Booking
Exchange
Cancellation
Determining current booking status
check booking exists
check if exchange or cancellation exists
Completed
Booking
Created
Completed
Exchanged
Cancelled
POST-BOOKING
CRUISING












MOBILE APP
check if exchanged/cancelled
check booking exists
Determining current booking status
BOOKING
can be both














Architectural Tension
Distributed States
Understanding the state of a concept requires consolidating data from multiple bounded-contexts
Architectural Tension
Distributed States




POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange
Cancellation












Selection
Booking
Search
Exchange
Cancellation
POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange
Cancellation












Selection
Booking
Search
Exchange
Cancellation
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange
POST-BOOKING
CRUISING
Fragmented Model












Cancellation
POST-BOOKING
CRUISING
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange
Extrinsic Coupling












Cancellation
POST-BOOKING
CRUISING












Feature Change
Remediation
breaks logic in
Architectural Tension
Frequent
Breaking Changes




Every model evolution break collaborating bounded-contexts.
Architectural Tension
Frequent
Breaking Changes





Investigative Case
Architectural Tensions

Business Logic leaks
Fragmented Lifecycle

Distributed States

Frequent
Breaking Changes

noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Extrinsic Coupling

Model fragmentation (extrinsic coupling):
the insidious builder of distributed BBOMs


















Text
Sclerosed
Model
Cruising
works around
Outgrowth
Model
Post-Booking




Sclerosed
Model
Outgrowth
Model
works around
Model
Fragmentation
becomes a fragment of
is a fragment of
causes
Extrinsic
Coupling
Cruising
Post-Booking




Business
Logic Leak
favorises
induces
exacerbates
is a form of
Extrinsic
Coupling
Outgrowth
Model
Model
Fragmentation




Synced
Evolutions
Model
Fragmentation
Extrinsic
Coupling
is a form of
contrains
systems to




Synced
Evolution
results in
Synced
Failures
leads to
System
Entropy
raises
binds the fragments into
Distributed
BBOM
entangles
into
crystallizes
into
Fragmented
Model
Rigidity
causes
Fragmented
Model
Fragility














Governing Constraint
Synced Evolutions
Governing Constraint














Compensations
System
Pursued Lead
Investigative Case

Our processes and organization are constrained to compensate for the synchronized evolution of the fragmented model
POST-BOOKING
CRUISING
Booking












Release 464
Release 52
Insurance
Policy
Insurance
Policy
POST-BOOKING
CRUISING












ignores
Release 464
Release 52
Booking
Insurance
Policy
Insurance
Policy
Cancellation
POST-BOOKING
CRUISING












ignores
Release 464
Release 52
Booking
Insurance
Policy
Insurance
Policy
Incompatible
Cancellation
POST-BOOKING
CRUISING












Insurance
Policy
Release 464
Release 53
Deploy Together
Booking
Insurance
Policy
Insurance
Policy
Cancellation














Process Tension
Synchronized Releases
Necessity to synchronize heavily around releases and model evolutions across systems
Process Tension
Synchronized Releases


















Organizational Tension
Inter-Team
Work Coupling
Teams need to constantly synchronize their plans and priorities despite their scope of autonomy
Organizational Tension
Inter-Team Work Coupling




Investigative Case

Synchronized
Evolutions

noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Model Fragmentation
Process Tension
Synchronized
Releases
Org. Tension
InterTeam
Work
Coupling
Governing
Constraint

POST-BOOKING
CRUISING












Release 465
Release 57
Incompatible
Special Meal
POST-BOOKING
CRUISING












Release 465
Release 57
Compatible
Special Meal
Toggle: OFF
POST-BOOKING
CRUISING












Release 465
Release 58
Compatible
Toggle: OFF
Toggle: OFF
Special Meal
Special Meal
POST-BOOKING
CRUISING












Release 465
Release 58
Toggle: ON
Toggle: ON
Special Meal
Special Meal
Compatible














Process Tension
Band-aid Processes
Unresolved design problems are compensated by processes such as multi-versioning, double run, feature flags to limit impact on another team
Process Tension
Band-aid Processes




POST-BOOKING
CRUISING












Special Meal
Special Meal
Interface
Toggle: OFF
Toggle: OFF
R
T
E
POST-BOOKING
CRUISING












Special Meal
ready?
Special Meal
Interface
ready?
Toggle: OFF
Toggle: OFF
R
T
E
POST-BOOKING
CRUISING












Special Meal
ready?
Special Meal
Interface
ready?
Toggle: OFF
Toggle: OFF
R
T
E
POST-BOOKING
CRUISING












Special Meal
ready?
Special Meal
Interface
ready?
Toggle: OFF
Toggle: OFF
Readiness
Toggle
Engineer














Organizational Tension
Palliative Roles
When the growing complexity of band-aid processes and ceremonies requires a full-time job
Organizational Tension
Palliative Roles








Extrinsic
Coupling
leads to
Synchronized
Releases
leads to
InterTeam
Work Coupling




Extrinsic
Coupling
Synchronized
Releases
InterTeam
Work Coupling
leads to
leads to
buffered by
buffered by
Palliative Roles
handled by
Band-aid processes




Extrinsic
Coupling
leads to
leads to
buffered by
buffered by
offset
offset
Synchronized
Releases
InterTeam
Work Coupling
Palliative Roles
handled by
Compensatory
Counter Measures
Band-aid processes
Process Tension
Org. Tension




Extrinsic
Coupling
Tests Envs Proliferations
Synced
plannings
& backlogs
Feature Flags
Overuse
Multi
Versionning
Shared & Distributed
DataSets
leads to
leads to
buffered by
buffered by
offset
offset
never address
Compensatory
Counter Measures
Synchronized
Releases
InterTeam
Work Coupling




Extrinsic
Coupling
Tests Envs Proliferations
Synced
plannings
& backlogs
Feature Flags
Overuse
Multi
Versionning
Shared & Distributed
DataSets
leads to
leads to
buffered by
buffered by
offset
offset
never address
Compensatory
Counter Measures
Synchronized
Releases
InterTeam
Work Coupling
Tension Crystallization
Tension Crystallization




Tests Envs Proliferations
Synced
plannings
& backlogs
Feature Flags
Overuse
Multi
Versionning
Shared & Distributed
DataSets
leads to
leads to
buffered by
buffered by
offset
offset
never address
Compensatory
Counter Measures
Compensations
System
Tension Crystallization
Tension Crystallization
Extrinsic
Coupling
Synchronized
Releases
InterTeam
Work Coupling
Investigative Case

noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Model Fragmentation
Process Tension


Compensatory Countermeasures
Compensations
System
Org. Tension
Band-Aid
Processes
Palliative
Roles


Synced
Evolutions
GoverningConstraint
Crystallized
Extrinsic Model Tensions














Socio-Technical
Entropy
Pursued Lead
Investigative Case

Our extrinsic coupling manifests as organizational dysfunction
Booking
Exchange
POST-BOOKING
CRUISING
Cancellation












Seat Preferences
Seat Preferences
Update Booking?
Create Exchange?














Organizational Tension
Unclear
Ownership
Organizational Tension
Unclear Ownership
When a need for feature debugging or development arises, debates often break out to determinate which team should be in charge









Bug
Ships departing in the past are bookable
ToDo


Bug
ToDo
Cruising BackLog
Ships departing in the past are bookable




Post-Booking BackLog
Cruising BackLog


Bug
Ships departing in the past are bookable
In Progress


Bug
Ships departing in the past are bookable
ToDo














Organizational Tension
Backlog Takeover
When the work of a stream-aligned team is systematically on the critical path of another team
Organizational Tension
Backlog Takeover




Investigative

Model Fragmentation
GoverningConstraint


Synced
Evolutions
Synchronized
Releases
InterTeam
Work Coupling
Crystallized Model Tensions


Compensatory
Countermeasures
Compensations
Systems
Band-Aid
Processes & ORg
Case
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()

Organizational
Fragmentation
Unclear
Ownership
Org. Tension
Backlog
TakeOver
Org. Tension

Catalyst




Model
Fragmentation
Organizational
Fragmentation
Synced
Evolution
Process
overhead
Socio-technical system entropy














Results






???














Business Tension
Business Capability Discrepancy
Business Tension
Business Capability Discrepancy
A capability varies in scope, maturity, or behavior across the system, causing gaps and inconsistencies.








Business
Impact
Socio-technical system entropy
Model
Fragmentation
Organizational
Fragmentation
Synced
Evolution
Process
overhead














Interpretation




Sclerosed
Model
Outgrowth
Model




Sclerosed
Model
works around
Outgrowth
Model
Historical
Team
New Team
offloads the
work of




Historical
Team
Sclerosed
Model
works around
Outgrowth
Model
offloads the
work of
New Team




Sclerosed
Model
works around
Outgrowth
Model
Organizational
Fragmentation
Historical
Team
New Team




Sclerosed
Model
Organizational
Fragmentation
Historical
Team
New Team
Model
Fragmentation
Conway's Law
Outgrowth
Model














Conway's Law
Organizations produce systems that mirror their communication structure.




Management unconciously design the architecture of the system via organizational decision
Organizational Shadow Design
Organizational Tension




Sclerosed
Model
Organizational
Fragmentation
Historical
Team
New Team
Model
Fragmentation
Conway's Law
Outgrowth
Model




Historical
Team
Sclerosed
Model
works around
Outgrowth
Model
offloads the
work of
New Team




The organization will charge you interest on your design debt!
Extrinsic coupling signals are mainly socio-technical


















Structure eats Strategy
Jan Bosch - 2017
B.A.P.O Model
Organizational Tensions
produce
Architectural
Tensions
structure
Process
Tensions
compensate
Business
Tensions
reflects as




Extrinsic coupling Signals are mainly socio-technical




Intrinsic Coupling
Model Tension
Heuristics
Model
Tension
spot
prevents
Model
Entropy




Extrinsic Coupling
Model
Tension
Model Tension
Heuristics
spot
Socio-Technical
Entropy
prevents
Conclusion














Build a Case!

Why ???

How !?!

Detect signals
across
the sociotech system
Highlight
Extrinsic Coupling

noDepartureInThePast()
noScheduleOverlap()
noDepartureInThePast()
noScheduleOverlap()

Use heuristics
to find symptoms

Collect a body of evidence to explore possible correlations

Assess its location, depth & Spread




... but are only heuristics. Not surefire rules.
Model Tension Heuristics
prevent accidental design debt
Signals












Cart
SHOPPING
Order
ORDER
Parcel
DELIVERY
...do not always reflect tensions.
This is not a fragmented lifecyle!




Experiment on the system
Once you have a body of evidences, act on the signals by running limited, safe to fail experiments to test your heuristics
POST-BOOKING
CRUISING
Exchange












Selection
Booking
Search
Cancellation
Search
Booking







SHODO
Model Tension
Heuristics
Preventing Accidental Design Debt


Julien Topçu
Josian Chevalier
Tech Coach
CTO / Coach
@julientopcu.com
@josianchevalier.bsky.social

TODo
Current Quest
Done
JIRA


???

Add a
Konami Code
Bug


Bug

Special meals
cancellation
Bug


Handle cancellation insurance

Overlapping ships can be selected

Deprecated seat preference shown during exchange
Bug

Feature
Feature
[Paid Option] Wireless pidgin connexion
TODo
Current Quest
Done
JIRA




Bug
Overlapping ships can be selected

Deprecated seat preference shown during exchange
Bug

Feature
Feature
[Paid Option] Wireless pidgin connexion


Handle cancellation insurance

Special meals
cancellation
Bug

???
TODo
Current Quest
Done



Inconsistent
special meal
orders
Bug

???
JIRA
POST-BOOKING
CRUISING
Exchange












Selection
Booking
Search
Cancellation
Search
Booking
POST-BOOKING
CRUISING
Booking
Exchange












Selection
Booking
Search
Cancellation
Search
Shared
Kernel
Model Mitosis
POST-BOOKING
CRUISING
Booking
Exchange












Selection
Booking
Search
Cancellation
Search
SK
Model Mitosis
POST-BOOKING
CRUISING
Booking
Exchange












Selection
Booking
Search
Cancellation
Search
Model Mitosis
BOOKING
CRUISING
Booking
Exchange












Selection
Booking
Search
Cancellation
Search
noDepartureInThePast()
noDepartureInThePast()
noScheduleOverlap()
noScheduleOverlap()
Booking
Exchange
Cancellation
POST-BOOKING
CRUISING
Fragmented Model
















drives
Exploration
&
Experimentation
Business Need
shape
Model
needs to account for new
Selecting




drives
Exploration
&
Experimentation
Business Need
shape
Model
needs to account for new
Selecting




drives
Exploration
&
Experimentation
Business Need
shape
Model
needs to account for new
Booking




Model
Accidental
Design Debt
Model
Entropy
produces through
accumulation
Features taking longer to develop?
More bugs in unrelated parts of the model?
Simple change causing widespread model updates?
generates through
misguided decisions
manifests
as complexity in

{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true



Intrinsic
Coupling
Accidental
Design Debt
Responsibilities
Coupling
may induce
Booking
Search
manifests as
strong

{
"search": {
"id": "XXXX",
"criteria": {
"outBoundDate": "2025-10-06T12:00",
"inBoundDate": "2025-10-16T11:00"
},
"selectionComplete" : true,
"totalPrice" : "230€",
"paymentMean": {
"type": "CREDIT_CARD",
"number": "***********"
},
"travelInsurance" : "40€",
"ships": [
{
"number": "A",
"bound": "outbound",
"departureDate": "2025-10-06T13:30",
"fares": [
{
"comfortClass" : "FIRST",
"price": "100€",
"seatOptions": [ "ANY", "..." ],
"deckOptions": [ "ANY", "..." ],
"preferences": {
"seat": "LOUNGE",
"deck" : "UPPER_DECK"
},
"selected": true,
"booked" : true



Intrinsic
Coupling
Accidental
Design Debt
Responsibilities
Coupling
may induce
Search
Booking
manifests as
strong




"Spork Effect"
Intrinsic
Coupling
{}
Refactoring
Habits
fosters
Sunk Cost
Fallacies
fosters
Deadlines
Pressure
KISS
DRY
YAGNI
is the path to
BBOM




"Spork Effect"
Intrinsic
Coupling
{}
BBOM
leads to
Model
Entropy
dissolves the model into a




"Spork Effect"
Intrinsic
Coupling
{}
BBOM
Model
Entropy
dissolves the model into a
leads to
locking the
model into
hardens into
Model
Sclerosis




Suffering...




Suffering...




Suffering...
Entropy
Tensions
Resolution
Accidental
Design
Debt
Model Rigidity
Entropy
Accidental
Design
Debt
Model Tension Heuristics: Preventing Accidental Design Debt
By Julien Topçu
Model Tension Heuristics: Preventing Accidental Design Debt
”All models are wrong, but some are useful.” This insight from George Box has become a cornerstone of software modeling. While exploration and experimentation are essential for shaping models, it is often challenging to know when a model is wrong or, worse, when an existing model has become obsolete and is no longer as useful. As a result, unsuitable models may be still used for a long time, leading to different issues not always identified as forms of design debt. These include the spork effect (intrinsic coupling), model fragmentation (extrinsic coupling), and model sclerosis, which ultimately contribute to entropy or the "Big Ball of Mud" phenomenon. These problems arise from undetected and unresolved model tensions. In this talk, we will explore what model tensions are, the complications they cause and why they occur. We will also present a set of heuristics to identify and address different kind of model tensions.
- 544