In recent years in the front-end (FE) world, especially with the rise of React as an AngularJs alternative, a hot debate has broken out on the following topic: “The best architecture for the FE application.”
So we asked ourselves: What architecture suits our needs the best, and why? How do we pick one, considering that we want to reduce the technical debt and grow the team and/or the codebase? This might be the most common problem every programmer will face at least once in his or her career.
In this article we will explain why we picked the FLUX architecture and how it can be used in a medium-sized AngularJs application. We will break down the architecture fundamentals and apply them to a real world scenario. And finally, we will discuss the pros and cons of this approach.
What is Admin about?
Admin is one of several Single-page applications (SPA) in Slido. Admin gives the user to create and set up an event according to his or her needs. It gives the user the ability to turn the Slido features on and off, and it allows him or her to manage the event in real time. It is the “single source of truth” (SSOT) for conference or meeting organizers. The user should be able to find everything he or she needs for the event to be successful there.
Slido is a technology company that enhances communication and increases interaction at events and meetings. We enable users to crowdsource top audience questions to drive meaningful conversations, engage participants with live polls and capture valuable event data. We focus on simplicity. Both for meeting planners who can create an event in less than a minute and participants who can join via any device with a simple code. Slido has helped to power audience interaction and engage millions of participants at over 120,000 events. We are proud to have worked with renowned conferences such as SXSW, Money20/20, and Web Summit and high-profile clients such as Adobe, Spotify, Lufthansa, BBC and Oracle.
At one point, Admin was a part of a monolithic structure. It covered only a few use-cases that the the organizer had at his or her disposal. Our vision was to make a complete overhaul of Admin UX/UI and to add more new features to it. Therefore — as the first step — we decided to rewrite Admin as an SPA. I was the only one responsible for the programming part but we were sure that it would not be the case in the near future.
This became a challenge in itself which prompted us to make the following critical decisions:
- Select a suitable architecture on which Admin will be built on: MVC, MVP, MVVM, FLUX, etc.
- Other things, such as: code style, maintenance, testability, code clarity, speed of development, learning curve, workflow, extreme programming principles, …
Taking the pragmatic approach we decided to use the technologies which we were familiar with, i.e. AngularJs, CoffeeScript, Grunt, Less and so forth. Later it partially transformed into AngularJs, TypeScript, Webpack and Sass.
As for the workflow we were accustomed to Gitflow. We agreed that the new parts of the code would be covered by unit tests. Pretty basic decisions and commitments. We have been dealing with things like code review, pair programming and some other core principles of XP and it has been increasingly gaining our attention as our team grew.
We decided to use the FLUX architecture.
The most important decision was to pick a suitable architecture type. We had to consider factors such as team work, complexity of the application, or the potential and very probable growth of the codebase.
After extensive research (as our team was quite junior and these decisions were made on a ‘one-person show’ basis) we decided to try FLUX architecture. FLUX was one of many trends in the world of the front-end development at that time. Therefore, I tried to approach it very skeptically and I wanted to rationalize my decisions as much as I could.
What the FLUX?!
- View represents the components in React or the components/directives in AngularJs.
- Actions is a set of operations in our component the user can make manually or automatically, such as initialization of a component or button press, opening of the modal window or showing of the confirmation dialog. Bear in mind that Actions are the only place in the architecture where we want to make asynchronous calls, like calling our external web APIs.
- Dispatcher is our central point (SSOT) and all the data in the app will flow through it. There is only one Dispatcher. It can be an ideal place for logging service, wiring web-view wrappers and so on.
- Store is the place where the internal state of the app is stored. In contains the app data from our APIs, or it can hold the state of our UI. There can be multiple stores, but most of the time only one per module. When the data is dispatched, Store will usually consume it, and if it wants, it will notify the application by emitting the “change” event. Usually there is a View subscribed to this event and after receiving it, the View will get the preprocessed data from the Store. And the circle is closed.
Pros and Cons of FLUX Architecture.
The most often mentioned pros of this architecture include:
- Unidirectional data flow. In this case, it means that the data will flow from the View through Actions and the Dispatcher to the Store.
- Minimized amount of the cognitive load. Each part of this architecture has a very specific role. Therefore, it is very easy to find about where the particular portions of the code are located. Or where and how the data is processed. Also, it simplifies the debugging process.
As for the cons of our implementation, I would like to emphasize:
- Multiple stores. On multiple occasions, we needed to set special conditions for initializing the data and handling of multiple stores in one component. For example: the questions or the polls can be fetched from the API only after the User is logged in, but the QuestionsComponent or the PollsComponent can be initialized before the User is logged in.
- Too much writing. Each part of the architecture has a specific role. Therefore, it happens that for a very simple action — which could be contained in one controller — we need to create a file with Actions, Stores, etc.
- Cloning the data vs. references. Most of the implementation (except the Dispatcher) is custom made, so we needed to cope with basic problems, such as copying the data from the Stores to the Views. Sometimes we unintentionally passed the object reference to the View which instantly resulted in a bug.
Implementation in the AngularJs.
Once we had chosen to use FLUX architecture, the next step was to implement it in Admin. In AngularJs MVVM is a standard architecture, so we needed to map the particular parts of FLUX to fit our needs.
The change was very easy. In practice, it means the following:
- View becomes a part of the Component/Directive and it is controlled from the Controller.
- Controller calls the Actions. Actions is a class with a set of methods in it.
- Methods in the Actions are calling the Dispatcher, on which the callbacks in the Stores are registered upon.
- Store consumes the data through the registered callbacks and then preprocessees it somehow. At the end it can report about itself that it is changed so it will emit an event.
Example: Events module.
Now we will explain the FLUX architecture in a real-world scenario to show you how it is used in combination with AngularJs. We will explore in more detail how this approach can enhance the migration from AngularJs to Angular in our next article.
Firstly, there is an Events module, which is used to manage the list of events in Slido. Following code examples will contain the main components and a few sub-components, its actions and store, in which its state will be stored, i.e. the event list. The user will be able to make a few actions over the event list.
Folder structure could be as follows:
As we have seen above, Views are the Components or the Directives. This is an example of how a very simple View can look like:
Actions can be called from the Controller of the View or from the View itself. In this view we have multiple actions, for example: selectEvent, duplicateEvent, deleteEvent and so forth. At the same time the action fetchAll, which initializes the event list, is available. It is invoked automatically during the component initialization phase.
This is the example of a controller:
After the initizalization of the component we are validating the user data. If the user is initialized correctly, we are trying to fetch the event list. Also, the current configuration of the component is fetched from the EventsStore. It can contain filters, ordering schemas, search patterns, etc. All actions are called from the component (or from the Actions itself).
Have a look at a simple EventsActions class:
EventsActions is an AngularJs service. There is nothing special to it. All of the API calls are made from the Actions. A few actions are available. Each of them can dispatch multiple calls, depending on our needs. The ActionTypes service is s simple class in which the properties are strings representing our action names.
There can be multiple Stores. Usually one per module. This one is for the Events module:
In the EventsStore’s constructor we register the callbacks from the Dispatcher. So it is a given that the data from the Dispatcher will flow through our store. All other commonly used operations over the data collections are contained in the ListStore. Store is the only place where the state is mutated. This is one of many aspects of decreasing cognitive load for programmers.
Pros and cons of this approach.
Implementation of FLUX architecture in Admin helped us to think about the application as a set of jigsaw pieces, each with a specific role and meaning. It also helped us to maintain a universal code style, which emerged from it and we have been upgrading it ever since. Technical debt means nothing to us, because the application can be very easily refactored. And since the refactoring is the daily routine of a programmer, we couldn’t be happier.
Despite the more verbose codebase, we maintain a generally clean code. The fact that our colleague was able to build new, production ready features in our application within only two weeks after taking on the role is our “proof”.
The next article in this series will explain how applications with FLUX architecture can be easily modified to hybrid AngularJs+Angular applications. We will demonstrate the implementation of this architecture using NgRx vendor and the near future of our beloved Admin.