Efficient Foundations for Building Long-Term Mobile Applications

Georgi Stanev
Prime Holding JSC
Published in
16 min readJan 19, 2024

Introduction

Let’s explore the most effective strategies for laying the groundwork for a long-term, complex mobile project that requires a sizable team and years of development. We will use Flutter as a cross-platform development technology, so grab your favourite beverage, settle in, and let’s delve into the challenges that lie ahead.

Setting the Scene

Imagine a scenario where a client approaches you with the mandate to undertake a substantial project over the next few years, involving multiple cross-functional teams. The goal is to establish the right foundations from the very beginning, ensuring that a few years down the line you won’t hear the dreaded phrase: “The project is so messy; we need to start over.” We’ve all encountered situations like this at some point, haven’t we? This brings us to our first challenge — creating a comfortable environment to lay the groundwork within a few weeks.

The MVP Conundrum

However, the comfort of laying the foundation quickly is soon followed by the next challenge: delivering the first version (MVP) within three to four months. This is a common hurdle, given the dynamic nature of today’s business environment. A business idea that is valid now may become obsolete in just a couple of years. Therefore, the need to gather user feedback rapidly becomes paramount!

Key Considerations

Rapid Foundation Establishment:

  • Strategies for efficiently setting up the project’s foundational elements within a short timeframe.
  • Tools and methodologies to streamline the initial phases and ensure a solid starting point.

MVP Delivery Challenges:

  • Overcoming obstacles in delivering a Minimum Viable Product within a tight timeframe.
  • Balancing speed with quality to meet business demands while maintaining a robust project foundation.

Background and Lessons Learned:

Now, let me provide some background on where we stand with our colleagues at Prime Holding JSC and the conclusions we’ve drawn, along with the corresponding solutions we’ve adopted. In 2018, Flutter marked its first stable release, and at that time, the ecosystem was relatively underdeveloped compared to its current state. It was like exploring uncharted territory. In early 2019, our company decided to invest in the technology by focusing on human development, expertise and most importantly tools that allow the development team to build mobile applications faster. We embarked on a massive project with a multinational real estate development company, developing their loyalty platform. With millions of customers and the sheer scale of the project, it presented a significant challenge given the youthfulness of the technology.

Further Ventures:

Since then we have built more than 10 Flutter Applications, among them a corporate banking application in 2021 and a retail banking application in 2023. Throughout these years, the ongoing conversation with colleagues has revolved around understanding what components and tools are necessary to ensure that the applications we develop can achieve their long-term goals.

Key Considerations and Challenges:

Google emphasises that Flutter is primarily focused on the user interface:

Flutter is Google’s UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase.

As we moved into more substantial projects, the need for third-party packages became apparent. Large-scale applications require robust solutions for:

Standardizing Project Setup with rx_bloc_cli

When tackling such vast projects, a common question arises: Why should we spend time on the above challenges over and over again? Why not standardize an approach that could work for a vast majority of cases? Recognizing that there is no one-size-fits-all tool, but there are generic instruments, we concluded that we shouldn’t reinvent the wheel with every project. Therefore, we introduced a package that addresses these challenges comprehensively — rx_bloc_cli. This package enables quick project setup, covering all the aspects discussed thus far. Let’s explore how this solution facilitates efficient development in the upcoming sections.

Reactive State Management

Introducing the Flutter package rx_bloc, designed to streamline the implementation of the BLoC (Business Logic Component) Design Pattern by leveraging the capabilities of reactive streams. By merging these technologies, developers can elevate their asynchronous programming skills and benefit from a concise package set, resulting in the creation of robust, scalable, and easily maintainable solutions.

Why should I use rx_bloc?

When tackling a sophisticated project, the challenge arises in constructing a highly interactive UI and robust business logic, all while managing various data sources such as REST APIs, Web Sockets, Secured Storage, Shared Preferences, etc. To navigate this complexity effectively, a sophisticated architecture is required to facilitate seamless product development. Here you can learn more about rx_bloc.

