Understanding The Elm Architecture
It’s common in the software development landscape for developers to use frameworks and programming languages that are trending, especially amongst new-comers. You may already know this and you probably hear it often from your fellow senior colleagues, but it actually all depends on the context. There is no single-language, architecture, or framework that is always the best option.
It’s easy to come across these thoughts when introduced to a new tech-stack for a project and wonder why the technologies were chosen. My most recent occurance of this was Elm. Although the Elm language wasn’t used in the product, there was a thin React wrapper that mimicked the Elm architecture called React-tea-cup. First thought that went across my mind was, why aren’t we just using standard React? The reason Elm was used was because of its unidirectional functionality for data streaming, and taking advantage of its reactive programming features.
What is Reactive Programming and what are the benefits?
You may have already heard of functional programming before if you’re familiar with JavaScript or TypeScript. Those two languages are built on functional programming paradigms. Reactive programming, however, is much different.
Reactive Programming is a paradigm which leverages asynchronous programming to allow applications to handle real-time data processing. It is used more commonly in enterprise Java applications with micro-architectures in mind. It listens for events to trigger “state” changes that propogate throughout the application, and does this without IO blocking. This results in high performance and concurrency, which is crucial for large applications catering to millions of users.
Upon hearing the idea of state changes in app views, React.js may come to mind. Although state management sounds similar to this concept of events triggering state changes, React.js is not a purely reactive programming framework. React.js is a declarative framework and some of its principles are derived from reactive programming, however, there are several key differences which will be explained later on.
What is Elm?
The Elm Architecture (TEA) is a programming pattern that is used for web applications handling interactive views and updating states. The flow is very simple: user interacts with the UI, which triggers an event to modify the application’s state, which is then reflected in the updated UI.
Elm consists of three major pieces: Model, View, and Update.
The Model is the part of the application which acts as a screenshot of the application’s current state. This encapsulates data for the app which can be modified by event triggers, such as a variable for the number of times a button is clicked.
The View is the front-end user-interface generated from the current state of the model. If we use the previous example, the view could be the HTML page showing a number and a button, where the number is the value of the state variable. It doesn’t necessarily need to be variables displayed, it could also be something like a page displayed only if the user is logged in, or a list of items rendered based on the data. In essence, the view is what the user can see, and it is influenced by the current model.
Update is a part of the process, and takes the form of a function. It looks out for a trigger from the client (i.e. a button click) and consumes this event message, returning an updated state. When consuming the message, the update function will perform some logic to calculate/modify the state, such as adding one to the number of times the button was clicked.
These core components will be the foundation when designing an Elm application. As illustrated in figure 1, we can see that data flows in a singular direction: view to model and then back to view.
Weighing trade-offs
Now that we have established what reactive programming and elm architecture are, how do we decide when we want to use them?
We previously discussed that reactive programming is great for real time data processing and unidirectional data flow, and Elm is a purely reactive programming language (PRP) that utilizes TEA architecture. TEA is also good for predictable state management and gives us the benefit of easier debugging. Since data flows unidirectionally, it is easier to track the data and know where it came from/where it ends up. This results in centralizing the application’s state.
The issue arises when we have a large system in place, such as one using microservices. Microservices thrive off of decentralized data to avoid single point of failures and establishing independence for each service. Since the state data is centralized, it creates a disadvantage in using TEA with microservices.
However, this doesn’t necessarily mean that TEA should not be used with microservices. The keypoint here is it shouldn’t be the single point of failure. Elm applications can still be used in microservices as long as the model isn’t capturing the state of the entire application. The model can still be used to manage the state of a micro-frontend, as drawn in the below comparisons. This keeps the service independent and the application can still take advantage of TEA. Data is fetched from the individual microservice, and the model state is preserved in the corresponding micro-frontend. Another possible solution is to use API gateways to handle backend processes. Since API endpoints have been separated from the service, the Elm model will not be tightly coupled to any backend model changes.
Ofcourse, these are very high overview solutions and aren’t a one-size-fits-all. There are advantages in using Elm and there are disadvantages as well, however, the disadvantages can always be worked around depending on the context of the application at hand.
Why would I use React-Tea-cup over just React.js?
React-tea-cup is a light-weight wrapper that provides Elm architecture for React apps. TEA has also inspired state management in Redux (a React library), however, React isn’t purely reactive.
React.js takes some principles from reactive programming, but is still a declarative UI library. The declarative approach is where the desired UI state is described, whereas the reactive approach leverages data streams to manage the “how” for states.
When the application requirements involve constant data changes that must be reflected in the UI, it makes sense to use a reactive approach. React.js does have features that mimic reactive programming such as useState() and useEffect(). These features do trigger re-renders in the DOM due to data changes, but because the data is not streaming, it is not considered purely reactive.
Therefore, if an application requires data streaming and a componentized front-end, React-tea-cup is available to provide this, and all the benefits of reactive programming.
Conclusion
It’s important to see the bigger picture when coming across a new product’s codebase. Each framework, architecture, and language has its own pros and cons and perform their best when used correctly. It’s very useful to take a deep-dive into the fundamentals of each part of the tech-stack you’re working on to better understand how everything fits together. This will also help you understand business requirements and get to know the product better.
#SoftwareDevelopment #ReactiveProgramming #Programming #Developer #SoftwareArchitecture #Elm #Architecture #React #Code #Coding #Software #Tech #Framework #TEA