Things a MVVM tech lead never told you about

Have you heard of … property observer?

Medium daily digest decided to recommend this article to me. It’s funny because the author who claims to be iOS tech lead all but admits that view model is boilerplate code. Quote:

When implemented outside of the Microsoft stack, the presence of a declarative data binding technology is what makes this pattern possible, and without a binder, one would typically use MVP or MVC instead and have to write more boilerplate (or generate it with some other tool).

Meaning: you need SDK support. Otherwise you have to write boilerplate shit.

Then he proceeds to write boilerplate shit.

Since the article is published in Dev Genius. Let’s tackle this as an intellectual, and do not just take his words for it. It’s not what he said, it’s what he didn’t say that is interesting.

For example, he didn’t say MVVM code he wrote is not boilerplate. He said you need a binder and he creates a binder. But he didn’t say you need to manually establish binding for every event for every view in every view model you created for every view controller, every time.

If you were a Dev Genius, MVVM without automatic binding support is the end of story. If something can be done automatically by SDK, it’s routine, it’s boilerplate. Developer time is valuable and should be allocated on activities that require creativity. You shouldn’t even allow boilerplate even if is generated by external tool. Working with boilerplate dulls your code sense. You know what activities require creativity? Not writing tools to generate boilerplate, but writing tools to avoid boilerplate. If I were Dev Genius, I’ll publish that article under humor category.

I'll list some other funny things that he didn’t say below. Maybe this article get to be published under humor category.

It’s not a story MVVM dev would tell you.

If you want to observe a value type, the language built-in go-to is property observer. Especially when this binding is not two way. Most of time, including his examples, you are setting up for a one way event-handler.

So the first mistake is skipping property observer completely. No discussion, not even a mention.

For example, you can use a value type to control state while separating view from model (not that it’s absolutely necessary, there are ways to work with a view directly without having the problems MVVM say I’ll have)

// under the scope of a view controllervar btnState = false { didSet { updateUI(newValue) } }
// btnSearch.isEnabled = newValue in updateUI(...)
// in delegate callback
btnState = true

What’s the difference? That, is what a Dev Genius should ask.

State change by delegate is represented by a mutation of value type. Remember you have to use reference type for view model. This is a level beyond already. There’s no value type anywhere in MVVM, which in large part has rendered MVVM obsolete.

Second mistake is to use implicit closure. You can’t reuse that. Guess what happens when you have another button? I hope you recognize that this is just setting up callback in an observer pattern. Where’s the event coming from? You still have to rely on SDK by setting up delegate and data sources. So work is not simplified nor reduced, it is increased now that you have to insert a middle man for an observer pattern. None of these are discussed, which if the author is a Dev Genius, he should. Comparison matters.

Imagine you have to do this in 2022, swift 5 later already, to observe a property which should be a value type. Stop copying Java.

He then saw the err in his way and tried to amend it.

This is the classic “if I make it look clean, then it is clean” ideology of MVVM, VIPER, Clean Architecture… etc.

So all their time is spent on organizing project hierarchy, creating new files, classes, categorizing problems without solving them. You will have 50000 classes spread over 20000 files each having 20 lines. Any implementation would be broken in 6 parts each having a manager. The assignment of managers will take up 5000 lines and is best generated by tools.

What this actually does, is to couple view with binding. Binding may not know about view, but view needs to know about binding! Anything can happen in callbacks of an UI element. Binding shouldn’t care about what could happen, and least of all, view. Imagine you have to look up extensions to see what this binding actually does, and more often than not it won’t be exactly what you need, so you have to add some more, which makes the next look up more difficult. You then will have problem with naming, documentation… etc. In other words, it won’t be scalable on top of being nonsensical.

Case and point, look at this extension.

The “binding” introduces a “reloadData()”, which is major side effect for a tableview. This happens under “view extension” when you create a “binding”. As a comparison, how would you go about doing this using property observer?

var data = [JSON]() { didSet {table.reloadData()} }

Yes I access view directly as God and UIKit intended. In UIKit, if you want to get a view reference, you can find a way to get that view reference, IBOutlet or otherwise. View model (being a reference type itself) doesn’t protect shit.

While simple, it defines a reactive response to data change. If you can manage the response in terms side effects, it’s a viable alternative. Not saying it’s the best solution, but it is a solution, and you need to at least beat this to justify additional overhead costs.

I have yet seen any MVVM article comparing with this. This is the first thing I would do if I were to convince you that these overhead costs are investments so you can have some kind of advantages.

All these setup and this is what you bring? A “simple wrapper”.

Hint: there’s something called “computed property”.

E.g.;

extension SearchResult {
var trackName: String {...}
}

If this “SearchResult” is not value type, I’ll ask why it’s not value type.

If this “SearchResult” is value type, then there’s no need to wrap it in reference type. In fact, the only way to share SearchResult is to have it wrapped in some reference type… So you see, MVVM asks you to do the exact opposite of what you should be doing.

And the end result, a wrapper. Remember when I said boilerplate makes you dull? If you can accept wrapper, you then will accept code-generated boilerplate, then you will think VIPER is not retarded.

Now imagine you work on another page that shows data from another endpoint. You have to create view model again, because underlying view is changed. You have to create bindings again because they are dependent on view. Then you have to create this same networking code again because they are not refactored out. At what point during this process do you feel joy? Do you feel like a Dev Genius? When will this “reusability” kick in? 80% of your codes would be button.isEnabled = true or func loadData() {vm.loadData()} or var username: String {vm.view.username} .

If you accept boilerplate, you will accept more boilerplate. Cut the middle man. Cut useless fat. Ask for comparison (which I did, with no reply, so let me compare for him). That’s how you become a Dev Genius.

I’m gonna share this insight as wrap up.

In a sense, this dude from Dev Genius is right. Let me quote him again:

without a binder, one would typically use MVP or MVC instead and have to write more boilerplate (or generate it with some other tool).

And he proved that.

Orite god damn it, stop sending me MVVM shit please medium daily digest. Can’t help but reply.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store