Remember when I wrote about MVVM and eventually in 2015 produced this: I learned that the “view model” in the architectural style of MVVM is a “model of the view” instead of a “model for the view”. Let me explain the difference and the benefits of being able to chose between both.
Joe Fabsevich (@mergesort) proposes to call data to configure UI elements “View Data” and keep the objects dumb. From part 1: In my experience, things become harder to maintain when they start becoming a crutch, as a place to put your code if it doesn’t neatly fall into the Model, View, or Controller label.
You can only improve things inside the frame you pick. If your frame is too narrow for the problem you try to solve, you cannot properly take everything into perspective. That’s a trivial statement as it’s only re-stating the same thing, but it’s worth stressing. Apply this to code. If you focus on code heuristics to improve your code base, you cannot improve the structure of your program. Even though the structure is manifested as code, it’s not code you should be thinking about. It’s concepts. Code is just the textual representation you stare at all day. Structure is what the imaginary entities of your invention bring forth.
Earlier this month, I wrote about validating temporary models for forms. The validation returned .complete or .incomplete, which doesn’t help much when you want to show what did go wrong. So I came up with a richer validation syntax.
Ian Keen posted an article about type-safe temporary models. You would use them like scratch pad contexts in Core Data: in forms, you collect information into these temporary models and then generate your real objects from them.
Picking up on my post “MVVM Is Quite Okay at What It Is Supposed to Do”, here’s a few images which illustrate the problem of mistaking MVVM for a solution to a structural problem. It’s the whole post in 2 images. Model–View–View-Model helps with the view layer. It can be a tool to break up a view controller into smaller things. But it’s still only a refactoring of view components into more objects.
Criticism targeting MVVM (Model–View–View-Model) from late last year essentially points out it’s not the silver bullet some take it for. Most of the stuff is missing the point. How are you supposed to make sense of it? What’s good advice for your project?
I executed my plan from earlier this week to split TableFlip’s monolithic view model into sub-view models. The process wasn’t too complicated. The highlights: The current hierarchy of controllers in the view layer is as follows: The window doesn’t look too complicated and there truly are not that many view components involved, but still it’s quite some work to keep things well coordinated. The TableViewController file clocks in at about 400 lines of code although it mostly delegates stuff to other objects. There’s still room for improvement, but I have to see patterns, first. I even extracted NSTableViewaDataSource and NSTableViewDelegate into different objects months ago. Today I doubt this was a good idea in the first place. We’ll see.
The upcoming changes in TableFlip’s user experience made me ponder how I structured the app’s modules. The bottleneck I created in my app is simple: there’s one presenter which transforms the model into a view model; the presenter defines a protocol for the view it expects and passes the view model to the object that satisfies this contract.
That’s a recent question from the comments put in my own words. A view model that encapsulates the display state sounds promising at first. But when you don’t have a simple view that displays one thing, how do you model that in code? How do you model a sequence of view controllers, for example a more complex checkout process?
Rui Peres proposes to make UITableViewCell view models the topmost model data. Traditionally, Cocoa developers stored something in arrays that corresponded to the indexPath of a cell. In principle, this qualifies as “model” data already, but it’s not yet a view model. In practice, it can even be something different than a view model entirely – and make your view controllers slimmer!
One thing that repeatedly messes up the conceptual purity of a view model is figuring out which entity should be mutated upon user interaction. Part of this purity stems from the fact that a view model is best served as view data to stress that it doesn’t contain much (business) logic. Making the data mutable introduces a lot of problems figuring out what that view model really is.
One of the commenters nailed it: any MV* variant focuses on architecting view components. Only VIPER takes the application as a whole into account. MVC by itself is an architectural pattern, but not an approach to app architecture in itself.
A UIViewController belongs into the user interface layer and is, in fact, a composite view itself. That’s confusing at first because of the name. This insight will liberate you from thinking that a view controller is sufficient to glue data to UIKit components. There’s room for a whole application between these two.
The VIPER example is exceptionally good. It takes VIPER’s heritage of Clean Architecture and Hexagonal into account and defines the Interactor through an output port. In that way Bohdan’s sample code is more east-oriented and cleaner than what you’d usually find on the topic:
protocolGreetingProvider{funcprovideGreetingData()}protocolGreetingOutput:class{funcreceiveGreetingData(greetingData:GreetingData)}classGreetingInteractor:GreetingProvider{weakvaroutput:GreetingOutput!funcprovideGreetingData(){letperson=Person(firstName:"David",lastName:"Blaine")// usually comes from data access layerletsubject=person.firstName+" "+person.lastNameletgreeting=GreetingData(greeting:"Hello",subject:subject)self.output.receiveGreetingData(greeting)}}
Usually, you’d model provideGreetingData() as a function that returns the data to the caller. This will cause trouble in async processes of course.
You see in the full example that the amount of types seem to explode. Don’t be afraid of that as long as you can assign each type a specific responsibility. Then it won’t turn into the mess everyone seems to be afraid of.
Having used VIPER in apps myself, I see a problem with the names, though. XYZInteractor and XYZPresenter aren’t much better than XYZController in terms of expressiveness. On top of that, a concrete Presenter is always modelled to act as event handler, too. Don’t let this fool you into thinking you absolutely have to do this yourself – there’s always room to separate writing from reading operations, or event handling from view population.
When I wrote about MVVM with a “control” which really was a presenter, the view in question displayed some kind of data. Any sufficiently complex view would do, but the example focused on a view controller which consisted of a single composite view. UITableViewControllers are a different kind of beast, though.
From the department of Domain-Driven Design code patterns, I today present to you: well-named value objects! You can go a lot farther than you have previously imagined with value objects in Swift. Now that Swift is more than a year old, most of us have seen the use of struct and heard how useful passing objects by value is.
Lammert Westerhoff compared MVVM to Presentation Controls recently. Since nobody likes massive view controllers, I had a look, too, and found a few interesting things. To write a real app with his tips in mind, we’re going to need a bit more, though, and refactor things a bit.
After working on the model of your app for a while, it can be hard to change your ways of thinking and see what should be coming next. How does an app come out of all this? Where does the user interface plug in? It helps to architect your app in layers and focus on the missing parts before figuring out the glue.
This is an excerpt of my book “Exploring Mac App Development Strategies”, on a sale right now! I learned that the “view model” in the architectural style of MVVM is a “model of the view” instead of a “model for the view”. Let me explain the difference and the benefits of being able to chose between both.
Srdan Rasic wrote a good post on creating wrappers around value objects (like Strings, say) and custom-glue them to an application’s interface. It’s a technique I have used in my book on Mac architecture at one point but which seems to be tremendously useful for virtually anything view-related once you get to a high enough level of abstraction.
It’s weird that articles related to programming are so hard to quote. Instead of a quotation, let the resulting code illustrates what he has to say:
class ArticleViewController {
var bodyTextView: UITextView
var titleLabel: UILabel
var dateLabel: UILabel
var thumbnailImageView: UIImageView
var viewModel: ArticleViewViewModel {
didSet {
viewModel.title.bindAndFire {
[unowned self] in
self.titleLabel.text = $0
}
viewModel.body.bindAndFire {
[unowned self] in
self.bodyTextView.text = $0
}
viewModel.date.bindAndFire {
[unowned self] in
self.dateLabel.text = $0
}
viewModel.thumbnail.bindAndFire {
[unowned self] in
self.thumbnailImageView.image = $0
}
}
}
}
So now when viewModel’s properties change, the view controller will update the corresponding interface component. Sweet.