Key Benefits:

  1. High Performance, achieved by rebuilding only the necessary part of the widget tree.
  2. Streamlined Inputs (Events) and Outputs (States), which leads to concise, understandable and flexible contracts.
  3. Zero-boilerplate BloC, so that the developers can focus on implementing the business logic.
  4. Automatic Loading and Error Handlings, to ensure a responsive application while seamlessly managing unexpected issues, enhancing the user experience.

Design System

A design system is a comprehensive set of guidelines, principles, and reusable components that provide consistency and cohesiveness across the entire application. It serves as a central repository of design elements, including typography, colour schemes, spacings, animations and UI components ensuring a unified and seamless user experience. The goal of a design system is to streamline development, enhance collaboration among teams, and maintain visual and functional consistency.

Why should I use a Design System?

The reason for using a design system is that it adapts seamlessly for scalability, fostering collaboration and providing a shared language for teams. It guarantees maintainability, centralizing updates and enhancing the user experience through familiarity. Additionally, it acts as a sentinel for brand integrity, enforcing standardized visuals and aligning products seamlessly with the brand image.

Key Benefits:

  1. Consistency: Ensures a uniform and professional look across various interfaces and platforms.
  2. Efficiency: Streamlines design and development processes by offering reusable components and established guidelines.
  3. Maintainability: Centralizes updates and changes, reducing the risk of discrepancies over time and simplifying maintenance.

Pre-Built Functionalities

Enterprise-Grade Pre-Built Features provide a foundation for robust and scalable application development. These features, designed for enterprise-level projects, offer a multitude of benefits. They ensure consistency, streamline development, enhance security, and expedite the implementation of complex functionalities. Leveraging these pre-built features accelerates the development process, reduces the risk of errors, and fosters a cohesive and reliable application architecture, meeting the demanding standards of enterprise-level projects.

Why should I use Pre-Built Components?

Leveraging pre-built components like those offered by the widget_toolkit package not only accelerates development by providing lightweight and customizable UI elements but also enhances consistency and efficiency. For instance, widget_toolkit_otp expedites secure authentication implementation, widget_toolkit_biometrics simplifies biometric integration, and widget_toolkit_pin streamlines secure PIN code functionality. The integration of a QR scanner through widget_toolkit_qr further exemplifies the time-saving advantages of pre-built components. When used alongside the rx_bloc_list package, these components not only reduce development time but also ensure a unified and robust user experience within the RxBloc ecosystem.

Packages that we use:

  1. widget_toolkit — The Widget Toolkit package consists of several lightweight and customisable UI components that boost productivity and reduce development time.
  2. widget_toolkit_otp — Package helping with building SMS or pin code fields and screens in a matter of minutes
  3. widget_toolkit_biometrics — A Flutter package that helps users to handle enabling and disabling biometrics in an application
  4. widget_toolkit_pin — This package provides out-of-the-box PIN code functionality, which can be used with biometric authentication.
  5. widget_toolkit_qr — A Flutter package which provides a QR scanner widget easily integrated into the application.
  6. rx_bloc_list — The rx_bloc_list package facilitates implementing infinity scroll and pull-to-refresh features with minimal setup. This package is meant to be used along with RxBloc ecosystem.

Of course, this is only a subset of all packages we usually when we start a project. Here you can see a comprehensive list.

Real-Time Updates

Real-time updates using HTTP Server-Side Events (SSE) offer a streamlined approach to push events from the server to the client over a single HTTP connection. SSE enables a continuous flow of updates, enhancing user experiences with live and instant data delivery. This lightweight and straightforward protocol eliminates the need for repeated requests, ensuring real-time information delivery for dynamic mobile applications.

Why should I care about real-time updates?

Real-time updates are essential for several reasons. They enable immediate data delivery, ensuring users stay informed in real time. This dynamic experience enhances user engagement and provides timely notifications for crucial messages or changes. Efficient monitoring of time-sensitive data, such as stocks or system statuses, is possible with real-time updates, reducing latency and ensuring a responsive application. This capability not only keeps applications competitive but also adapts well to a variety of scenarios, from live chats and social media feeds to financial updates and collaborative tools. In summary, real-time updates significantly elevate user experience, responsiveness, and the overall effectiveness of dynamic applications.

