Reactive Architecture
Introduction to Reactive Architecture
Reactive Architecture is focused on making the system Robust, Resilient and Flexible. It is a pattern for building software specially on the Enterprise level. There are four traits of the Reactive Architecture which are Responsive, Elastic, Resilient and Message-Driven.
Elastic
- Core Design Goal in the Application Architecture
- Software should be written to allow the incoming load to be partitioned
- System stays responsive under varying workload
- No contention point or central bottlenecks
- Process in more than 1 machine, profit from cloud
- Cost effective on commodity hardware and software platform
- No limit to how far the system can grow
Resilient
- Reasons:
- Programming errors, mistakes happen
- Errors happen, network, faulty drive, hardware fail
- Attacks
- Solution:
- Application should be written to be distributable
- Different location
- Different network
- Result:
- Elastic components will scale with their load
- Responses in the presence of partial failures
- Can adapt to different load, cannot be overloaded
Responsive
- Containment of
- Failures
- Implementation details (totally decoupled)
- Responsibility
- Shared-Nothing architecture, clear boundaries (less coordination means better scalability)
- Microservices: Single Responsibility Principle
- Microcomponents
- Decoupled responsibility – decouple teams
- Develop pieces at their own pace
- Continous Delivery
Message-Driven
- Decouple the Sender to the Recipient which is needed to achieve resilience
- Asynchronous message passing to establish boundary
- Ensure loose coupling, isolation and location transparency
- Provides delegation for failures as messages
- Focus on communication between components
- Message flows as model
Please see the references section to get some more information in Reactive Manifesto and it is the guiding principle of the Reactive Architecture (References)
The Reactive Core
Consolidating the experience for the web and native apps is the right path forward. Benefits are enormous in the sense that development can move to a direction where everything is re-usable with cohesive experience.
How does it work?
Web and Mobile Apps have a huge difference in terms of how a component is presented. The presentation, interaction are tightly integrated to the platform, i.e. iOS vs Android vs Web. Although the presentation and interaction are dictated by their respective platform, the pattern of handling Models, ViewModels should be similar to achieve a common goal of using a single scallable platform to deliver experience. Decoupling the way the ViewModels, Models are handled are the key indicators of re-use and consistency. With this we are using the Redux principles to have a predictable state container for the application. It will help the app to behave consistently even if it is run in different environments (client, server, and native) and are easy to test. it will also help the develop experience specially in development and debugging for having the advantage of live code editing combined with time travelling debugger.
Redux architecture revolves around a strict unidirectional data flow. This means that all data in an application follows the same lifecycle pattern, making the logic of the app more predictable and easier to understand. It also encourages data normalization, so that you don’t end up with multiple independent copies of the same data that are unaware of one another.
Understanding the Clean Architecture
Clean Architecture focuses on the separation of concern and it is primarily dividing the app in 3 major components. Presentation, Domain and Data.
Presentation
it is responsible in presenting the information to the user.
Domain
responsible for making the sure that there will be an intermediate layer for the Data and Presentation. It is needed to make sure that the presentation layer doesn’t write directly to the data layer
Data
The layer that is responsible for getting the necessary information. The diagram below shows the detail on how the data are stored, retrieved and used.
Repository
It is the access point and the interface to the outside. These are the four main operations that are exposed in this layer
- GET: Returns an infinite stream that will emit updates of the specified type of data but doesn’t ensure there will be a value inside.
- FETCH: It fetches the data from the external source typically from API, and stores the data once it receives it.
- REQUEST: This is an alternative to fetch operation when we don’t need the infinite stream counterpart. It returns a single that will return the data in the onNext even and complete or error if there was any problem
- PUSH, DELETE: It sends or deletes data to and from the external sources. Provides a single or completable depending if there is any data coming from back from this operation
Reactive Store
This is the component behind the GET. It holds the data and provides infinite streams to it. It is the most complex part of the whole architecture and be designed carefully: this layer will be holding the data and will be accessed asynchornously. it must be solid against concurrency.
There are many ways of implementing this component depending on the nature or features of the app.
public interface ReactiveStore<Key, Value>{
Flowable<option getSingular(@NotNull final Key key);
Flowable<option<<List>> getAll();
void storeSingular(@NotNull final Value model);
void storeAll(@NotNull final List modelList);
}
Design Patterns
Simple Component Pattern
- Maximize cohesion and minimize coupling
- A class should only have 1 reason to change
- Less coordination, easy execution
- “STATELESS”
- Building Blocks
Model-View-ViewModel Pattern
- View – A UI component that renders or a container that has a representation of a style and content. A container can be sometimes called as a presenter.
- ViewModel – A model that is specific of influencing on how the View will be rendered
- DataModel – A data structure that holds or persist information that is coming from different sources
- Store – a temporary memory allocated to store or retrieve information
- API – external data source
- Config/Preferences – a collection of key and value pair
Data and Model Transformation and Consuption
This diagram shows the relationship of the DataModels in different perspective. From data structure, storage and retrieval up to rendering to specific form factor.
Component Design and Architecture
The Reactive UI
The diagram illustrates the flow of data or stream to each of the components. The start of the flow are triggered by a UIElement event via the elements lifecyle event. Though it is different in iOS and Android, assuming the init() event is the initial event, then an Observer will listen to all those on*Events and dispatch the necessary operation. Ultimately the Reducers will identify the action and decide if a request is needed to the services or the state can be updated. This means that the state can only be changed by an action and not to any other means. The state should stay immutable to prevent any other components related to the state might get into an un-stable state. Once the state is updated, then the necessary refresh event to the component is fired. This will be the lifecycle of the components on the UI.
UI Container Lifecycle
- Initialize the Presenter
- Android –
val view = MainViewImpl(findViewById(android.R.id.content) as ViewGroup) val presenter = MainPresenter(authService = AuthService.Impl(), ioScheduler = Schedulers.io())
- IOS – init(nibName…..)
- Android –
- Observer catches an Init event firing
- dispatcher identifies the type of event fired and dispatch and action (operation)
- DataModel identifies the action and retrieves the model necessary
- RemoteDataModel responds to the request
- Response are returned and state have changed and notifies Presenter of the changes and updates the UI
- Container updates
Remote Config
Change the behavior and appearance of the app without publishing an app update.
Remote Config is a cloud service that lets you change the behavior and appearance of your app without requiring users to download an app update. When using Remote Config, you create in-app default values that control the behavior and appearance of your app. Then, you can later use the console to override in-app default values for all app users or for segments of your user base. Your app controls when updates are applied, and it can frequently check for updates and apply them with a negligible impact on performance
Types of Data
The Remote Config Object should be a representation of the UI, behavior, action handler and such that are stateless in nature. It should not contain any information holding state specially when it comes to user information, session that are persisted in the request. The config can be retrieved as a resource with the URI pattern
Key Capabilities
Capability
|
Description
|
---|---|
Customize your app for segments of your user base | You can use Remote Config to provide variations on your app’s user experience to different segments of your user base by app version, by Analytics for audience, by language, and more. |
Quickly roll out changes to your app | You can make changes to your app’s default behavior and appearance by changing service-side parameter values. For example, you could change your app’s layout or color theme to support a seasonal promotion, with no need to publish an app update. |
Run A/B tests to improve your app | You can use Remote Config random percentile targeting with Analytics for to A/B test improvements to your app across different segments of your user base so that you can validate improvements before rolling them out to your entire user base. |
How does it work?
Remote Config includes a client library that handles important tasks like fetching parameter values and caching them, while still giving you control over when new values are activated so that they affect your app’s user experience. This lets you safeguard your app experience by controlling the timing of any changes.
The Remote Config client library get
methods provide a single access point for parameter values. Your app gets service-side values using the same logic it uses to get in-app default values, so you can add the capabilities of Remote Config to your app without writing a lot of code.
To override in-app default values, you use the console to create parameters with the same names as the parameters used in your app. For each parameter, you can set a service-side default value to override the in-app default value, and you can also create conditional values to override the in-app default value for app instances that meet certain conditions. This graphic shows how parameter values are prioritized in the service and in your app
Implementation Path
#
|
Implementation
|
description
|
---|---|---|
1 | Instrument your app with Remote Config | Define the aspects of the apps’s behavior and appearance you want to be able to change using Remote Config and translate these into parameters that will be used in the app |
2 | Set default parameters values | Set the in-app default values for Remote Config parameters setDefault() |
3 | Add logic to fetch, activate, and get parameter values | Your app can safely and efficiently fetch parameter values from the service and activate those fetched values. So, you can write your app without worrying about the best time to fetch values, or even whether any service-side values exist. Your app uses get methods to get the value of a parameter, similar to reading the value of a local variable defined in your app. |
4 | (If Needed) Update service-side default and conditional parameter values | You can define values in the Firebase console to override in-app default values. You can do this before or after you launch your app, because the same get methods access in-app default values and values fetched from the service. |