Protocol-Oriented MVVM

A discussion on how and when to use Protocols and MVVM in Swift.

natashatherobot

Transcript:

00:05: Hi, everyone. So today, I'm gonna talk about Protocol-Oriented MVVM. It was too long on the slides so I just abbreviated, so here's your new hashtag. My name is Natasha the Robot. I started doing Swift pretty much when it came out almost full-time. And I think when it first came out I actually would write Swift, but I was coming from Objective-C so I would write code that was basically Objective-C and Swift. I would write lots of classes. And then I started watching different talks from other people in the community. Andy Matuschak gave a great talk at the Functional Swift Conference and then later at the Realm Meetup, and he talked about how you're supposed to use Structs and all the benefits of value types about immutability and copying data, so all the stuff you already heard. So I kind of went back and I was feeling all good. I'm like, "I gotta use structs." And then it started off and I was like, "By default, everything I start, I'm gonna start using structs." But then I need to test my code or I need to do something else, and then the next thing I need to do is sub-class. And while I knew and I felt good about starting with structs, I had to kind of regretfully go back and just put a class there and feel bad about myself as a Swift developer. [chuckle] 'Cause I didn't fully understand how to get rid of sub-classing.

01:37: So this year at WWC, there was this amazing talk about... We met Crusty, and they talked about how to use protocol-oriented programming in Swift. So the answer to sub-classing was using protocols. So that really put things together for me. And what even more put it together was... And we've seen protocols before, we've used them a lot as Objective-C developers, but it wasn't the same. They said that Swift is a protocol-oriented programming language. Objective-C, by its name, is an object-oriented programming language, so that's how we were thinking. And sometimes we use these APIs that use protocols, maybe we created some of our own, but in Swift, protocols are the main architectural decision that you're making, and that you're using that instead of sub-classing so you can use value types and get all the benefits from that. And this was by Dave Abrahams, he's the professor of blowing your mind. And by the end of that session, my mind was blown. I was like, "This is awesome. Let's use protocols."

02:50: But then I kinda had the same moment as I did with Structs. I was excited, I understand the benefits, but then I went back to work. And then you kind of use the same code-base, it's easy to follow your own work that you're already doing. But then as I was working and coding in my own code-base, I kept kind of having protocols in the back of my mind. "How can I use these?" 'Cause the answer wasn't as clear right away when you're already using all these other things and you have an existing code-base. So one time when I was sleeping... So sleeping is how I get my best ideas, or my brain at least gets my thoughts together for me, which is really nice, so I highly recommend sleeping as a developer. [chuckle] But I woke up one day and I was like, "Protocols, I get it now." I found a use-case that's relevant that I can go back to work and use it actually. And the use-case was MVVM. So talking about MVVM, I'm not gonna go into too much detail, but you can google "Artsy Engineering” - Ash Furrow wrote a great blogpost recently on doing MVVM in Swift. He also has one on Object C that is introduction to MVVM.

04:11: But the way I guess to think about it for the purpose of this talk is that usually we have MVC architecture, Model View Controller. With MVVM, you have Model View View Model, and the idea is that the View Model is the layer between your model and the view, which translates your raw data into how the data should be displayed. So one great example is if you have a banking app and you have some kind of currency, like how much money you have in your account, that should be stored as a decimal number as a raw data type, but when it's displayed to the user it should have a dollar sign or a Euro, it should be formatted with commas or periods depending on the country, so that type of display logic of how the raw data should be displayed to the user is in the View Model layer. Another example is simple as first name last name fields in your model, but then for your user you might wanna display one string that's last name, first name. So how you do that, like string interpolation, that should be in the View Model, so that's the idea behind it. I highly recommend checking it out and using it if you haven't already.

05:26: So today I'm gonna walk through something very simple, so right now I have a setting screen and it has just one cell on it which is the... It turns your app into minion mode and turns everything yellow, it's really fun. And as Sam mentioned earlier, as iOS developers unless you're like a game developer, you're probably spending a lot of time in your table views and you have these cells and you're configuring these cells. So something like this simple cell will actually have a lot of settings. So this was my life before protocols. [chuckle] Unfortunately you add table view cells, they don't have a custom initializer where you can inject different settings. So the way I dealt with it for configuring each cell is to have this big configure method, and those who worked with me, they'll tell you these can become even bigger like ten. Right now it's like six different things but then imagine you have a more complex cell. Now you have a subtitle, subtitle color, subtitle font, so this configure method would get pretty large but you want it to be there to force those configurations to be passed in, 'cause individually they could be forgotten. So this is kind of ugly, but done in Swift it was nicer because you can set up a default parameter, so switch colour here is by default purple colour, so then other places where they don't need to customize things they can just kind of skip that parameter, so method signatures are not that long.

