Originally from the abused GUI design pattern.

Give your personal opinion on GUI design patterns.

In recent years, with the development of Fronted technology, the old (at least decades old) “GUI design pattern” used to solve the problem of code organization in GUI applications has become a hot topic among Frontend engineers. MVC, MVP, MVVN and other design patterns have been discussed on the Internet. Many engineers have started blogging about them, explaining their understanding of them, and even open-source implementations of various GUI design patterns on Github.

Following this trend, many Frontend engineers even regard THE GUI design pattern as a “norm” or even a “dogma.” The bad reality, however, is that most people don’t understand and use GUI design patterns properly and carefully, and instead their shortcomings are magnified by Tradeoff. As a result, you spend a lot of effort and template code designing it, which makes it more complex and harder to maintain.

For example, if you open up most Github repositories that try to implement GUI mode, the entire application is about two or three pages, four or five network interfaces, and you’ve probably created dozens of classes and interfaces to host that thin logic. To give a more specific example, I have personally worked with several large Android projects that were designed in MVP mode, and the MVP mode became a liability when it came to maintenance or iteration due to various design problems.

First of all, most of the views in the project are high-granularity, high-coupling Activity classes, and many of the views provide methods like Fun updateView(User: UserModel) for convenience, leading to direct coupling between the View and the domain/business model. In addition, views and Models can include commands to jump to pages, send global messages, and other “side effects” that make interface programming formalistic.

Therefore, it is better to understand the nature of the problem than to “ignore the root of the problem” and “know the cause without knowing the cause”. In fact, the most important idea of the GUI design pattern is “divide and conquer”, allowing code that was previously written in one place to achieve “low coupling and high cohesion” by dividing it into different classes by function. Therefore, GUI design patterns should be considered as an idea rather than a means, and there is no need to use templates to solve problems. As long as you can design hot, critical code with low coupling and high cohesion, you can ignore all GUI design patterns.

For example, in the fun updateView(User: UserModel) problem mentioned above, there are actually two ways to decouple the View from the business model UserModel:

/ / method
interface ViewA {
    fun updateText1(text: String)
    fun updateText2(text: String)
    // ...
}
class PresenterA {
    fun onSomeEvent(a) {
        val userModel = Apis.requestUser()
        viewA.updateText1(userModel.name)
        viewA.updateText2(userModel.age.toString())
    }
}

/ / method 2
interface ViewA {
    data class ViewAttributes(
        text1: String,
        text2: String,
        // ...
    )
    fun updateView(view: ViewAttributes)
}
class PresenterA {
    fun onSomeEvent(a) {
        val viewAttributes = Apis.requestUser().mapTo ViewAttributes()
        viewA.updateView(viewAttributes)
    }
}
Copy the code

Method one tends to describe views in terms of “instructions”, while method two tends to describe views in terms of “data”. I personally prefer approach two because the data is runtime processable, persistent, and even shared across processes, languages, and machines. As an aside, Web Fronted has popularized the term “time travel” with state management tools like Redux. In my opinion, the core idea is to submerge the instruction and use data (/ state) to describe the upper level logic so that the logic can be recorded and replayed at run time.

It is important to note that the ViewAttributes must be the domain model of the View, and field names should only refer to the View itself, not other domains.

Back to the other issue mentioned earlier: side effects in Views and Models. This is actually easier to fix, just move all the side effects to the outside (/ caller). Such as:

// There are side effects
class ViewA {
    fun onTitleClick(a) {
        sendBroadcast("x")}}// No side effects
class ViewA {
    fun onTitleClick(a) {
        caller.onTitleClick()
    }
}
class PresenterA {
    fun onTitleClick(a) {
        sendBroadcast("x")}}Copy the code

In fact, only know the OOP (object-oriented programming) engineer, it’s easy to cause the aforementioned problems, because they are accustomed to rely on the state of “external” to solve the problem (instance of the class itself is also a state), but in the state of the increasing number of cases, state of management will become a new problem. OOP’s advocacy of “low coupling and high cohesion” of classes can actually be seen as solving the problem of state management.

So at the end of this article, I strongly recommend that engineers learn about FP (functional programming). In contrast to OOP, the idea of FP is to get rid of external state and achieve “low coupling and high cohesion” at the function level with a smaller granularity. You just need to make sure your functions are side-effect-free and manage the internal state of your functions. Maintaining this programming mindset allows you to navigate large, complex projects with ease, and even makes your code easier to debug and execute in parallel.

For Android engineers, Kotlin’s current popularity is an opportunity to learn more about FP. I’ll write about Kotlin and FP later.