The Functional Core, Imperative Shell pattern is just so exciting! 🔥
This pattern enables us to use functional programming for what it does the best, and to use imperative programming for all the messy, mutable, side-effectful stuff that most applications also need to do. And what makes this pattern super nice is that it provides a clear separation between the two programming styles, so they can peacefully coexist in the same application.
The Functional Core, Imperative Shell pattern is similar to Hexagonal Architecture, Ports and Adapters, Clean Architecture, and similar styles that, a bit simplified, are characterized by two key architectural attributes:
- There is a core with the core business logic, and a shell that handles interactions with the outside world, such as persisting data in databases or providing UIs to interact with end users.
- The shell can call the core, but the core cannot call the shell and the core is even unaware of the existence of the shell. This is also known as the Dependency Rule (see, for example, Clean Architecture to learn more about this rule).
An additional architectural attribute in the Functional Core, Imperative Shell pattern is, unsurprisingly, that the core should be written in a functional style, meaning using immutable values and pure functions.
The key objectives in the Functional Core, Imperative Shell pattern is to separate functional code and imperative code, and to minimize the imperative code, so when in doubt whether a piece of functionality belongs in the core or shell, then make it functional and put it in the core.
💡 Book Tip: If you want to use Domain-Driven Design and functional programming (for example, in the Functional Core, Imperative Shell pattern), I can warmly recommend Domain Modeling Made Functional, a truly awesome book 👍
In practice, the core will often be an instance variable in the shell. The shell will call the core with a value and get a new value returned, and then do side-effectful, imperative stuff, like displaying it to a user or storing it in a database, with value returned from the core.
If you’d like to read more about the Functional Core, Imperative Shell pattern, I recommend the links below:
- Functional Core, Imperative Shell
- Functional core, imperative shell (a Hacker News discussion)
- Functional Core, Imperative Shell in TypeScript (my demo implementation in TypeScript).
Thank you for reading. Hope you will find this pattern useful. If you know someone who might enjoy this article, please share it 🙏