07:00: But still if you need to add an image or something, now you need to add three more things. You have to change your method signature in all the cells. It wasn't the best solution, and I wasn't feeling comfortable with it, but it was kind of the best I could come up with. So this is where protocols come in. So that was my first thought, "I can fix this configure method." So my first solution was basically take the configure method and make everything into a property or into a protocol property. So now I don't have that configure method, I just have kind of each individual, whichever object implements this protocol, will now have a much nicer implementation of each variable. And just like I had default parameters in my configure method, you can use protocol extensions to basically set those default parameters. So now anything that doesn't need to overwrite them, you can just have it in there. They don't have to implement that part of the protocol. So this was pretty nice and now my configure method went from six things to just passing something that conforms to this protocol. And it's gonna configure, based on that, gonna set the cells title, colours, all that stuff.

08:24: So this is again, what your view model will look like. I'm doing a simple version, so it doesn't actually interact with the model. But normally you might wanna instantiate your view model with an actual model. And then you can manipulate that model or take the data from that model to customize it for how it should be actually displayed. So this was pretty nice and I was pretty happy with it. Okay, got a view model and now in your self furrowed indexpath, you just de-queue the cell and then you pass in a view model. So this was great this was a very... Again like view models, one of the biggest advantages is, it takes a lot of the logic that would be in your massive view controller to somewhere else. So this is, your self furrowed indexpath is only three lines which is really nice, and all that logic of how everything should be displayed is in your view model, which can then be easily tested. So I was very happy with this. I was like proud of myself, kind of what Sam said, that feeling of like, "I'm a real Swift developer, this is great I used protocols."

09:29: So I wrote about it on my blog. And someone said," Hey you know you can split up your protocols into two things following the table view model. Maybe you can have a data source and a delegate," and I thought that was a great idea 'cause that makes sense. There are two parts to my cell. One is what's the data that should be displayed, like the title and whether the switch should be turned on or off, and then there's the part of what should it look like, what is the fonts, where are the colours? That's kind of separate, so I loved this idea. So I implemented two protocols, I updated my configure method to have a data source and delegate. I updated my view model. It first had conformed to the data source protocol, and then I extended it to conform to the delegate. So now it had kind of had that other part, and I love using extensions for separating out my code and when you have different protocols, it looks really nice to hold everything together in one part, so this was my switch with Tex-al delegate.

10:37: And it's pretty much the same thing. I de-queued the cell and then I passed in the view model to my configure method. It's both the switch cell... This was the data source and the delegate. I was actually really happy with it. I came up with this cool idea of using protocols to fix something. Then I blogged about it. And then someone came up with a better idea, and then I blogged more about it. So at this point I'm feeling really good. Like "That's awesome." I'm kind of relaxing and then I read another article, a really good article that I highly recommend, and it's called "Mixins and Traits in Swift 2.0." And basically this person shows, and I'm not even a game developer. But this example made so much sense. And he shows how normally in game development you would have a big sub-classing structure, because a monster, there could be different monsters. And there's different players based on a castle, so there's very hierarchical structure for game developers, but then weird things end up happening such as like humans or monsters can shoot, but then the castles can sometimes shoot because you have like a cannon on it.

12:06: So then you kind of end up with this weird helper shooter class and then it becomes a little bit more spaghetti code, then you can imagine things like that keep coming up and then things get more interlaced than you meant to in the nice hierarchical model. So he talked about how you could re-factor that big hierarchy into just pretty flat structure and instead of... And for the things that are traits, like having a gun, having health, that could be all created with protocols. So this is what the code would look like, which I thought was just really gorgeous because just by looking at this class signature, I can already say that a player has an AI trait, gun trait, transact trait, health trait, the castle will have a gun trait. So you can kind of already see how beautiful this looks.

13:03: So yeah, the nerd in me was just like, "Yes, this is really beautiful. I wanna use it." So this is where I came up kind of applying that concept from game development to my table view cells. So instead of separating my protocols into either one block or into kind of a data source and a delegate that only was relevant to my particular cell, I actually separated it out into things that are relevant to the object displayed by the cells. So a label would have a text presentable protocol where you can kind of talk. Everything that should be presented by the text should be there. So like text, text color fonts, and then for switch, this would be again the same, everything that has to do with a switch would be in there. You can imagine this type of composition. You can expand it to, as you have more cells with different type of objects, now you can have an image presentable protocol or you can have a text field presentable that talks about your place holders and text.

