The past few weeks we have explored the problem space of application architecture, and tried to uncover the root of what makes it so complicated. We ended up building a moderately complex application in the process, and although it was a bit of a toy example, it accented all of the pain points we encounter when building applications. In particular, we saw:
We want to be able to have complex app state that can be shared across many screens so that a mutation to one part of the state is reflected in the other screens instantaneously.
We want to be able to mutate the state in a consistent manner so that it’s obvious to newcomers to our code base how the data flows through the application.
We want to be able to build large, complex applications out of simple, composable units. Ideally we’d be able to build a component in full isolation, possibly even in its own module, and then later plug that component into a much bigger application.
We would like a well defined mechanism for executing side effects and feeding their results back into the application.
And finally we would like our architecture to be testable. Ideally we should be able to write tests with very little setup that allow us to describe a series of actions a user does in the app and then assert on the state of the app after those actions have been performed.
These are very important problems to solve because they allow us to scale our code base to handle many features and many developers working on the same app. Unfortunately, SwiftUI doesn’t solve these problems for us completely. It gives us many of the tools to solve it for ourselves, but it is up to us to take things the extra mile.
And so today we begin doing just that. We will introduce an application architecture that solves these problems. It’s opinionated in much the same way that SwiftUI is. It tells us exactly how we are supposed to model application state, tells us how mutations are applied to that state, tells us how to execute side effects and more. If we follow these prescriptions some really amazing benefits will start to pop up. And of course, the most important part, this architecture is entirely inspired by functional programming! We will draw inspiration from simple functions and function composition in order to understand how we can solve all of these problems.
We of course don’t claim that this architecture is a panacea and will solve all of your problems, and there will definitely be times where it seems that the problem you are working on simply does not fit this framework. However, we still feel that it’s worth exploring these ideas, and it can also be surprising how many problems can be solved with this architecture if you look at the problem from the right angle.