Key Benefits

  1. Pre-Built Infrastructure: SSE requires minimal setup and is often simpler to integrate into existing systems compared to WebSockets, which may involve additional configuration.
  2. Compatibility: SSE is supported by standard web servers and works over existing HTTP infrastructure, ensuring broader compatibility.
  3. Fallback Mechanism: In the rx_bloc_cli we have added a built-in automatic reconnection mechanism, providing a graceful fallback if the connection is interrupted.

Localisation

In Flutter applications, localization involves adapting the UI and content for different languages and regions. It ensures inclusivity, allowing global access. Key aspects include internationalization, managing translations, structured resource storage, language switching, pluralization, RTL support, and tools like r_flutter for efficient development. Localization is vital for creating versatile, globally accessible apps with a personalized user experience.

Why should I use localisation in my project?

Integrating localization into your project is essential for achieving global reach and user engagement. Beyond language translation, it demonstrates cultural sensitivity, ensures legal compliance, and enhances market competitiveness. Offering a customized user experience fosters positive brand perception, potentially increasing revenue. Moreover, localization adapts your project to evolving language trends, making it more adaptable and user-friendly in diverse markets. In summary, localization is a strategic decision that goes beyond translation, contributing to the overall success and resonance of your project on a global scale.

Key Benefits:

  1. Seamless Integration in the widgets: Developers can easily integrate translations into the code by importing the app_extensions.dart file.
  2. Remote Localization Lookup: Supports fetching remote localizations during app start, allowing dynamic updates without requiring a new app release.
  3. Organize I18n strings by feature: Adopts a structured naming scheme for keys, including feature names and separators, promoting clarity and organization.

Routing With Built-In ACL (a.k.a Permissions)

Efficient routing and robust access control are pivotal components for a seamless user experience and achieving the needed security as well. We decided to integrate the go_router, which is a Flutter Routing Package employing a declarative approach, utilizing the Navigator 2.0 API to offer a user-friendly, URL-based interface for seamless navigation across various screens. This package allows you to define URL patterns, navigate via URLs, manage deep links, and address various other navigation-related scenarios.

Navigating with RouterBloc:

The navigation layer is managed by the lib/lib_router/bloc/router_bloc.dart, allowing for fine-grained control over each route. Developers can perform actions such as pushing, popping, navigating to specific locations, and more, using the following snippets:

context.read<RouterBlocType>().events.push(MyNewRoute())
context.read<RouterBlocType>().events.pop(MyCustomObject())
context.read<RouterBlocType>().events.goToLocation('/users/123')
context.read<RouterBlocType>().events.pushReplacement(MyNewRoute())
context.read<RouterBlocType>().events.go(MyNewRoute())

How do I protect the pages of my application?

Ensuring secure access to various app routes is made effortless with ACL. By default, the access to each page can be controlled remotely through the corresponding API endpoint /api/permissions. Let's explore the expected API response structure for both anonymous and authenticated users.

Expected API Response for Anonymous Users:

{
'SplashRoute': true,
'ProfileRoute': false,
// Additional routes...
}

Expected API Response for Authenticated Users:

{
'SplashRoute': true,
'ProfileRoute': true,
// Additional routes...
}

Key Benefits:

  1. Integrated ACL: The built-in Access Control List (ACL) simplifies user access management by effortlessly defining and enforcing permissions for specific app routes. Enhance security and streamline access control within your application effortlessly.
  2. Flexible URL Parsing: Easily parse path and query parameters using a template syntax like “user/:id?param1=someValue”, providing a flexible and intuitive way to handle dynamic content and user-specific routes.
  3. Dynamic Redirection Support: Seamlessly redirect users to different URLs based on the application state. This is particularly useful for scenarios like redirecting unauthenticated users to a sign-in page, enhancing the overall user authentication flow.

Environments (Dev, SIT, UAT, Production)

In the dynamic realm of software development, distinct environments — DEV, SIT, UAT, and Production — play crucial roles in ensuring a smooth deployment process. Each flavour is technically a separate application, which allows each environment to be configured and tested individually. Let’s quickly navigate through each phase:

DEV (Development)

  • Purpose: Foundation for code creation and experimentation.
  • Activities: Rapid prototyping, unit testing, and continuous integration.

