This is how we decided to do Frontend at Invisible
Having always relied on Slack as the main interface for most of our work, we have done without our own UI for a while.
As of now, the time has come, to build a scalable, simple and fast user interface that actually responds to our exact needs.
For that we decided to craft our Frontend stack with as much care for details as we can afford, so that we can be able to build simple, reactive and functional frontend applications that are easy to scale, and that also honor our technology principles.
Since we care to abide by functional principles as much as we can, we wanted our state management system to be reactive, so that we would be able to subscribe to state changes, and be able to react to those changes appropriately.
In other words, we wanted our view to “react” to state changes and preferably have such reactive subscriptions be automatically handled, instead of relying on manual subscription and risk state divergence and inconsistency as our application size grows.
Luckily, this problem was very well solved by MobX !
Upon picking up a list of candidate libraries that could serve as the backbone of our state management system, MobX has really stood out thanks to the simple API it provides and the principles it preaches. It was a great fit for our needs.
MobX provides the necessary tools to manage your state well, in the sense that you can distinguish your state mutations by putting them in actions, and also enforce every mutation to be wrapper in an action, and separate the reactions (such as UI updates or calling a webhook to notify another service) that follow those mutations pretty elegantly, and especially without having to manage subscriptions to state changes.
However, it is to be kept in mind that although MobX provides the tools, it does not provide the patterns to manage the state, so it was still for us to decide on that part if we wanted to go with MobX.
When it came to our rendering engine, we wished to remain on the same track and try to be as consistent as possible, by having a reactive rendering library that would fit our technology principles and our newly picked library (MobX).
It’s pretty hard to not choose React if you are intending on building big Frontend applications that scale, given the modularity, performance and elegance it can leverage to your application.
Preact was a great candidate, and we almost ended up picking it over React since it provides the same API for lesser size, but since we are not concerned about the application size at this point, and since we entertain the idea of having a mobile app in the future, React was ultimately the right choice for us.
But you might ask for a second, if you are going with React, why didn’t you just go with Redux and have superior compatibility? Isn’t Redux built on functional programming principles?
A very good question, we had to ask ourselves the same question before having decided on MobX, we still needed a pattern for state managment at that point anyway…
Design Pattern: How it all ties together, Data Binding, State Management and User Interface
One of the main reasons we gave a pass on Redux is because we were not interested in having Flux as our main design pattern, we wanted something a lot more simpler…
We wanted to represent our frontend models through MobX observables, be able to react to Mobservable changes to calculate the state and update the view, and we wanted to do it as simplistically as possible.
I’ve had the chance to take a closer look at the SAM Pattern, and I have tried to bend it and criticize it as much as I can as to be able to judge the value it can bring to our frontend engineering principles, and it really proved to be usefully simple.
The SAM Pattern -as is stated in its main website- challenges the unnecessary complexity that is often brought by other patterns.
At the right level of abstraction, most of the patterns we use are just some kind of derivative of the Separation of Concerns principle, so for a second, the SAM Pattern might not look very different from MVC, nor Flux to a certain degree, in the sense that they all try to separate concerns, to decouple data representation and rendering from data mutation and business logic, but as JJ Dubray mentions, implementation details make the most difference.
To express how simple is the SAM Pattern, we can really briefly describe it as:
View = F( Model ) \ whereas Model is your data model, and F is a pure function
This very simple formula allows for a high level of flexibility, providing us with the ability to define the intricate details of F.
As far as state management is concerned, the SAM Pattern enforces the pattern of representing your models’ mutation as pure functions (that you will call actions) whose sole role is to “propose” a mutation to a model, by actually returning the mutation itself, and from that point on, it is up for the model to decide on what to do with those changes.
The application state is then a pure function of the model and the action, that is computed upon model changes and passed to the view, and ultimately updating it with latest state changes.
This simple yet powerful concept allows a higher decoupling between the view layer and the data layer.
So, the way we defined our F function is:
F: model -> Render(State(model))
So our whole frontend application is litteraly just:
View = Render(State(Model(Action)))
With the Model being our frontend “data-scheme” and “container” which is implemented as MobX Observables, the Action being the mechanism by which we mutate our data (say after an API call or upon an event), and lastly the application’s State being a pure function that is reactively computed based on the Model changes, which is then rendered as the View. (thanks to MobX reactions)
Having implemented the SAM pattern with MobX and React has allowed us to have a real simple Frontend architecture that has allowed us to speed through development and also guarantee that our code can scale as our needs grow.
We’ve managed to very simplistically implement the SAM pattern, which has resulted in a small library that we are thinking about open-sourcing in the right time.
We will soon be releasing an in-depth article describing every important detail we’ve implemented and how we’ve done it, and we pretty excited about it, so please stay tuned!
We were pretty excited about the second version of the Digital Assembly Line in the Engineering Team, as we starting from a blank canvas, we regard this as an opportunity to build a more robust and scalable architecture.
Having mashed up our own implementation of the SAM Pattern made it even more interesting, as we’ve won significant flexibility and speed in development, allowing us to gain more on what capitalize on the most at the engineering team, Developer Time.
This has allowed us to focus more on our business needs and less on bugs, but more importantly, It has enabled us to have the necessary time to craft our software with care and smoothness, so that we can deliver maximum value to our clients.