Developers quite often face the necessity to optimize the local storage of an app. It may include a variety of factors. From substituting one of the libraries to changing the whole architecture of a project. In this article, we’ll show you how you can increase the performance of the e-commerce app and what should you do to receive such an order.
What did we have? We received the order from our client to analyze the architecture of his mobile application and optimize it. The app was created to help sellers, sales managers, and experts to interact faster and better with the buyers. This e-commerce app allows viewing available goods in the store, check their affordability at the warehouse, add items to the cart, and place orders with in-store pickup or personal delivery. The client wanted to increase the performance of the e-commerce app and advance the efficiency of employers.
What was the workflow?
We divided the workflow of our specialists into several steps to cover the task.
- Analyses of the app architecture, key UX design mistakes;
- Defining ways to organize the database of the app;
- Analysis of the app functioning;
- Optimization step.
Analysis of the app architecture
In the analyses process, we found out that the information in the e-commerce app is dynamic (renewable). The app presents the info about available goods in the store, their affordability at the warehouse and other stores, and bonuses of users in the local bonus program. The interaction with the server is implemented to get the necessary information. User authorization is processed via the third-party local app of the client’s company.
If a user needs certain goods fetching, he/she can use a variable app filter system. Filters update automatically via the server according to the input parameters of a user’s inquires. The data in JSON format for the goods are coming in reply, they are processed and stored. Then per-page data output with the ability to change goods list displaying is fulfilled.
If it’s needed to authorize or register a user in the app to place an order or see the bonuses, data exchange with the server is also implemented.
Problems in the development process
During the development process, some problems with the implementation of certain elements appeared. It leads to bad usability and the inability to expand its functional opportunities. For example, it was planned from the beginning that the app would need its own database and all the data would be received from the server. And the app only provided a temporary cache. But later it turned out that sellers close the app quite often. The cache is cleared and they had to wait again till the big inquiries with the big data would come. In other cases sellers were using the app for a long period, however, due to the fact that the cache was temporary, it was cleared and users had to wait for the data anyway.
Despite this fact, the development process was often delayed because of the uncontrolled changes by the client. This practice positively influences the result, though makes the process more durative. It’s obvious, that the changing of one feature leads to changing many others.
The absence of testing in the development process should also be mentioned. It’s recommended to write and use tests regarding the expected behavior of the functional. In other words, to apply TDD. Its absence leads to a decrease app security.
Because of these problems the client made the decision to reconsider the original approach to the project architecture and refactoring.
It was supposed that all the data would be stored at the server. Since they are updated quite often, there was no need to store them on the device. That’s why a temporary cache without the local database was implemented. The MVC architecture perfectly fits these conditions. Since the data updates automatically, data management and storage were not needed. There was also no need for interaction of the controllers with each other, as there was a limited number of screens and a coherent transition between them.
However, the structure of the project expanded significantly during the development and support of the app. A great number of new features for new app screens appeared. Besides, new several tabs were implemented that contained the volume of transitions and interaction between the components and fit into previous project realization. It was needed not only to provide a coherent transition between the controllers but also the ability to return to previous conditions of the app and interact with separate app tabs. The basic architecture of the app didn’t cope with that.
In using it turned out that the caching functional isn’t enough for quick app work. Because of that, the staff complained about low app work and constant upload.
Thus, it was decided to change the architecture of the app and add the local base to increase the performance of the e-commerce app.
Approaches to organizing a local database of a mobile app
In most mobile apps the main information that is shown to a user is stored remotely at the server. The app inquiries this data via API.
For our mobile app for sales consultants, there is also API. However, the amount of data is big and they are stored at different servers. To receive them a mechanism of the synchronization of different inquiries groups is needed. Dictionaries provide this mechanism in an app.
Dictionaries store links to different servers and the information needed for inquiries to every server. They update every time when the app is launched by a separate inquiry. Then every new inquiry needs the information about one of the servers from the dictionaries. Accordingly, the app stores these dictionaries locally so that it wouldn’t send inquiries every time.
In general, there were few dictionaries and store information in the app. However, we needed to solve the problem of the complete absence of the information if the app lost the connection.
It was decided to use request caching for this e-commerce app. Every item request is unique and there are a variety of possible filtering ways and other requests to depict the full information about goods. That’s why it was rather challenging to predict what info would be requested.
We used NSCache to implement caching in the app. Its implementation is quite simple and doesn’t require additional settings.
Nevertheless, the app started to grow and it required more space to store more data. So we decided to use a local database instead of caching.
Local databases can store big data and they are not cleared when the app is closed. It allows optimizing resources assigning in the app memory and not to request a great amount of non-updateable queries.
The most popular local bases are Realm and Core Data.
The advantages of Core Data:
- Availability out of the box, what allows to save an app size;
- This stable framework is the basis for every kind of apps;
- The text search and big data volume search speed is high;
- Storage is one of the standard data formats.
The advantages of Realm:
- Laconic record and easy use;
- Encryption support and data synchronization;
- Work speed at relatively small data volume.
We decided to use Realm. It’s more simple in the implementation process and this positively influences its support. Moreover, it optimizes the work with data increasing the speed of work.
Analysis of the e-commerce app functioning
The new architecture should provide the ability to work with the local base. It’s important as well to save the key implementation features of the app. For example, the project uses Swinject. It is a light framework for dependency injection in Swift. Clean architecture is used for architecture implementation. It should be also saved in the app.
Of course, a new architecture shouldn’t differ significantly from the previous one, because the terms for reengineering and refactoring were limited. It was necessary as well to consider the time for regression testing that shouldn’t detect many bugs in the previously implemented features.
We chose MVC, MVP, MVVM-C, and VIPER to implement a new architecture. Each of them offers its decisions to solve the set tasks and has a number of features to be compared. We chose variant analysis to choose the best architecture approach for our project. We made a pair comparison according to their criteria and the importance between them. Based on the results we defined that the best decision was to use MVVM-C architecture. It’s quite simple in support and implementation due to the experience of the project specialists. An additional modification of the coordinator allows solving the problem of the routing of user navigation between the screens. This architecture as well as a good separation of concerns between its modules improving their testability.
Realm supports the migration system that allows users to update its database in case of change. That’s why you should signify its version every time you create a configuration. You can also state how the database will be updated, the conditions of its updating, and the version according to the conditions. All changes of Realm database are processed inside the write transaction, so we created the block that simplifies the record of data in the base conducting all required tests.
To record the data into Realm the object should be a descendant of a basic Object and possess the field primaryKey. A basic class that created this field was created for objects that originally don’t possess it.
The local storage let significantly reduces the time of the program launching. Now it accounts for approximately 5 seconds instead of 12. It also lets get rid of reloading of previously downloaded data during the app work. This all increased the performance of the e-commerce app.
Besides, the new delegation method was implemented for the app's new architecture. A delegate is a link to the instance of another class that can take the part of responsibilities for response to a certain situation. However, there is a considerable problem with such an approach. Delegation means the restraint of a link to the object of one class by another. This leads to memory leaks that can be difficult to control.
Bindings can help to decide the delegation problem and optimize the app work due to the elimination of memory leaks. Bindings don’t restrain one object from others. They work on the principle of subscription of the object to an event. If this object is unbound from the memory its subscription will be deleted with it. We used ReactorKit to implement bindings in the app. ReactorKit is a platform for reactive and one-direction architecture for Swift apps. It is a combination of Flux programming and reactive programming. A user’s actions and the view state are delivered to every level via observable streams. These streams are one-directed. The view can only generate actions and the reactor generates only conditions.
The structure of the app was also changed and now it satisfies the Clean method. All the app is divided into layers. This helps to navigate better in the code and simplifies its support.
The new architecture positively affected the responsibilities assigning between the app modules. And that in its turn affected well the testability. Now every architecture module fits the principle of responsibility. Heavy routing logic was transferred to separate coordinators.
Optimization of the app response speed and the speed of user interaction with heavy tables was done. Due to the transfer from delegation to binding, it was achieved what allowed getting rid of memory leaks in the app.
As a result, our team managed to fulfill all the client's requirements and significantly improve the performance of the e-commerce app. A separate aspect for improvement is ensuring the security of the application. We have written a special guide about this, where we described in detail all the optimization steps. And if you have a project idea, write to us and we will discuss with you all the details of the project!