Mattermost Mobile — From Vision to Architecture

Introduction

This is the second essay in a series of four essays, as a part of Delft Students on Software Architecture 20221. Mattermost is an open-source platform for team communication, and Mattermost Mobile is the app to use Mattermost on mobile devices In the previous essay, we explored the problem Mattermost is trying to solve and the vision behind the Mattermost Mobile app. Now we dive into the architectural choices the Mattermost team made to realize this vision.

Main Architectural Style

Two common ways of building mobile apps are native and cross-platform development. In native development, a separate codebase is created for each operating system that the app needs to work on. In cross-platform development, there is only one codebase, which is then compiled to multiple platforms’ native languages. Mattermost uses React Native for cross-platform development for mobile apps.

There are several advantages to cross-platform development. First, one codebase can be used to create an app for multiple operating systems, thus reducing the amount of code needed to build multiple apps. Also, when using a library like React, a large ecosystem of supporting libraries is available for things like routing and animations2 that can be used for functionality shared between the iOS and Android apps.

Second, since a reasonable amount of the development of the app is done by open-source contributors, it is beneficial to choose a library, framework, or language that many people know. React is the most used frontend JavaScript framework3 and is commonly used for web apps and cross-platform development. This makes it a good choice to lure in some open-source developers for a project.

A downside of using a cross-platform framework is that the performance is usually suboptimal compared to natively built apps4. Also, debugging code might be harder when the code you are testing has been compiled to another language. From these advantages and disadvantages, it becomes clear that trade-offs need to be evaluated when deciding on the architecture of a mobile app.

There are also other alternatives for developing mobile apps. Google, with Flutter and Microsoft, with Xamarin, have moved towards comparable systems to React, where a single codebase is compiled to different native representations. Uber has developed a different framework, having a unified architecture called RIBs but not a unified codebase: code is still specific to the targeted operating system. For fully native apps, there are also many alternative architectures. Most well-known is the Model-View-Controller (MVC) architecture, but many alternatives exist, such as MVVM and its spiritual successor VIPER.

Design Principles Applied

Mattermost Mobile is built with React Native, which is used to transform React code into native applications. It is important to distinguish here that while React is a user interface library for web applications, React Native is a framework that compiles code (mainly JavaScript, with some additions) to languages that can be run natively. In this section, we first explain what React is. Then, we explain how Mattermost compiles mobile apps using React Native.

React

Mattermost Mobile is written primarily in React. The main design principle of React is that every part of the user interface is a component. Components are arranged in a hierarchy, which means that a parent component can draw many child components. Using components makes it easy to adhere to the single responsibility principle, which states that every part of a computer program should have just one responsibility5. Using components creates a modular, reusable, and testable codebase.

Components use state, which are variables that upon change will cause the component to rerender. State can be passed down from component to component so that child components can access data from their parent component. Mattermost uses this architectural style of component inheritance in their app. For instance, the channels and the settings sidebar both present a list of elements and therefore reuse the drawer_layout component.

State that is used by many components does not have to be passed down but can be accessed from any component using global state. For this, the Redux library6 is commonly used. This library is also used by the Mattermost Mobile app. Redux stores global state, which any component can access and modify.

React Native

React Native is a framework that can be used to transform React code into native applications for multiple operating systems, such as Android and iOS7. React code is compiled to the native components that are used on the operating system to create a native experience. The image below8 shows an example of how Facebook is rendered differently for both iOS and Android.

Figure: Cross development frameworks like React Native allow developers to use native components of an operating system to create a native feel.

Containers View

Mattermost as a product is larger than the mobile applications we are looking into for this essay. Users can also access Mattermost through a web app and desktop application. These three environments send requests to the server which is connected to a data warehouse. Mattermost plugins9 are written separately from the main repositories and extend the functionality of the server and web app. We chose the Mattermost mobile application as the subject for our essays, so we will not go into further detail when it comes to the other containers.

Figure: Overview of the container structure of Mattermost.

Components View

As explained in earlier sections, the main architectural choice for the Mattermost Mobile app is the choice to use React Native as the underlying framework. The React component structure is described in detail in the next section on the Development View. However, that doesn’t mean there is only React Native code in the project. Taking a look at the GitHub repository, we see there are also small amounts of Swift, Objective-C, and Java code in it. These are the languages you’d use for native iOS and Android apps if you weren’t using React. So maybe there are some non-cross-platform, native parts here?

Figure: Languages used in the Mattermost Mobile repository.

Diving into the repository, we see that there indeed are. There are ios and android directories, containing Swift/Objective-C files and Java files, respectively. In both of the directories, the files can mainly be divided into two pieces of functionality: push notifications and sharing. The first are notifications sent from the Mattermost server, for example about new messages10, where the extension is used to customize content the server sent in the notification payload11. The second functionality allows users to share to Mattermost using the system’s share button, for example, to share a link from the browser via Mattermost.

Figure: Sharing functionality, here shown on iOS.

These parts are written in the native system language (respectively Swift and Java for iOS and Android) because they are not cross-platform: each implements platform-specific notification and sharing functionalities. Therefore, writing them in the native system language may be more logical and allows reuse of iOS and Android example code provided by Apple and Google.

Figure: Overview of the components of the Mattermost app.

Development View

From the development view, the system can be decomposed into a main module, two platform supporting modules, two modules (sharing and notifications) providing extra functionality, and another two modules (Detox and Fastlane) targeted at supporting the development of Mattermost itself. Mattermost has documented the outline of their folders and files12.

The main module is the app module contains most of the structural code of the app. It is entirely written in React Native, and consists of a combination of TypeScript and JavaScript files. The app module is divided into multiple submodules, each offering a specific functionality. We cover a few of these submodules next.