14:11: So now none of this is tied to my actual cell, it's a lot more abstract. And the benefit of this is that, like if you have labels on a bunch of cells in your project, most likely they're gonna have the same font and they're gonna have the same text color. So again, you can use protocol extensions and now anything that conforms to the text presentable protocol will already have the fonts, the default fonts, and colours, and everything setup for you. So this is already very nice 'cause when you try to re-factor, you just have to go to the text presentable protocol and you change all the default labels. So, this is... I'm really excited about this.

14:56: And in your table view cell, 'cause I was trying to get more like that game right now where you can go in and just read, "What do I need for the cell?" So I already called it switch with text view, with text table view cell, but now I have this generic type that it's looking for and it's a type that has to conform to the text presentable protocol and switch presentable. So just by looking at the signature of this class, I immediately know that this is what it needs. So I personally love this 'cause I can right away say, "This is what this class does”. If I need to add an extra one, I do a comma, add image presentable. Whatever the cell needs. So now my view model is just gonna conform to each of the relevant protocols. Each one in an extension so you can kind of keep it clean. So this is the text presentable. It has what it should look like, what are the fonts, the colours. If you have protocol extensions, you don't even have to include the colours and fonts if it's default, which is really nice. And then same thing for the switch. I can say, "The switch should be on or off, this is the color, what should happen when the switch turns off or on?"

16:15: So, your table view cell again looks the same. You're just configuring the cell with delegate and I think Sam hinted that you can even put that in a protocol for all table view cells. The only difference is that when you de-queue the cell, you do have to specify that the type. So that's how generics work in Swift. So I'm saying that the type that's gonna be passed in as minion mode view model and this is my view model that conforms to the text presentable and the switch presentable protocol. So it all compiles and works. So I'm really happy about this. [chuckle] Yeah, it's very composable. It's abstract, but not abstract in a way where there's custom operators and that it's not readable. But the main reason I think, Ash Furrow mentioned earlier, that when you get a best practice you kind of know. For me, one of the things I look for when in a best practice or one of the ways I know that this is... This feels good, maybe that feeling. Is because I know that my project will change. I know that the code I write today will be deleted or it's gonna have... Or someone is gonna come and say, "I want the image here." or "I want a different color." So these are things that I'm expecting as a developer that everything I write today will have to be rewritten. That's the constant I'm working with.

17:40: So, this is why, for me, this type of protocol system is amazing, because if I needed to again add that extra image in my previous configure method, I would've had to add maybe three more fields. What's the image name? What's the size? Maybe type... Like should it be fit, scaled, things like that, and I would've had to re-factor all the code, all the matter signatures and that would have been painful and that's bad for change. But with this new system if I need to change something, I just add a image presentable protocol conformance to my cell and then I just extend my view model to configure what that image should be and I'm done. Or if I need to delete it, I can delete the protocol necessary, delete that part of my extension, and it's done. And I love that you can do default protocol extensions with the defaults right there because, again, you can change all your default labels just by changing one line of code. So that to me is really powerful and really easy to test.

18:54: So the robot in me is very happy and ready to ship this code. So kind of what did I talk about today? Consider using protocols to configure your views. So I just talked about one small table view cell. But again, this could be used for any view, any view can have have a label or an image or a switch, all these components. So this is something like a pattern you can try to use with your views. Protocol extensions are amazing for defaults. So any type of text or colours that are relevant to a lot of your views, this is a great way to put them there.

19:33: And use view models to provide data for the protocols. So you're likely gonna instantiate your view model with some kind of model and then the information you're gonna provide to your views should be based, taking that raw data and putting it in a way that the user should see it. But the main point is that I just talked through three different implementations of using protocol-oriented programming for my views, and each time they get better and better and better. In my opinion I think that they get better. So I don't want this to be a kind of like "Go home and I'm gonna use this thing", which maybe that's a good starting point, but I wanna hear from you, I wanna learn. If someone comes up or if someone thinks this is horrible, here's a better way to do it, I'm happy to hear it. Or if you think of a better way to do it, I'd love to hear it. 'Cause like I said, for my delegates and data sources, that was someone for my blog. And that's what I'm looking for in the community, I'd love to hear from you. Thank you.