My Personal Takes from Using Combine
I have a confession I want to begin with — before adopting any new technology or design pattern, I need to understand its benefits and problems.
While it may sound reasonable, this behavior was holding me back in some important areas over the years.
For example, it took me almost two years to get into Swift (because “What is wrong with Objective C?”) or get rid of MVC (“What’s the matter, suddenly MVC is not good enough?”).
You can say the same for throwing exceptions (“Just return FALSE”), dependency injections (“Why do I need to write init function”), and many more. I really need to understand why to change my beloved habits before getting new ones.
Reactive Programming was no exception. After all, I wrote hundreds of classes without reactive programming.
When Apple introduced Combine, I felt that maybe I’m missing something and need to dig in a little more. But, I still couldn’t understand precisely what “pain” is supposed to solve.
So, I did my first step — I implemented a small, Combine implementation. I hooked a page title to a view model instance variable.
For some reason, I really liked it and tried to understand why.
So I tried to compare it to a conventional implementation.
A standard UI design pattern is built from separate classes with different responsibilities. The most important task is to design the interfaces between those classes.
Now, this is not a negligible task — interfaces define how your components communicate with each other and what their implementations are.
There are different ways for your classes to communicate — delegates, notifications, or closures. But in the end — they are all “interfaces”.
In fact, when you think of it, Interfaces represent half of the development itself! Similar to “knowing the problem is half of the solution”.
And then it strikes me — Combine (or RxSwift, for that matter) significantly reduces the number of interfaces I use in my code.
With Combine, I connect streams of data updates directly to UI components, bypassing delegates, closures, and function calls.
In fact, I can chain different layers in my App Architecture without the need for interfaces at all.
It’s like paving a direct road instead of building an interchange network.
This move made my code more straightforward, more decoupled, and much more stable.
The Async Challenge
Combine is primarily famous for handling a-synchronized tasks.
Async programming considers being challenging — difficult to build and hard to test. But over the years, we came up with solutions and paradigms that let us get along with it. I’m not saying Combine is not super helpful with Async work, but for me, building a stream of data through different layers up until the UI was a much more profound advantage.
SwiftUI is built upon Combine. On the one hand, moving to Combine helped me understand SwiftUI better, but on the other hand, it enabled me to leverage UIKit and get it closer to SwiftUI. In fact, SwiftUI fits in just nicely when your layers are connected using Combine, but you can now easily swap it with UIKit by using @Published variables and Observable Objects.
I started by saying I need to fully understand why I’m doing because I hate doing stuff just because they are “new” or “this is how things are done today”. I genuinely believe that understating the cause of what you do improves how you implement and make use of new technology and ideas.
Always dig in and think of what and why you do what you do, it paid off.