← Extractions

Development with axioms (Martin Gamsjaeger, wroclove.rb 2019)

Martin Gamsjaeger presents the axiom-driven development process his small fully-remote team shares with Markus Schirp: a written-only workflow grounded in universally-accepted truths (redundancy and inconsistency have no value, human attention is unstable, automation beats manual checks) from which five atomic commit-level transformations — remove, fix, refactor, change, add — and concrete CI-enforced constraints are derived. The talk sets the stage for Schirp's following talk on Mutant and mutation testing.

Model
claude-opus-4-7
Ingestion
be042194
Input tokens
157,463
fresh
85,813
cached
61,409
cache write
10,241
Output tokens
10,782
Duration
165.2s
Roundtrips
5
Tool calls
12
Cost
$0.00
Nodes/edges extracted
19 / 39
Read set (nodes/edges)
72 / 3

Nodes (19)

create Regression (broad sense) concept
kind (empty) → concept
name (empty) → Regression (broad sense)
slug (empty) → regression-broad-sense
attrs (empty) → {"category" => "concept"}
description (empty) → Gamsjaeger's team uses 'regression' more abstractly than the common 'a regression is a bug'. A regression is anything...
short_description (empty) → Any change leaving the system in a worse state, not just a production bug.
update Development with axioms talk
attrs {"type" => "talk"} → {"type" => "talk", "year" => "2019"}
description Talk at wroclove.rb 2019. → Martin Gamsjaeger's wroclove.rb 2019 talk setting the stage for Markus Schirp's Mutant talk that follows. Presents th...
short_description Talk at wroclove.rb 2019. → Talk on axiom-driven development process with atomic commit transformations.
update Martin Gamsjaeger person
description Conference speaker. → Software developer working in a small fully-remote team together with close friend Markus Schirp and team leader Dan ...
short_description Conference speaker. → Software developer, member of Markus Schirp's fully-remote team, wroclove.rb 2019 speaker.
create Dan Kubb person
kind (empty) → person
name (empty) → Dan Kubb
slug (empty) → dan-kubb
description (empty) → Team leader of the small fully-remote team that Martin Gamsjaeger and Markus Schirp work on. Credited by Gamsjaeger a...
short_description (empty) → Team leader on Martin Gamsjaeger and Markus Schirp's remote team.
create Axiom-Driven Development concept
kind (empty) → concept
name (empty) → Axiom-Driven Development
slug (empty) → axiom-driven-development
attrs (empty) → {"category" => "methodology"}
description (empty) → Methodology presented by Martin Gamsjaeger in which a team agrees on a set of axioms — sentences everyone accepts as ...
short_description (empty) → Development methodology deriving constraints and process from universally-accepted truths (axioms).
create Commit Transformations concept
kind (empty) → concept
name (empty) → Commit Transformations
slug (empty) → commit-transformations
attrs (empty) → {"category" => "pattern"}
description (empty) → Gamsjaeger's team restricts every commit to one of five transformation kinds, each an atomic (cannot-be-made-smaller)...
short_description (empty) → Closed set of five atomic commit-level change types: remove, fix, refactor, change, add.
create Atomic Commit concept
kind (empty) → concept
name (empty) → Atomic Commit
slug (empty) → atomic-commit
attrs (empty) → {"category" => "practice"}
description (empty) → Commit discipline in Gamsjaeger's process: every commit must be the smallest possible change that still forms an impr...
short_description (empty) → Commit so small it cannot be meaningfully broken up further.
create Checks, Tests, Reviews and Flags concept
kind (empty) → concept
name (empty) → Checks, Tests, Reviews and Flags
slug (empty) → checks-tests-reviews-and-flags
attrs (empty) → {"category" => "practice"}
description (empty) → Gamsjaeger's vocabulary for verifying that a proposed commit matches the team's intentions. A check is any verificati...
short_description (empty) → Vocabulary distinguishing automated checks (tests) from manual checks (reviews) and their flags.
create Redundancy provides no value takeaway
kind (empty) → takeaway
name (empty) → Redundancy provides no value
slug (empty) → redundancy-provides-no-value
attrs (empty) → {"type" => "insight"}
description (empty) → The central axiom of Gamsjaeger's process — everything else in the system of axioms can arguably be boiled down to th...
short_description (empty) → Master axiom: anything redundant in code or semantics adds no value and should be removed.
create Inconsistency provides no value takeaway
kind (empty) → takeaway
name (empty) → Inconsistency provides no value
slug (empty) → inconsistency-provides-no-value
attrs (empty) → {"type" => "insight"}
description (empty) → Secondary axiom, arguably reducible to 'redundancy provides no value' but stated separately because inconsistency is ...
short_description (empty) → Style inconsistency across a codebase adds no value; agree on a shared style.
create Every commit must be an improvement, atomic, and deployable takeaway
kind (empty) → takeaway
name (empty) → Every commit must be an improvement, atomic, and deployable
slug (empty) → every-commit-must-be-an-improvement-atomic-and-deployable
attrs (empty) → {"type" => "recommendation"}
description (empty) → Constraints Gamsjaeger's team enforces on every commit: must not regress automated test coverage; must be an improvem...
short_description (empty) → Enforced constraint: every single commit must improve the system, be atomic, pass checks, and be deployable.
create Push constraints down to the lowest level takeaway
kind (empty) → takeaway
name (empty) → Push constraints down to the lowest level
slug (empty) → push-constraints-down-to-the-lowest-level
attrs (empty) → {"type" => "recommendation"}
description (empty) → Because your mental model of a project will change, ingrain identified constraints as deep in the system as possible....
short_description (empty) → Ingrain invariants as deep in the stack as possible — into the database, not just the model.
create Reject invalid input as early as possible takeaway
kind (empty) → takeaway
name (empty) → Reject invalid input as early as possible
slug (empty) → reject-invalid-input-as-early-as-possible
attrs (empty) → {"type" => "recommendation"}
description (empty) → As soon as someone sends data your system should process, check it; if invalid, reject with an appropriate HTTP error...
short_description (empty) → Validate at the boundary and return an HTTP error rather than coercing bad data.
create Never self-censor on reviews takeaway
kind (empty) → takeaway
name (empty) → Never self-censor on reviews
slug (empty) → never-self-censor-on-reviews
attrs (empty) → {"type" => "recommendation"}
description (empty) → In code review, don't hold back a comment because you worry your colleague will think you missed something obvious. A...
short_description (empty) → When reviewing, voice every concern — worst case you learn something, best case you catch a real issue.
create Act as a perfect tool on reviews takeaway
kind (empty) → takeaway
name (empty) → Act as a perfect tool on reviews
slug (empty) → act-as-a-perfect-tool-on-reviews
attrs (empty) → {"type" => "recommendation"}
description (empty) → We can easily imagine what a perfect tool would do even when it's hard to build. Agreement in the team: on manual rev...
short_description (empty) → Human reviewers should flag everything an ideal automated tool would flag, even if today's tools don't.
create Commit messages must start with a transformation verb takeaway
kind (empty) → takeaway
name (empty) → Commit messages must start with a transformation verb
slug (empty) → commit-messages-must-start-with-a-transformation-verb
attrs (empty) → {"type" => "recommendation"}
description (empty) → Because the team limits commits to the five transformations, CI enforces that every commit message starts with one of...
short_description (empty) → CI rejects commit messages that don't begin with remove, fix, refactor, change, add (or synonyms).
create Move transformation vs refactoring when tests change question
kind (empty) → question
name (empty) → Move transformation vs refactoring when tests change
slug (empty) → move-transformation-vs-refactoring-when-tests-change
attrs (empty) → {"answer_summary" => "Extract a move or rename as its own atomic commit from within a larger refactoring; being in a ...
description (empty) → Audience member notes that moving code in a refactoring usually also changes tests, and asks whether this is difficul...
short_description (empty) → Audience asks about moving code as part of a refactoring when tests necessarily change.
create How was the axiom-driven process introduced? question
kind (empty) → question
name (empty) → How was the axiom-driven process introduced?
slug (empty) → how-was-the-axiom-driven-process-introduced
attrs (empty) → {"answer_summary" => "Refined over years of discussion with Markus Schirp and team leader Dan Kubb; requires rigid te...
description (empty) → Audience asks how the team started using the axiom-driven process — it clearly wasn't overnight. Gamsjaeger: all thes...
short_description (empty) → Audience asks whether the team adopted the process overnight or gradually.
create How are fix and change different from remove and add? question
kind (empty) → question
name (empty) → How are fix and change different from remove and add?
slug (empty) → how-are-fix-and-change-different-from-remove-and-add
attrs (empty) → {"answer_summary" => "The distinction is crisp only under atomic-commit discipline: a fix corrects a rule violation/s...
description (empty) → Audience member observes that fixing or changing code seems to amount to removing or adding features, and asks what d...
short_description (empty) → Audience asks whether fix/change are just remove/add under another name.

Edges (39)

update Martin Gamsjaeger → authored → Development with axioms
context (empty) → Gamsjaeger delivered this talk.
update Development with axioms → presented_at → wroclove.rb 2019
context (empty) → Talk given at wroclove.rb 2019, immediately before Schirp's Mutant talk.
create Martin Gamsjaeger → attended → wroclove.rb 2019
context (empty) → Speaker at the conference.
relation (empty) → attended
source_node_id (empty) → 60766d79-6b2e-420b-a522-0a83a1c85883
target_node_id (empty) → 8bcc988a-785d-4dfa-a063-1daa7ba349c0
create Development with axioms → about → Axiom-Driven Development
context (empty) → The talk presents the methodology of axiom-driven development.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
create Development with axioms → about → Commit Transformations
context (empty) → Introduces the five commit transformations and their priority.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 73c84a5b-4b6b-4c64-91ea-8bc62268052b
create Development with axioms → about → Atomic Commit
context (empty) → Atomicity is a core principle enforced on every commit.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → f9123e27-d255-4544-b362-3d4b96fca9aa
create Development with axioms → about → Regression (broad sense)
context (empty) → Defines regression broadly as anything leaving the system in a worse state.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 90a9d6c4-4f1e-4524-92b1-e322163aef36
create Development with axioms → about → Checks, Tests, Reviews and Flags
context (empty) → Defines the team's vocabulary for automated tests, manual reviews and flags.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 7037f6d2-978a-4446-8e77-ae8a2e51003d
create Development with axioms → about → Mutation Testing
context (empty) → Frames Schirp's upcoming mutation-testing talk as how to remove redundant semantics automatically.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 23d3425f-ac30-4ff6-b95a-d6349fd39a6b
create Development with axioms → about → Mutant
context (empty) → Points to Mutant as the tool that helps remove redundant semantics in Ruby, teed up for Schirp's follow-on talk.
relation (empty) → about
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → ab45ac79-e626-4dbb-b938-be653956e6e5
create Development with axioms → related_to → Mutant on steroids
context (empty) → Gamsjaeger explicitly sets the stage for Schirp's Mutant talk, which follows immediately.
relation (empty) → related_to
source_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
target_node_id (empty) → 7f6e2f29-0154-4dc3-87f3-e26baf7729ec
create Markus Schirp → related_to → Development with axioms
context (empty) → Schirp is Gamsjaeger's close friend and teammate and a key co-author of the axiom-driven process described in the talk.
relation (empty) → related_to
source_node_id (empty) → 6d1416eb-8271-4024-8c67-28d9e5513683
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Dan Kubb → related_to → Development with axioms
context (empty) → Gamsjaeger credits team leader Dan Kubb as a driving force behind the years-long refinement of the axiom-driven process.
relation (empty) → related_to
source_node_id (empty) → 8f8a1a20-008c-421c-a7ee-9c36fdc8861f
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Martin Gamsjaeger → related_to → Markus Schirp
context (empty) → Close friends and teammates on the same fully-remote team.
relation (empty) → related_to
source_node_id (empty) → 60766d79-6b2e-420b-a522-0a83a1c85883
target_node_id (empty) → 6d1416eb-8271-4024-8c67-28d9e5513683
create Martin Gamsjaeger → related_to → Dan Kubb
context (empty) → Gamsjaeger works on Kubb's team and thanks him as team leader.
relation (empty) → related_to
source_node_id (empty) → 60766d79-6b2e-420b-a522-0a83a1c85883
target_node_id (empty) → 8f8a1a20-008c-421c-a7ee-9c36fdc8861f
create Axiom-Driven Development → related_to → Commit Transformations
context (empty) → The commit transformations are the practical output of the axiom-driven methodology.
relation (empty) → related_to
source_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
target_node_id (empty) → 73c84a5b-4b6b-4c64-91ea-8bc62268052b
create Axiom-Driven Development → related_to → Atomic Commit
context (empty) → Atomicity is a core derived constraint of the methodology.
relation (empty) → related_to
source_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
target_node_id (empty) → f9123e27-d255-4544-b362-3d4b96fca9aa
create Commit Transformations → related_to → Atomic Commit
context (empty) → Each transformation must be atomic for the priority ordering to be meaningful.
relation (empty) → related_to
source_node_id (empty) → 73c84a5b-4b6b-4c64-91ea-8bc62268052b
target_node_id (empty) → f9123e27-d255-4544-b362-3d4b96fca9aa
create Redundancy provides no value → from_talk → Development with axioms
context (empty) → Master axiom articulated in the talk.
relation (empty) → from_talk
source_node_id (empty) → 310bd7f7-ea57-43d8-aa36-721d643921d1
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Inconsistency provides no value → from_talk → Development with axioms
context (empty) → Axiom articulated in the talk, focused on style.
relation (empty) → from_talk
source_node_id (empty) → 4bda7d4a-da99-43fa-a0b8-50faacf10dac
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Every commit must be an improvement, atomic, and deployable → from_talk → Development with axioms
context (empty) → Core enforced constraint described in the talk.
relation (empty) → from_talk
source_node_id (empty) → fe786f21-5ba4-42f9-98af-216e239ba154
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Push constraints down to the lowest level → from_talk → Development with axioms
context (empty) → Recommendation derived from the 'mental model will change' axiom.
relation (empty) → from_talk
source_node_id (empty) → c00c37f3-631e-4435-9995-4330b00a73fd
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Reject invalid input as early as possible → from_talk → Development with axioms
context (empty) → Complementary recommendation from the talk.
relation (empty) → from_talk
source_node_id (empty) → 39e9bee9-652a-4a69-8131-309251b5a5fe
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Never self-censor on reviews → from_talk → Development with axioms
context (empty) → Review-discipline recommendation stated in the talk.
relation (empty) → from_talk
source_node_id (empty) → b35e58c0-19e0-4c45-98ef-53ff24631c7d
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Act as a perfect tool on reviews → from_talk → Development with axioms
context (empty) → Review-discipline recommendation derived from the 'imagine a perfect tool' axiom.
relation (empty) → from_talk
source_node_id (empty) → 34cd3d13-ab33-4a28-b24c-a3b0b3f52c45
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Commit messages must start with a transformation verb → from_talk → Development with axioms
context (empty) → CI constraint described in the talk.
relation (empty) → from_talk
source_node_id (empty) → 7adaf2e4-33e6-4e17-8253-ea631144e279
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Redundancy provides no value → about → Mutation Testing
context (empty) → Mutation testing is the automated way the team removes redundant semantics per this axiom.
relation (empty) → about
source_node_id (empty) → 310bd7f7-ea57-43d8-aa36-721d643921d1
target_node_id (empty) → 23d3425f-ac30-4ff6-b95a-d6349fd39a6b
create Every commit must be an improvement, atomic, and deployable → about → Atomic Commit
context (empty) → Takeaway directly enforces the atomic-commit concept.
relation (empty) → about
source_node_id (empty) → fe786f21-5ba4-42f9-98af-216e239ba154
target_node_id (empty) → f9123e27-d255-4544-b362-3d4b96fca9aa
create Inconsistency provides no value → related_to → Redundancy provides no value
context (empty) → Inconsistency is arguably a special case of redundancy but stated separately for clarity.
relation (empty) → related_to
source_node_id (empty) → 4bda7d4a-da99-43fa-a0b8-50faacf10dac
target_node_id (empty) → 310bd7f7-ea57-43d8-aa36-721d643921d1
create Move transformation vs refactoring when tests change → asked_at → Development with axioms
context (empty) → Audience question during Q&A.
relation (empty) → asked_at
source_node_id (empty) → 4d3e58c0-fbe0-4a87-a8df-1dd0ff7d29ed
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create How was the axiom-driven process introduced? → asked_at → Development with axioms
context (empty) → Audience question during Q&A.
relation (empty) → asked_at
source_node_id (empty) → c7d327ae-c2db-4013-835e-220e18ef2853
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create How are fix and change different from remove and add? → asked_at → Development with axioms
context (empty) → Audience question during Q&A.
relation (empty) → asked_at
source_node_id (empty) → 1c526f69-379d-4f97-8eaf-6b251a664ef8
target_node_id (empty) → 0ef6f37b-c71a-421b-b6f8-ed7eba231aaa
create Move transformation vs refactoring when tests change → about → Commit Transformations
context (empty) → Question concerns the move and refactor transformations.
relation (empty) → about
source_node_id (empty) → 4d3e58c0-fbe0-4a87-a8df-1dd0ff7d29ed
target_node_id (empty) → 73c84a5b-4b6b-4c64-91ea-8bc62268052b
create How was the axiom-driven process introduced? → about → Axiom-Driven Development
context (empty) → Question concerns adoption of the methodology.
relation (empty) → about
source_node_id (empty) → c7d327ae-c2db-4013-835e-220e18ef2853
target_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
create How are fix and change different from remove and add? → about → Commit Transformations
context (empty) → Question concerns the five transformations.
relation (empty) → about
source_node_id (empty) → 1c526f69-379d-4f97-8eaf-6b251a664ef8
target_node_id (empty) → 73c84a5b-4b6b-4c64-91ea-8bc62268052b
create How are fix and change different from remove and add? → about → Atomic Commit
context (empty) → Answer hinges on the atomic-commit discipline.
relation (empty) → about
source_node_id (empty) → 1c526f69-379d-4f97-8eaf-6b251a664ef8
target_node_id (empty) → f9123e27-d255-4544-b362-3d4b96fca9aa
create Martin Gamsjaeger → works_on → Axiom-Driven Development
attrs (empty) → {"role" => "co-author of the process"}
context (empty) → Co-developer of the methodology with Schirp and Kubb.
relation (empty) → works_on
source_node_id (empty) → 60766d79-6b2e-420b-a522-0a83a1c85883
target_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
create Markus Schirp → works_on → Axiom-Driven Development
attrs (empty) → {"role" => "co-author of the process"}
context (empty) → Co-developer of the methodology with Gamsjaeger and Kubb.
relation (empty) → works_on
source_node_id (empty) → 6d1416eb-8271-4024-8c67-28d9e5513683
target_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2
create Dan Kubb → works_on → Axiom-Driven Development
attrs (empty) → {"role" => "team leader"}
context (empty) → Team leader who drove years of refinement of the process.
relation (empty) → works_on
source_node_id (empty) → 8f8a1a20-008c-421c-a7ee-9c36fdc8861f
target_node_id (empty) → 6e402747-fab7-468a-be15-ac2362f40be2

Read set

72 nodes

concept Mutation Testing search_nodes concept Mutation Testing Preconditions search_nodes concept Incremental Mutation Testing search_nodes takeaway Start mutation testing incrementally search_nodes question Has Mutant been run against popular Ruby libraries? search_nodes question Experience with mutation testing in other ecosystems? search_nodes talk Mutant on steroids search_nodes tool Mutant search_nodes talk Mutation testing workshop wroclove.rb 2019 search_nodes takeaway Mutation testing replaces dumb review questions search_nodes person Markus Schirp search_nodes question How to integrate Mutant with CI search_nodes concept Mutation Operator search_nodes question Can Mutant guide refactoring? search_nodes talk Setup and operation of mutation testing in agentic world search_nodes tool Heckle search_nodes question What to do with an apparent equivalent mutation? search_nodes talk Development with axioms search_nodes+get_node_edges concept Application Logic vs Business Logic search_nodes takeaway Mutant as complexity metric and refactoring guide search_nodes concept Aspect-Oriented Programming search_nodes concept Developer vs Programmer search_nodes concept Breadth-First Search for Code Removal search_nodes question How to detect coupling in a large existing project? search_nodes question How to do DDD remotely? search_nodes takeaway Stable commits enable bisect search_nodes question How is the event-write kept consistent with external operations? search_nodes takeaway Immutable Database Raises Mistake Cost search_nodes concept Snapshotting search_nodes tool git bisect search_nodes concept Event Store search_nodes concept Reservation Pattern search_nodes takeaway Contribute to Arkency aggregates repository search_nodes concept Vector Clock search_nodes takeaway Replay-Based Debugging search_nodes event wroclove.rb 2019 search_nodes event wroclove.rb 2018 search_nodes event wroclove.rb 2023 search_nodes event wroclove.rb 2024 search_nodes event wroclove.rb 2022 search_nodes event wroclove.rb 2025 search_nodes event wroclove.rb 2026 search_nodes talk Building LLM powered applications in Ruby search_nodes talk International cooperation in IT teams search_nodes talk One machine please, make it Turing search_nodes talk Events events events search_nodes talk No 'Pundit' Intended search_nodes talk On the tasteful journey to Yippee search_nodes talk Webmock unmocked search_nodes talk Kamal is not harder than your PaaS search_nodes concept Zero-Disconnect Deployment search_nodes takeaway Sign serverlessforruby.org petition search_nodes concept Entity Caching and Snapshotting search_nodes concept Mutator Layer search_nodes talk Adventures in durable execution search_nodes takeaway Prefer conventions over custom code search_nodes takeaway Hindsight is 20/20 — don't judge past code search_nodes takeaway Metrics Alone Don't Fix a Coupled Legacy Codebase search_nodes takeaway Avoid complexity before fighting it search_nodes concept Boolean Flags as Implicit State search_nodes takeaway Stop delegating decisions to popular library authors search_nodes tool RealtimeBoard search_nodes talk Offline Sandwich Focus Workflow search_nodes project DataMapper 2 search_nodes tool DBM / SDBM / GDBM search_nodes concept Flat Query Structure search_nodes person Kuba Suder search_nodes person DHH search_nodes concept Context Map search_nodes talk How wroclove.rb impacts developers and companies search_nodes person Emiliano Della Casa search_nodes concept DDD Whirlpool search_nodes

3 edges