Domain-Driven Design vs. “Functional Core, Imperative Shell”

Sometimes different paradigms are forces that pull our code in different directions. I’ll try to describe such a situation with concerns from Domain-Driven Design and Functional Programming.

Anton Stöckl
9 min readMar 28, 2022

Using the tactical patterns from Domain-Driven Design we sometimes have to inject dependencies into aggregates or entities, because they are necessary to fulfill the functionality of those domain objects, e.g.:

  • a repository that the aggregate needs to query
  • a remote service that the aggregate needs to send a command to

The way to avoid that the domain depends on some infrastructural concern is to define the interface for the dependency in the domain so that the dependency goes the other way round, the infrastructure depends on the domain (aka. Inversion of Control — IOC).

So far, so good, this is a known pattern. Except that we might still want to avoid such synchronous dependencies because they create runtime coupling. If the dependency needs IO (network) we have an issue. IO is not reliable, not deterministic. From the point of view of functional programming, as soon as IO is involved, a function is not pure and we don’t want to call impure functions from pure functions.

As we can see we have multiple reasons to avoid such dependencies. Sometimes the solution is to…

--

--

Anton Stöckl

Domain-Driven Design, Hexagonal Architecture (aka. Ports&Adapters), Go, Elixir, Event-Sourcing & CQRS, Learning Designer for Software Developers @ MaibornWolff