Tjeerd in 't Veen
— 5 min read
UI architectures are like fashion. They go in and out of style, and they can bring fresh perspectives, but they aren’t as important as you might think.
“Our codebase should use RxSwift. Reactive programming is going to be the future!”
If I had €1 every time someone said this to me in the past, I could almost afford an Apple USB C charging cable.
Not that long ago, RxSwift was the next big thing. “Obviously”, reactive programming would solve all of our problems.
Some job listings required RxSwift knowledge. There was hype around it. And at my work — being a platform member at ING at the time with a considerably sized codebase and team — I received monthly proposals to introduce a new pattern to the codebase, whether that was RxSwift, MVVP, MVVM, or whatever the next big thing was during that time.
Our team often had to disappoint people because we couldn’t adopt everything on a whim. And our work was proof that simple viewmodels with some coordinators were more than enough for most, if not all, our features.
That didn’t mean we said no all the time to any trend. Some of these trends came with — in my eyes — great ideas, such as coordinators. Experimentation was an important part to figure out what would work for us as a team.
But the art was the ability to judge whether an architecture solves an actual problem or if it’s just trendy. On top of that, people want to grow and learn from adopting new technologies and ideas, and there needs to be space for that, too.
Most UI architectures are valid and do a great job, yet they’re often based on preferences.
Some people want a more functional style, others prefer a more reactive style over imperative, others prefer routers over coordinators, and so on. They all have their pros and cons.
There is a myriad of patterns and architectures out there to choose from; MVC, MVVM, MVVMP, TCA, SwiftUI, UIKit, Kotlin Multiplatform, Jetpack Compose (for iOS), hybrid, imperative, reactive, declarative, or a mobile clone of the Elm architecture, you name it.
Unfortunately, it isn’t possible to please everyone. Setting aside your own preferences, it’s healthy to view them as alignment tools that come and go in different flavors.
Instead of worrying which architecture to pick, try to move forward with the simplest solution possible. Consider adopting a fancy architecture only when a simple solution doesn’t suffice.
Keep in mind that you don’t have to follow the latest trends. SwiftUI is popular today, but I don’t see UIKit leaving soon, either. In contrast, I wouldn’t value “5 reasons SwiftUI isn’t production ready” pop articles, because people are making great apps with it. Try to use what works for you and your team, long term it doesn’t matter too much. It’s more important your team is aligned.
Maybe your team might feel the need to implement a new architecture, especially if you’re experiencing problems, such as having to write UI Tests to test business logic. But in that case, I’m willing to bet that the “wrong” UI architecture isn’t the source of these problems.
Maybe the problem you’re dealing with is unrelated to UI architectures at all; Such as missing documentation, missing proper examples, lack of training, a bad onboarding experience, disagreements not being resolved, a poor code-review culture, or multiple issues combined.
Your team may come up with rules such as “A viewmodel may never have a
import UIKit statement”. But that
import UIKit is only a single pull request away once a team member uses that oh-so useful
AttributedString. Which shows more of an alignment or code-review problem than a “we need a new UI architecture”-problem.
Chances are, the UI architecture you picked is fine for the foreseeable future. Note that plenty of apps in production today are powered by good old Objective-C and viewcontrollers.
Despite sticking to fewer architectures, it can motivate people to try out new technologies or architectures.
But instead of overhauling an entire codebase—such as replacing all UIViewControllers with SwiftUI views “because it’s new”—try starting with an experiment.
Grab a smallish feature, and build it using a different technology, and relay the lessons back to the team. Now your team has controlled experiments and everyone can learn from the experience.
Nowadays, I think it’s safe to say that RxSwift had to make way for Combine and SwiftUI, thanks to first party solutions. And some might say that Combine is losing part of its share to Async/Await.
The discussions about MVC vs MVVM turned into discussions about UIKit vs SwiftUI, and whether a
View is a viewmodel or not.
And there will always be the next best thing for developers to squabble about.
This is why my upcoming book Mobile System Design covers applying UI patterns and Dependency Injection using vanilla code. It’s a more timeless approach, regardless of which patterns you adopt.
It’s already a challenge to get a large team to align on one way of working, and sticking to a few select architectures can help create some sense of predictability to a codebase. This helps, because once a coworker swaps teams, or a new person joins and reads docs, they already have a general idea of where to find things and how things work.
Want to learn more?
Coming in 2023!
Subscribe to get updates to the upcoming book:
Mobile System Design
Learn about passing system design interviews, making features faster, testing apps more thoroughly, avoiding overengineering, dependency injection without fancy frameworks, writing strong components, and more!
Suited for feature engineers of all mobile platforms.
Tjeerd in 't Veen has a background in product development inside startups, agencies, and enterprises. His roles included being a staff engineer at Twitter 1.0 and iOS Tech Lead at ING Bank.