Dave DeLong - A Better MVC

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hi everyone my name is Dave DeLong does Patrick mentioned I am a senior iOS engineer at Snap but mainly I'm a guy who likes to think too much about things so before we get started there are a couple of things I need to warn you about with this talk first off I need to do a shout out to our legal and PR departments that the thoughts expressed in this presentation are my own opinion and do not necessarily reflect those of my employer or others who work there high legal the next step I'm going to be using a lot of familiar terminology in this talk and a lot of it is going to kind of maybe cause comes some confusion so let's clear things up right away first off I'm gonna be talking about views I'm also going to be talking about UI views and I want to make sure you understand upfront that when I talk about view I'm talking about the view and the MVC sense of a view of a thing that does UI related things it is not necessarily the same thing as a UI view so if you watch the slides I've tried to do a good job about making sure that when I'm talking about a UI view I'm using a code font and a regular view is just a normal font same thing with controllers I'm going to be talking about controllers we also have UI view controller again they're not necessarily the same thing but I hope that the concepts that I talked about today will all sound familiar especially after listening to the talk earlier today about a parka texture this should all be pretty familiar so let's talk about MVC MVC as we know is a standard cocoa architectural pattern it's also been around much longer than cocoa has and we have this diagram that Christophe hates where you have the controller and you've got your model and your controller tucks to your model and your model talks to your controller and then the controller turns around and you know really relays that information onto your UI and and you know gets events back so this is like of course the high level thing we can hand wave of like whether this is correct or not but one of the things I want to point out is that we talked about this being a pattern but it's not really a pattern it's more of a philosophy it's a way of thinking about things and the philosophy is that MVC's says that we need to separate concerns so what does that mean it means that our storage doesn't know about our networking and our networking doesn't know about parsing and our parsing doesn't know about routing and our routing doesn't necessarily know the specifics of our business logic and the business logic doesn't necessarily know how things are rendered like these are all separate areas of concern in our app and this is the philosophy behind MVC that we separate all of these things out however MVC of course is easily abused and the common example is that MVC doesn't actually mean model-view-controller but it means massive view controller and this this is a problem massive view controller is the the idea that you have a UI view controller and you start loading things into the it's it's behavior such as dealing with loading your views or your zip zorse storyboards you implement IB actions you've got model observation you've got networking and callbacks you have your data sources to supply information to your table view or collection view then you have delegates to handle in reactions to that and of course you have trait collections because this might be a you know hybrid or iPad and iPhone app or you know supporting multiple size classes and then oh of course there's actually also the logic that makes your app your app the problem with massive viewcontroller is that your code is hard to understand nobody wants to open up a file and discover that they're dealing with a 7000 line view controller you have no idea what's going on you can't really isolate functionality to test it you can't isolate functionality to change it reliably it's it's hard to work with it's hard to test and we deal with these view controllers where 2,000 lines of code is common and that's a travesty and we also run into situations where we have 10,000 line view controllers and when we come across one of those things we just don't want to live on this planet anymore because who wants to deal with 10,000 lines of tightly coupled code but what if I told you you could fix MVC so let's talk about how we could make a better MVC now one of the principles I adhere to really closely is that when I'm faced with a problem to not just throw it all away and start over from scratch so don't rewrite let's refactor as engineers we have this this tendency that we come across something we don't understand and so our gut instinct is to try something different and this you know sounds really nice because then we're dealing with something that we understand entirely and it's in it's all up to us but let's not do this let's refactor MVC we're going to make iterative changes to MVC and arrive at a better pattern and we're going to do this by making eight observations so observation number one patterns are like data structures so let's talk about data structures really quick so when I talk about data structures I'm talking about ways to organize your data so they have performance characteristics we know that if you've got in an an array and you want to find or you want to get an object at a particular index in that it it's a constant time operation just jumping to that index however if you want to find a particular object that of course is linear time so different data structures have different performance characteristics they also have different memory characteristics so the amount of memory you need in order to implement a data structure affects you know its capabilities but choosing the right data structure means that making it makes certain problems really easy to solve so if I need a data structure that says simply you know have I come across this thing before then I probably want a set because I can have constant time lookup that's fast whereas using an array would be linear time lookup which would be slower if I'm only dealing with like ten objects it doesn't really matter but if I'm dealing with thousands of objects that's that's very important so choosing the right structure makes the right things easy now let's talk about code structures well code structures also have performance characteristics and it has a couple of different kinds of performance characteristics there's a performance characteristics at runtime you know how you organize your code in like how many layers of abstraction you're dealing with affects how fast your code runs the more layers of abstraction you have the slower it's going to run this is why people still write an assembly because there is no abstraction at that point pretty much there's also the performance characteristic of you as the coder if you're dealing with unfamiliar patterns and unfamiliar structures then your performance as the coder drops you cannot be as efficient there's memory memory memory characteristics so again the more abstraction the more structure you have perhaps the more memory you're going to be using and again for the coder the more arcane the pattern the more memory is required to understand it and again choosing the right structure makes the right things easy there are situations where an FRP approach to solving a problem is absolutely the right thing to do even at the cost of it being different from how you typically might solve a problem under other circumstances but the right structure makes the right things easy so how do we choose the structures well when it comes to data structures it's hard to go wrong with array set and dictionary there are situations where you want something more obscure like a you know a self-balancing tree or you know a doubly-linked list or something like that but in general we start with array set and dictionary and only move to something else if we can prove that these will not meet our needs and I would propose that it's also hard to go wrong with MVC that if you're looking for a place to start start with MVC and then once you've proven that it's not going to work move to something else because other patterns are also valid things like FRP or Viper or discover and mvvm fits and you know very nicely with all of this as well these are all relevant patterns they're all tools in our toolkit so in order to make these decisions we need to spend the time learning their respective strengths and weaknesses so that's observation number one observation number two is that our naming effects perception so there's a joke that the two hardest problems in CFS are naming things cache invalidation and off-by-one errors naming things is hard how much time do we spend bike shedding names like you just need to go look at the Swift forums to see how big of a problem this is should this be contains only or should it be all or it should it be all matching or you know we spend an inordinate amount of time naming things so for example if we come across a class that starts NS star it's probably not gonna be a UI concept it's probably going to be more at the controller layer maybe the model layer it might be you I of course it would be you i if you're writing a Mac app but we can make an assumption that it's you know how it's named has effects where it's used ditto if we come across something that starts with you I it's probably going to be a view level concept we do like calling things controllers and we assume that if it has controller in the name it must be a controller and we kind of use this as a default thing to name things you know it's if it's not in our model and it's not a view well it must be a controller and we end up where everything is a controller and nothing makes sense and this is bad and sometimes we'll run out of things to call controllers and so we'll name the managers and set it and pat ourselves on the back because we've solved that problem and then we get into other weird situations where we kind of like reach across the concern separation and we call things view models we have model controllers as well we probably well we of course have view controllers we might even have controller views and naming as naming is weird so this is just an admonition please choose good names observation number three UI view controller is not a controller and before you break out your pitchforks and come at me let's look at what have you a UI view controller does first off it loads views it shows views it lays out views it rotates views it transitions between views in fact it pretty much only does things related to views you well if it only does things about views maybe it's really a view and not a controller I want this to sink in because this is definitely at odds with how uiviewcontroller is positioned by Apple by the sample code by the documentation but what are the implications of this if we consider the notion that a view can UI view controller is not a controller in the MVC sense what does that mean well it means like our view controllers shouldn't have any networking code in them because why would you put networking in a view it shouldn't be concerned about data persistence or even the specifics of how your UI is laid out with respect to navigation between screens there shouldn't be any business logic in your views you shouldn't be directly dealing with your model it's all just displaying stuff so those are those are the things that shouldn't be doing so what should it be doing well it should be receiving an intention from a controller and I'm going to use the word intention a bit meaning kind of what you're hoping to accomplish so it receives an intention from the controller that that intention can be like you know put this profile data into the UI and so it takes that intention that data breaks it apart and puts it into the consensual at UI views it implements some rudimentary IB actions to deal with selection or button tapping and so on and then it translates that those actions back into a corresponding intention and it relays them back out so the question then is if a view controller is a view then you can kind of think about it as just a little bit more complicated UI label so would you do networking or data persistence or business logic in a UI label which is also of you and if the answer is no then chances are you probably shouldn't be doing it in your view controller either observation number four views are small now when I talk about small views I don't necessarily mean code size although we are arriving at that through this approach I'm talking about it from this their physical size their their dimensions on screen the view is a unit of UI and you use a lot of these units to create the UI of your application and you don't have a single view for your screen your your screen of your app is composed of many UI views hundreds of them in fact and so we want to take this concept of a small view and mean small UI view controllers and this is something I really want you to understand that of yook UI view controller does not have to fill your screen it is not equivalent to the screen you don't have to fill the screen or in other words you can show many view controllers on the same screen or a single screen can show lots of view controllers this is I think a concept most people don't get because again the sample code emphasizes the the the notion of like you have a UI tableview controller it fills the screen you're the UI navigation controller it fills the screen you have a UI tab bar controller it fills the screen split view controller fills a screen page view controller fills the screen this does not have to be the case as a view controller a UI view controller could be 10 by 10 pixels or points I guess and that if that's what it takes to simplify the view side of your application then you should do that does not have to fill the screen observation number five views are composable so composition is the idea of adding together lots of little things to make a big thing and its inverses decomposition which is taking a big thing in breaking up into little ER problems and I would suggest that composing the ability to compose and decompose is the singular skill that makes you a good coder it's not really how many languages you know it's not really the frameworks you know it's not the tools you know how to use is can you break problems down into smaller steps can you solve the smaller problems and can you put those small solutions back together to make a big solution all good coders in my experience know how to do this really well and the bad ones don't so let's talk about how we can compose UI view controllers well there is API that deals with us called edge child view controllers it was added in iOS 5 so you literally have no excuse to not use this because there is no app you are shipping today that does not support iOS 5 and the idea around child view controllers is actually it's it's manifest in a bunch of key api's in UI kit all navigation whether it's tab bars or split view controllers or navigation controllers is done through child view controllers UI search controller looks really weird at first until you realize it's using composing view controllers and then it gets less weird it's still a little weird especially how it like MUX with navigation bars in the search field that slides in still weird but it's about composing view controllers I also throw you i refresh control up here as well because if you remember when you I refresh control first came out in iOS 6 it could only be used on a UI tableview controller this was really be intentional and I know because I wrote it this way we had just introduced child view controllers in iOS 5 and we really wanted to incentivize people to use child view controllers in iOS 6 so we have this new control UI refresh control let's put it in the API in such a way that you're kind of you have to use view controller composition in order to use it because you could only use it on a table view controller this didn't work out quite so well for a couple of reasons but there was a method to that madness okay observation number six views are reusable when I talk about reusing views I don't necessarily mean the reuse in the sense of UI tableview and D queueing reusable cells and stuff I'm talking about reuse in the sense of allocating multiple instances of this so whenever we want to display text on the screen we do not subclass UI view and create a new UI label variant if we want something that's interactable we do not subclass UI control and create our own custom UI button so why are we always sub classing UI view controller to create our own view controllers that are only used in one place I would suggest that that is not how it's supposed to be I would say let's write our code with the expectation that we are going to use a view controller in multiple places all of the views provided by UI kit are built in such a way that you use them all over the place anywhere you need a spinner you use an activity indicator anywhere you need a progress bar you use UI progress bar anywhere you need a slider you can use UI slider you don't have to create a custom version for each of these cases so what does this look like well if we consider a couple of different scenarios where we have these view concepts let's see if we can pull them apart and into more reusable components so for example for writing a Twitter app assuming they haven't killed the API yet we might want to eight tweet list view controller but that would be a sort of thing that would really only be used once so instead let's make a list view controller that happens to show tweets or it maybe could show lists of users or it could show a list of you know hashtags or filters and so on so instead of a very specific concept we can make a more general concept that's then reusable in many places we see this a lot we have you know a uiimageview subclass that will go hit the network because we've given it a URL to download an image and so it's gonna do this but maybe instead of like this custom uiimageview we've got an image view controller because again a view controller doesn't have to fill the screen it can be a even just the size of an image view and it's got some sort of protocol typed emerge image provider and then suddenly we've got this asynchronous loading image everywhere in our app or in store instead you know if we've got you know a list that asynchronously loads we will do things like you know we'll remove a view from the view hierarchy or just hide it and like throw an activity indicator that's like centered into the screen and like maybe do some fading stuff well that's really just a container controller that's transitioning between multiple children so it's a container controller that's got you know some sort of list view controller it's got a loading view controller that's just the activity indicators maybe got an error message view controller if something fails and it's just a container that's fading in between a different child so this is the ideally of building a UI view controller that can be reused in many different ways so this sort of container view controller is literally just it shows another view controller and would fade between the old one and a new one and that's that sort of thing is highly reusable a seventh observation to more show data or they have children let's talk about how we build views views generally do one of two things we they add logic and layout by composing other views or they draw stuff and this is the case for all UI views provided in UI kit so for example UI button we use it as a single thing but in reality UI button is a whole bunch of different composed views under the hood it's got image views for drawing borders it's got a label for drawing the text it's got an image view for showing selection state it's got another image view if you've set in an image for a various control state so it's really just a massive composing view even something as simple as UI progress view just the progress bar this is a container view with generally three image view subclasses it's got a left cap a right cap and then a stretchy image view in the middle and so when you're changing the progress of a progress of you it's really just changing the width of an image view and then stretching the image and that's all there is to it and so UI progress view itself is really just dealing with some layout even something that's complicated as a UI text field same sort of thing when it's not in editing mode it's literally just some image views and the label there in the UI text field once you start editing then it brings up this thing called the field editor and and the text system kicks in and that's all weird but the text view text field itself is just composing other views when we build the UI view controllers provided by Apple as well they generally also follow this the same pattern so again view controllers either put data directly into their constituent UI views or they compose other UI view controllers there are some exceptions to this there are cases where we come across UI view controllers that both manage children and put things into UI views so for example a tab view controller you know manages the children of its tabs but it also draws the tab bar you could build UI tab our controller in such a way that the tab bar is actually a private child view controller and then it's responsible for drawing the tabs ditto navigation controller and it's bar and stuff but generally this is this is how you build view controllers they either put stuff into views or they have other children okay observation number eight we've we've done all these things we've made all these observation and what we realize is we still need controllers or as we were hearing about earlier they can be called flow coordinators and stuff because all of this stuff that we've been talking about in MVC is really just focusing on the views right we haven't really talked about you know how to structure you know the routing logic that goes into your controller or how to organize the data persistence of your model and so on so the question then arises where is this logic well this approach is really going to dumb down your UI view controllers you're gonna end up with you controllers that are really small because they never know how they're being used they're just given data and they put stuff into their views or pass it on to new children so they don't necessarily know oh I'm on the profile screen or I'm you know looking at the details of a tweet or or so on so in order to get the actual logic of our of our app we still have to delegate this intention out to our controller layer so there are a couple of ways we can do this we can either do the delegation we can pass around prototype controllers and so on and so we're gonna take a look at this by doing a case study and this case study is an app that I know very well it's the WWDC up hopefully you know it well as well so they is the session details screen of the WWDC app this is multiple screenshots stitched together this is not a super tall iPhone yeah no secret leaking going on here it's just just multiple screenshots on this screen there are a bunch of things going on we have the ability to watch a video we can read session information we've got some contextual actions can look at related sessions and all of this is is manifest in code is like we've got our logic so we observe model to know if the title or the description changes because it can update dynamically we determine what actions are contextually relevant for a session we have to observe some state with the with these actions to know like is this download in progress is it already downloaded so I need to remove it or do I need to initiate a download we of course list you know discover the related videos and then the actions that we perform on this we can favour it a session we can share a session we can watch the movie and then you know perform the contextual actions and of course watch our related movie so a bunch of different things going on on this relatively straightforward screen now if we were to build this as a single view controller this would be terrible let's not build this as a single view controller because remember if we wouldn't make it a single UI view subclass then it probably wouldn't make sense to be a single UI view controller either so how would we break this up well we've got the overall main screen and this screen is divided up into a few different areas we've got the poster frame at the top we've got the title we've got the description and the title and description I would consider separate just because they're positioning changes when you rotate we've got the list of contextual actions and we have the list of related videos so let's make those view controllers so you have a session detail view controller that's really maybe just a variant of a stack view controller because these are all pretty much just laid out in a stack although it does get a little bit more complicated if we rotate and then this has children view controllers a poster view controller title view controller description actions and related videos related content so as we're dealing with actions in passing data around we've got things where you know we've got our controller and I am just gonna kind of like hand wave over what that is because that's a whole different third part of our app so we've got our controller and it's gonna give us some sort of session object and this session detail view controller is in going to turn around and just instantiate those five children and give them each a copy of the session information and then that title view controller is going to pull out the title the description view controller will pull out the description and and so on now when we need to get actions back we can perhaps one way to do it is by setting up delegates so our session video post review controller delegates to the detail view controller detail view controller delegates to a controller and then we have some action whether it's tapping a poster tapping a related video those get passed up to here this then recontextualizes what that intent is so instead of getting a message of just like hey the user tapped on this button we're now going to translate that into the intention of we want to watch a video and so at each layer we're dealing with the semantically appropriate way to describe this information so this is approach number one approach number two would be more of a dependency injection sort of approach where we've got the detailed view controller and then we receive again some how I refer back to the earlier talk on on how to do this we receive these sort of protocol typed objects of that are used to receive the intention directly so instead of delegating up layers through the various view controllers we can kind of bypass directly to the controller layer and again you know translate this tap a poster into whatever action is appropriate for those for those objects so this is how we can make a better MVC we've made the series of observations that patterns are like data structures that view controller UI view controller is not actually a controller in the MVC sense that our view controllers and views should all be reusable that they should rely heavily on composition and when we end up when we when we apply all of these things to our apps we end up with some really interesting results we end up with really tiny view controllers and when I say tiny I really mean tiny like the smallest view controller I've written in this approach was four lines of code there was one line to declare the class a second line for an init method that really just called super dot init with nib named nil bundled nil I just wanted a plain ol initializer I had to have a third line because Xcode makes me put in in it with coder and that just fatal erred and then a fourth line for a closing brace all this just so I could have a nice init method but that's really it and then the entire UI was just loaded from the zib for this for the view controller and it just happened automatically this was in particular view controller that was a an activity loading state so it's really just an empty view controller with a spinner in the middle that started automatically so no code necessary four lines of code but I could use it anywhere I needed to indicate asynchronous loading going on but generally your view controllers will be under 200 lines of code and if you follow this approach you will get to the point where 300 feels long which i think is a really good place to be in second you will find that you rarely ever subclass UI view a bit if you were to go take an inventory of your apps you would have dozens of subclasses of UI views just because you're using UI views to do custom layout once you move UI view controller down to the view layer you can realize that you can just do all the layout in the view controller and you never ever never have to subclass UI view again which i think is really nice because it means you have more influence on you know dynamically choosing layout with regards to lifecycle traitcollection stuff and so on the only time you ever really need to subclass UI view with this approach is when you need to fundamentally draw things differently so like you need to use a different kind of CA layer to back your UI view for example you end up with extremely reusable UI view controllers so like I was talking about this this four line view controller to indicate activity progress that's the example you end up with a view controller where like you just give it a new child view controller and it will just fade from an old one to a new one or you have a view controller that's literally just like it shows a list and maybe that list is made up of other child view controllers or so you're dealing with now with view controllers as cells in many cases so you get extremely reusable view controllers and I think even more valuable you get a clear separation of concern you look at a view controller and you know I'm displaying a list I don't have to worry about the details of you know how this tweet is getting laid out or or whatever is just I'm displaying a list and that allows you to really focus on the problems at hand and make fixes that are appropriate that don't have cascading effects and so ultimately you get happy programmers you get code that's nice to clean it's nice and clean and then you're happy to work on because it's it's beautiful it's small it's focused it's it's it's fun it's not a 10,000 line view controller and that makes me happy and I hope it would make you happy too so thank you for listening if you have any questions you can come up and find me afterwards and I think I've ended a little bit early so we can get to lunch a little little early thank you very much [Applause] you
Info
Channel: Swiss Mobile Developers Association
Views: 8,767
Rating: undefined out of 5
Keywords:
Id: YWVzCd5FYbs
Channel Id: undefined
Length: 36min 48sec (2208 seconds)
Published: Mon Apr 23 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.