SIT (System Integration Testing):

  • Purpose: Integration testing for seamless system cohesion.
  • Activities: Verification of inter-component interactions and data flow by QA Engineers.

UAT (User Acceptance Testing):

  • Purpose: User-centric validation pre-production.
  • Activities: End-to-end testing, user acceptance validation, and final checks by business representatives.

Production:

  • Purpose: Ultimate deployment for real-world use.
  • Activities: Controlled deployment, real-time monitoring, and continuous improvement.

Development Experience

In the fast-paced world of mobile application development, experience plays a pivotal role in determining the success and efficiency of a project. Seasoned developers bring a wealth of knowledge, problem-solving skills, and a deep understanding of the intricacies involved in creating robust mobile applications, but regardless of how experienced they are once provided with the needed tools for streamlining the development process, the project timeline could look much more attractive than before. IntelliJ (Android Studio) plugins such as RxBloc can greatly increase development efficiency as explained below, but before that let’s install it easily from the market. Open your Android Studio, open the Plugins section, search for RxBloc and hit the install button.

How the RxBloc Plugin can boost development efficiency?

This plugin saves time and effort when it comes to creating Features, Rx BloC List, Rx BloC Class or Test Suits for an already existing feature.

Facilitate the initiation of your feature effortlessly.

Why do we need to spend time creating all needed classes and folders when creating new features?

Just right-click on the `lib` folder -> New -> RxBloc Feature

Fill in the needed details, such as Name, Routing Integration etc

Then all needed folders, classes and routing integrations will be created for you.

Add dynamic data to your existing widgets

Wrap the widgets of your existing widget tree with the RxBloc-related widgets, which work as a binder of the Business and the UI layer. Just click on the widget that needs to consume dynamic data, and select the wrapper you need.

and then you can start consuming the BloC State

Key Benefits:

  1. Unified Feature Structure: Streamlined Development: Fosters a consistent feature structure for efficient and collaborative development.
  2. Seamless Widget Wrapping: Enhanced Integration: Simplifies widget integration, promoting cleaner code and accelerated development.
  3. Unit Tests Bootstrapping: Efficient Testing: Facilitates easy unit test set-up, ensuring robust testing for reliable code.

Automated Tests

Integration tests validate the functionality of our Flutter applications at a broader level and assess the entire application as a cohesive unit, including its interactions and dependencies. While unit tests focus on isolated units of code. Apart from those well-known testing approaches, in Flutter we have Golden Tests, which help maintain pixel-perfect applications.

Unit Tests

Unit tests in software development evaluate individual code units, such as functions or methods, to ensure they perform as expected in isolation. These tests help identify and fix errors early in the development process, promoting code reliability and maintainability.

Key Features

Golden Tests

In Flutter, golden tests are a type of UI testing that focuses on capturing and comparing the visual appearance of widgets. Instead of asserting specific widget states or properties, golden tests create and store “golden” images representing the expected appearance of UI components. During subsequent test runs, the actual UI is compared against these golden images, helping developers identify visual changes or regressions in the application’s user interface. Golden tests are particularly useful for maintaining consistent and visually appealing UIs across different platforms and releases in Flutter applications.

Key Features

  • GoldenBuilder: The GoldenBuilder class lets you quickly test various states of your widgets given different sizes, input values or accessibility options.
  • DeviceBuilder: DeviceBuilder class is like the GoldenBuilder except that it constrains scenario widget sizes to Device configurations. This removes the need to specify a column or grid-based layout.
  • multiScreenGolden: The multiScreenGolden assertion is used to capture multiple goldens of a single widget using different simulated device sizes & characteristics.

Integration Tests

End-to-end (E2E) testing provides a comprehensive evaluation of the entire application, examining its functionality from the user’s perspective as a complete, integrated system

Key Benefits:

  1. A Powerful Tool: Our chosen tool for integration testing is Patrol, a versatile package that extends beyond Flutter’s context.
  2. Access to Specific Controls: Patrol provides access not only to the application’s surface but also to specific native controls such as push notifications, biometrics etc
  3. Making the Impossible Possible: Patrol, as claimed by its developers, empowers developers to achieve the seemingly impossible.

Understanding The Customer Base

