World Flux Architecture in iOS (last part)

PART 1PART 2

(continued Step 4: Mounting the UI with Store in part 2 )

tableViewModelForState is a pure function, has the latest input state and returns a description of table view in the form of FluxTableViewModel . The way this method works is similar to React's render function. FluxTableViewModel independent of UIKit and is a simple struct that describes the content of the table. You can find implementation of the open source example in the AutoTable repository .

Then, the result of this method will be associated with the view controller's tableViewDataSource property. The component stored in that property is responsible for updating UITableView based on the information provided in FluxTableViewModel .

Other code isFiltering: is easier, like code that activates / disables the "Clear Filer" button based on state isFiltering:

Executing (implementing) UI bindings is one of the hardest parts, because it doesn't completely match UIKit's programming model. But you only need to write a few custom components that can easily implement UI bindings. Instead of attaching to the traditional MVC method to implement UI updates through a lot of view controllers, we have saved a lot of time thanks to implementing these components.

With the appropriate UI bindings, we analyzed the end of implementing 1 Flux feature. I want to rewrite the recap before moving on to analyzing method testing for Flux features.

Implementation Recap

When executing a Flux feature, I often split the work into multiple segments as follows:

  1. Identify the shape of the state type
  2. Identify actions
  3. Implement business logic and state operations for each action – this implementation exists in the store
  4. Execute UI bindings outline the state diagram to view presentation

Next, we will analyze how to test Flux features

Writing Tests

One of the main advantages of the Flux architecture is that it separates the problems, so it's easy to test business logic and larger UI code.

Each Flux feature has 2 main areas to test:

  1. Business logic in store
  2. View model providers (these are functions like React, produce a description of the UI based on 1 input state)

Testing Stores

Testing stores is often very simple. We can attract store interaction by transmitting actions, monitoring state changes by registering the store or observing internal _state property in our tests.

In addition, it is possible to mimic types outside any store that needs to communicate with each other to execute a feature (probably a client API or a data access object) and to include those types in the initializer. of store. It allows us to verify that these types are called when needed.

In the PlanGrid application, we use Quick and Nimble to write tests. Below is a simple example of testing in annotation filter store specification:

Again, although I don't delve into the details of this particular test, testing spirit needs to be clear. We send the store actions and authenticate responses in the form of changes in the state or calls to the inserted mocks.

(You will probably wonder why we are calling the _handleActions method in the store instead of sending an action using the dispatcher. Usually, the dispatcher uses dispatch asynchronously when sending actions, syncing our tests as well. So, we have directly called the handler in the store. The implementation of the dispatcher has changed, so we can use the dispatcher in tests.

Now, when executing business logic in a store, I will almost write my tests first. Structure of our store code, along with the behavioral Quick specs, is very suitable for test programming process.

Testing Views

Flux architecture, combined with declarative UI layers, makes it easier to test views. We are still debating the target in the layer view.

In fact, all of our view code is quite easy to understand. It connects the state in the store with the different properties of the UI layer. For our application, we decided to solve most of this code through UI automation tests.

However, there are still many options. Since the view layer is set to render a state that has been inserted, the snapshot test also works very well. Artsy has mentioned the idea of ​​snapshot testing in many posts and blog posts, including great articles on objc.io.

When we realize that UI automation has been fully utilized, we do not need to add snapshot tests anymore.

I also tested unit testing view supply functions (like the tableViewModelForState function we saw earlier). But this view providers are pure functions that plot from a state to a UI description, so it's easy to test based on 1 input and 1 return value. However, I realized that these tests do not make much sense because they reflect the description description of the implementation strictly.

Using Flux architecture view testing is quite simple because the view code is completely separate from the rest of the application. You just need to insert a state that needs to be rendered in tests and you're ready.

Because there are so many options for testing UI, I am very eager to know which tools (and other developers) will choose from in the long run.

Conclude

After dividing into many implementation details, I want to conclude with the experience we have.

We have only used Flux architecture for about 6 months, but have realized quite a lot of advantages of having our code base:

  • New features are implemented synchronously. The structure of stores, view providers and view controllers through the features is almost identical
  • When viewing state, actions and tests of BDD format, you can immediately understand how a feature works
  • The issues between stores and views will be completely separated. Most of the time, you won't have to be ambiguous, so you should put some code somewhere
  • Our code is easier to read. State that depends view will always be transparent and clear. Thus, the debug process is also easier.
  • All of these points will help new developers more receptive

Of course, there are still shortcomings

  • First and foremost, integrating with UIKit components can be a bit more difficult. Unlike other React components, UIKit views do not provide an API just to update themselves based on the new state. This burden forces us to execute it manually in view bingdings or to write custom components wrap UIKit components
  • Not all our new codes follow Flux patterns. For example, we still haven't solved the operating / navigation system with Flux. We need to integrate a coordinator pattern into the Flux architeture or use a router that is really similar to the ReSwift Router .
  • We need to think of a good pattern for the state to share through a large part of the application. Should we have dependencies between stores like in the original Flux pattern? What are the alternatives?

I really want to delve into implementation details, advantages and disadvantages. So I hope to study some aspects in more detail in other posts.

Hopefully this article will help you understand if Flux architecture is right for you.

Refer:

  • Flux – The official Flux website on Facebook includes the original introduction to Flux
  • Unidirectional Data Flow in Swift – My article on Swift related to Redux concepts and ReSwift implementation original
  • ReSwift – 1 implementation of Redux in Swift
  • ReSwift Router – 1 router declared for ReSwift applications

Source: IDE Academy via Blog.Benjamin

Share the news now