To add to what @peerreynders and @gregvaughn have said,
Even in OOP the best way to determine abstractions (use of design patterns) was to look at the messages between objects. Regardless of if the objects were calling methods on each other and it wasn’t at all the same as a BEAM process messaging - the way to figure out how to decouple and configure dependencies was too look at the messages and the contracts between components.
The difference lies with imperative OOP-style vs actor model and how first-class messaging is. To achieve architectural goals by inverting dependencies and implement decoupled systems with imperative-OOP requires (in my opinion) more overhead and complexity. So much so that there are entire books about the design patterns! (I really like Sandi Metz’s books on OOP because there’s less emphasis on the design patterns and more on the messages). Regardless it’s more straightforward in our actor model world. Maybe messaging contracts seem scarier because we don’t have a handy book of conventions to use?
The part of Domain Modeling Made Functional I really liked was his description of different messaging contracts between contexts. Scott broke it down into three different types (paraphrasing):
Shared Kernel: A shared module that separate bounded contexts or pieces of the system depend on. A given change requires coordination between both contexts. This entails high coupling and costs in exchange for properties like compliance and preventing breaking changes made by one team.
Consumer Driven: The downstream consumer of messages dictates how the producer must behave. If the consumer wants a change, the producer must conform to the new contract.
Producer Driven: The producer of the message controls how the consumer must behave. The consumer must comply to changes made by the producer or break.
A big shared kernel we have in the ecosystem are Ecto Changesets. Phoenix uses Ecto Changeset for Phoenix HTML. There’s a trade-off of dependencies but we get benefits of surfacing errors from changesets and reducing a lot of work. The mutual dependency is probably fine since Ecto is a well-established and stable open source project, but it’s there none-the-less.
So what the Elixir community uses (mocks / behaviours / messaging contracts) are in the same category as the gang of four pizazz but simpler because the actor model puts messages first class.