From my perspective, this tool is absolutely necessary for any application, impacting every facet of its existence. After all, what we’re developing is a product, and for any product to thrive, understanding its end users is paramount. We need to know who they are, where they are, and which screens of our product they visit the most.

Why Firebase Analytics?

Our choice of Firebase Analytics is multi-faceted. Firstly, it boasts excellent integration capabilities with Flutter, ensuring a seamless experience within our development environment. Secondly, the service provided by Firebase Analytics is free of charge, a crucial factor for many projects. Last but not least, the fantastic support from Google further solidifies our decision.

Key Benefits:

  1. Seamless Flutter Integration: Enjoy smooth integration, minimizing development efforts.
  2. Cost-Effective: Benefit from Firebase Analytics’ cost-free service.
  3. Google Backing: Rely on robust support and continuous improvements from Google.

Catching The Product Malfunctions In Real Time

Continuing our toolkit exploration, let’s delve into Crashlytics, a pivotal tool for error monitoring in Firebase. Whether we’re discussing an enterprise-level overview or a smaller-scale project, the need for error monitoring is universal.

The Imperfection of Software:

In the realm of software development, perfection remains elusive. Even tech giants like Facebook and Google encounter regressions. As developers, it’s crucial to acknowledge that imperfections exist. To identify and rectify issues efficiently, a reliable tool is indispensable.

Why Crashlytics?

Crashlytics stands out as a robust solution for error monitoring within the Firebase ecosystem. Here’s why it’s a crucial addition to our toolkit:

  1. Real-time Error Reporting: Instantly detect and report crashes, enabling swift response to emerging issues.
  2. Comprehensive Crash Reports: Access detailed crash reports, aiding in the identification of root causes.
  3. Prioritization of Fixes: Prioritize fixes based on the severity and impact of each issue.

Application Network Monitoring

Application Network Monitoring involves the continuous observation and analysis of an application’s network activities. It aims to ensure optimal performance, detect potential issues, and enhance overall reliability. By monitoring network metrics, traffic patterns, and communication between the mobile application and its API, the developers can proactively identify bottlenecks, troubleshoot problems, and maintain the health and efficiency of their applications.

Embedded Network Monitoring

There are scenarios where we need to quickly debug our application by monitoring the API Requests directly from our phone. Here we found Alice, an HTTP Inspector tool that helps debug http requests. It catches and stores HTTP requests and responses, which can be viewed via simple UI.

Key Features:

Web Proxy with Charles

Charles Web Debugging Proxy is a cross-platform HTTP debugging proxy desktop application. It enables the user to view HTTP, HTTPS, and HTTP/2 and allows TCP port traffic accessed from, to, or via the local computer.

Key Features:

  1. HTTP and SSL/TLS Traffic Monitoring: Charles serves as an HTTP proxy, facilitating the monitoring and debugging of HTTP and encrypted SSL/TLS traffic between applications and the internet.
  2. SSL Proxying: The tool supports SSL proxying, enabling users to inspect and debug encrypted SSL/TLS traffic, aiding in the identification and resolution of security-related issues.
  3. Dynamic Request and Response Manipulation: Charles allows on-the-fly modification of HTTP requests and responses, offering flexibility in testing scenarios and optimizing web application functionality.

Conclusion

Within the realm of mobile development, the Prime Holding JSC services offer a distinctive value proposition. Specializing in Flutter technology since 2019, our emphasis on user-centric development, efficiency, and consistency sets us apart. We have adapted bullet-proofed, standardized solutions for automated testing, analytics, error monitoring, real-time updates, localization, routing, multi-environment deployment and all you need to take your application to the next level. Prime Holding’s commitment to experience, expertise, and proactivity positions us as a valuable partner in navigating the dynamic mobile development landscape.

Related articles

  1. Building complex apps in Flutter through the power of reactive programming
  2. Introducing rx_bloc ecosystem — Part 1
  3. Introducing rx_bloc: Part 2
  4. Introducing flutter_rx_bloc: Part 3
  5. RxBloc Intellij Plugin
  6. Building forms in Flutter
  7. Easy Paginated Lists In Flutter
  8. Bootstrapping Your Flutter App With Ease
  9. Inter-feature communication in Flutter apps

--

--