The screens submodule contains all the screens the app offers, these include the about screen, the channel info screen, and the channel members screen. The components submodule contains the main widgets used to build the screens. These include channels, pickers for emojis or reactions, error messages, and sidebars. The actions submodule contains the script for executing certain actions, such as navigating the app, posting a message, or creating a channel. The redux submodule, which is made up of actions and reducers, manages global state in the app, such as the theme the user has selected. The i18n submodule contains the files for translating the app to other languages, stored in JSON files.

The two platform supporting modules are the android and ios folder. They contain the code that is necessary to convert the React Native app to a platform specific app. These files are configuration files, assets such as fonts, files serving as interface between the iOS code and the React Native code, and files for platform specific actions such as notifications and sharing files.

The two modules providing platform-specific functionality are the share extension and the notification service, which we described in the Components section.

The two modules for supporting the development of Mattermost are Detox and Fastlane. Detox is a library for end-to-end testing in React Native and automation. Fastlane is an open-source platform aimed at simplifying Android and iOS deployment. It is used to build, deploy and submit the app.

Figure: The development view of the Mattermost app.

Runtime View

At runtime, the native components are bundled with the React code, which gets translated to a native representation for each operating system. These native representations are fast and optimized, which is one of the reasons why performance of React components can be similar to pure native components13.

Of course, due to its client-server architecture, the Mattermost app also needs to connect to the Mattermost server. It does so using WebSockets, which are well-suited to the real-time, bidirectional nature of messaging14. Additionally, Mattermost uses iCloud, since some of Mattermost’s dependencies include support for iCloud backup, but Mattermost does not use iCloud storage of APIs directly.

Notifications and sharing functionalities are also part of the app, but do not run in the same process for security and performance reasons15. They communicate via a version of remote procedure call (RPC) with the rest of the app. For this, Apple requires the use of App Groups: Mattermost creates a single app group, of which the main app, share extension, and notification service are members. On Android, Mattermost uses Intents, which similarly allow the main Mattermost app to communicate with its children, such as the system share sheet.

Figure: Overview of the runtime view of the Mattermost app.

Key Quality Attributes

In the first essay, we identified some key quality attributes that apply to Mattermost. Some of the architectural choices that the contributors have made allow Mattermost to perform well on these specific aspects.

Detox is used to implement automated end-to-end testing. When new contributions are automatically tested, it is less likely that bugs enter the application. So the reliability of Mattermost is improved by using this framework.

The component-based work method of React allows for a flexible architecture. Components can be added, removed, or changed with relative ease. This allows the application to scale with an ever-changing market and adapt itself to the needs of different industries. Any changes made to the React components will carry into the iOS and Android applications, so these changes only need to be implemented once.

Fastlane is used to simplify and speed up the deployment and release process16.

Detox, React and Fastlane all contribute to a quick development process. When issues are quickly developed and deployed, the application is much easier to modify and extend. This creates a codebase that is flexible and reliable.

Conclusion

In this essay, we outlined the architecture of the Mattermost Mobile app. The mobile applications are built using cross-platform development. In this case most of the code is written in React, which is compiled to native platform applications by React Native. The building and deployment process is automated using Fastlane. Detox is used for end-to-end testing. These three technologies help to create a quick and flexible development process. This way of working has its effect on the system’s quality. We will analyze this further in our third essay.

Sources


  1. https://2022.desosa.nl Delft Students on Software Architecture: A blog on the architecture of open source software systems written by students from Delft University of Technology. Accessed: 12-Mar-22 ↩︎

  2. https://github.com/enaqx/awesome-react Awesome React: A collection of awesome things regarding the React ecosystem. Accessed: 9-Mar-22 ↩︎

  3. https://cult.honeypot.io/reads/best-frontend-javascript-frameworks-learn-2021/#:~:text=1.,four%20years%20by%20JavaScript%20developers. Best Frontend JavaScript Frameworks To Learn 2021. Accessed: 9-Mar-22 ↩︎

  4. https://medium.com/walmartglobaltech/native-vs-cross-platform-322e9896e745 Native vs React Native by Shilpa Bansal. Accessed: 8-Mar-22 ↩︎

  5. Single-Responsibility Principle - Wikipedia https://en.wikipedia.org/wiki/Single-responsibility_principle. Accessed: 13-Mar-22 ↩︎

  6. https://redux.js.org/ Redux: A Predictable State Container for JS Apps. Accessed: 8-Mar-22 ↩︎

  7. https://en.wikipedia.org/wiki/React_Native React Native. Accessed: 8-Mar-22 ↩︎

  8. https://www.purrweb.com/blog/cross-platform-design/ Cross-platform app design: 3 ways to build React Native UI/UX Accessed: 9-Mar-22 ↩︎

  9. Mattermost Plugins: An Introduction. https://developers.mattermost.com/contribute/plugins/ Accessed: 8-Mar-22 ↩︎

  10. Specifically, these files are needed for sending notification receipts, which acknowledge to the server that the notification has been received. ↩︎

  11. https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications Modifying Content in Newly Delivered Notifications. Accessed: 8-Mar-22 ↩︎

  12. Folder Structure at Mattermost. https://developers.mattermost.com/contribute/mobile/developer-setup/structure/ Accessed: 8-Mar-22 ↩︎

  13. https://reactnative.dev/docs/performance Performance Overview Accessed: 11-Mar-22 ↩︎

  14. https://sookocheff.com/post/networking/how-do-websockets-work/ How do websockets work? Accessed: 11-Mar-22 ↩︎

  15. Understand How an App Extension Works - Apple https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html. Accessed: 13-Mar-22 ↩︎

  16. https://fastlane.tools/ Fastlane: App automation done right. Accessed: 8-Mar-22 ↩︎