Design Patterns in iOS/Swift: Standing on the shoulder of giants | iOS Lead Essentials Podcast #014

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone welcome to another edition of the Irish late essentials podcast I mic nom Caio and in this episode we'll be answering some questions regarding design patterns so first question what is a design pattern okay so a design pattern is basically a simple and elegant solution to a recurring problem exactly so these kind of problems that you're most likely gonna face as a software developer and that have been solved already over and over and it's been documented on how you can solve those problems effectively so basically you don't reinvent the wheel every single time exactly because the reinventing the wheel is probably a waste of time and it's likely that you might end up with sub optimal solutions yes so worse solutions yes because like a design pattern captures years and years of experience of many developers exactly if you try to recreate it on your own you might take you years and years and years to end up with an elegant solution such as a design pattern so the idea is to stand on the shoulder of giants that's it exactly you build a solid foundation and then on top of that you bring your own contribution so instead of inventing there will learn the solid foundation elegant solutions and build on top of it yes and we have a code by Eric Evans here and Eric Evans says in domain driven design when an experienced developer looking at the domain problems is a familiar sort of responsibility or a familiar web of relationships he or she can draw on the memory of how the problem was solved before what models were tried and which worked what difficulties arose in implementation and how were the result the trial and error of that earlier experience is suddenly relevant to the new situation some of these patterns have been documented in shared allowing the rest of us to draw on the accumulated experience that's it so design patterns give you elegant solutions to recurring problems so it helps your code be more flexible maintainable decoupled in all the good trades you want in a software system and they also give you a vocabulary to talk about those problems exactly you can communicate with others what the problem is in what solution can be applied to that problem so this is very important because if I tell you I am gonna use the decorator pattern to solve this problem then you instantly can identify and can know what do I mean by that so there is there is an effort for eliminating miscommunication there so that's that's very very good very important as well the better your vocabulary the better you can communicate your intent you can take this shortcuts of just saying a word like decorator and conveying the meaning instantly to your peers but both sides need to understand the vocabulary for it to work yes of course yes that's why you have design patterns so a design pattern have a common name they refer to a specific problem they provide solutions to the problem with trade-offs in variations of the pattern as well yes exactly and as you said before they are well-documented so all these things are known to anyone who is looking for them exactly if we share the same vocabulary we can take shortcuts and achieve better results so that's it next question where can I find the best catalog of design patterns first of all Wikipedia is not this catalog you can find yes all the design patterns in there but the descriptions are not the best ones the best catalog that I know is the design patterns book that's right by lascivious helm Johnson and Gama it is being the Bible for design patterns yes so if you go to Wikipedia they're gonna be referencing the book if you read other books dimension design patterns they're gonna be referencing the design patterns book yes so that's the best catalog it doesn't mean you need to read that book from cover to cover and memorize every pattern no it's important that you understand the basics of the most commonly used patterns and if you have a problem that you're looking for an elegant solution you scan the book until you find a pattern that fits your problem and that's it the design patterns book is the best catalog to date of the design patterns exactly next question what is an antique pattern okay the opposite of a design pattern right an anti-pattern is a solution that the industry has deemed too risky and has found better solutions better options to a specific problem so basically it's it's an option that you should not use because there are better options to use exactly every time you use an anti-pattern we are introducing a liability to the system a norm liability widely known liability because an anti-pattern is only considered an anti-pattern if there is a better alternative if there are no alternatives and you have a bad solution well that's the solution exactly until there is a pattern that solves that in an elegant way so I have a quote here from the anti-patterns book by William J Brown an anti-pattern is a commonly occurring solution to a problem which generates decidedly negative consequences how do other documented solutions that prove to be more effective are available so when there are better alternatives but a team keep using a solution with negative consequences they are using an anti-pattern for example over using Global's just for convenience for example convenience of accessing an instance Network stack dot shared or database stack dot shared and introducing these potential concurrency problems or increasing the complexity of your system because every shared instance now needs to handle multi-threading or just making global mutable state that can make it very hard to keep data consistency even worse if this global state is mutable so you have dot shared and you can set it up just access it but set it as well yeah you end up with data races then you need to drop all your code into some kind of queue which makes things is lower and more complex then we're all coupling you don't know what the order is and what is being called when I mean it's just it's bad and it's a nutty pattern because there are better solutions proper dependency injection for example separation of concerns so that's it anti-pattern is a commonly used solution with decidedly negative results although they are better solutions around next question are all design patterns similar or are there categories of design patterns well there are design patterns they're similar to others but not every design pattern is similar right so yes there are categories of design patterns for example there are structural design patterns like the decorator pattern the adapter pattern the composite pattern or even architectural patterns like MVC mvvm and MVP there are also structural patterns they help you structure your code right and if you're interested in MVC and VM MVP we already released a podcast dedicated just to those patterns so not going to mention them today so that's it structural design patterns yes and you have also creational patterns such as the Builder pattern and factory method and the prototype which are all about how you create your objects so even singleton is a creational pattern because it's a pattern on how to create and manage the instance of your objects yes exactly and finally you have behavioral design patterns such as the saying of responsibility the observer the strategy pattern so st. Patty's Day so similar problems they are part of the same category yes in some design patterns may even cross categories but they have like a main category and all of this is documented in a design patterns book in categories it is a way of helping us organize the knowledge do you need to know every category by heart you need to know that the single tome is the creation or design pattern no you can just look it up if you need to that information so if you're trying to solve a problem related to creating Stan shading your object graph you can consult the creation of design patterns but that's it you don't need to memorize everything okay so I believe the next questions are related to specific design patterns so let's dive right in what is the adapter design pattern so the adapter design pattern is a structural design pattern that allows you to adapt the interface of a component to an interface that a client expects without changing that component let's say a client once you make a request to another component but that component doesn't have the interface the client once you don't want to change the client you don't want to change the components as well so you create an adapter in the middle to translate that communication to adapt that communication so the adapter needs to know how to make the request write translate to the clients request to the component and also translate back the result to what the client once that is correct I have found out that a very simple way to think about these things is with plugs and chargers and electricity for instance you have a UK charger for your MacBook you travel to Greece here we have EU plugs you can't plug your charger in the EU plug so what do you need you need an adapter exactly I have an adapter here they can convert any plug to any plug this is a very valuable tool exactly so the client in this case is your machine that you want to charge that's it so you need this adapter to convert the plug so you can charge the client the machine that's it basically everyone is doing their job but there is an incompatibility when you connect them so you want to remove the e compatibility and how do you do that create an adapter exactly here we can follow the same principle in software so I quote here again from Erica Evans in the domain-driven design book an adapter is a wrapper that allows a client to use a different protocol then that understood by the implementer of the behavior when a client sends a message to an adapter it is converted to a semantically equivalent message and sent on to the adoptee the response is converted and passed back that's it so that's it we didn't have a matching interfaces you put an adapter in a video keyword is convert here you just need to convert what the client expects what the server provides that's it so you use an adapter when you want to use a component but it doesn't expose the interface you want for example imagine you have a tableview controller that expects you receive an array of view models to render on the screen but the service providing the data returns a dictionary right so here you have clearly an incompatibility between these two data structures yes the view controller expects an array but the service provides a dictionary yes so you either convert the dictionary to an array of your models in the table view controller or you make the service convert that data into view models before returning it but if you do so either the table view controller will be coupled with the service or the service will be coupled with the view models and usually even services they are not coupled with the UI with the presentation later yes usually yes and you also don't want your view controllers coupled with a service so the solution is to put an adapter in between them the adapter that will convert the request from the tape of your controller to the service and when you get a response back from the service it's going to convert it to what the table view controller expects and that's it then the table for controller and the servers are much simpler maintainable decoupled reusable they are both replaceable and easier to test in isolation the equivalent will be to buy a new macbook in every new country you're going because of the incompatibility with a charger so you don't want that right you just want to buy well yeah good for you if you do what you want is just a small adapter that is gonna make your macbook charge and you can use it with a minimum cost that's it the adapter should be small not a lot of logic just converting the messaging next question what is the composite design pattern so the composite design pattern is also a structural design pattern it's related to how you structure your components so the composite allows you to compose objects through a unified interface so clients can treat the whole composite as one even though behind the scenes you may have a bunch of objects collaborating exactly so the composite butter makes heavy use of polymorphism which allows you basically to create these tree-like structures which with each node having the same interface yes because the composite shares the same interface as the objects it composes which means you can compose composites as well and create a tree structure of your object graph exactly and if you do so this thing can scale infinitely right because you never know like you can have a compose for a reference which can have another composite for a reference and this thing can grow infinitely exactly just like the adapter pattern the composite pattern allows you to create open closed systems so you can add new features without changing clients without changing code you just compose your system differently to get different behaviors for example imagine you want to load some data from a remote source but if you fails we want to show some cached version of the data and fetching data from remote can fail for multiple reasons for example you may have no network connectivity right but you cannot check for network connectivity before performing a request it's not reliable the only reliable way to know if you have connectivity with the server or not is to actually perform the request and check if you go to connectivity ever back if you check if you have connectivity before making a request Apple documentation they say don't do that yeah they say don't it's not reliable the only reliable way is to perform the request and check the result if you block a request because you think there's no internet connection it might be blocking the client from actually making the request so this logic of trying to load from remote if the request fails then look at the cache can be implemented as a composite so instead of having if-else everywhere in your code base you can create a composite that starts with a primary data source that can be the remote in a fallback data source that can be the cache that's it so it's gonna try to fetch it from the primary source if you fails it's gonna load it from the cache you can just compose this into the composite and pass through the clients the clients don't need to know about the remote clients don't need to know about the cache the Kleins no need to know about the composite they only talk to the polymorphic interface they hides all those details the same polymorphic interface that the composite the remote data source in the cache data source share which could be a simple function load can even go one step further and scale your composition by providing another composite for the fallback strategy when you're loading from the cache you can say okay now I'm loading from the caster's the fallback but now I have a new strategy so first I want to check if I have an in-memory cache for example before I hit the store the persistent store right so you're composing composite you're composing composites and that's that's it what we said in the beginning that of this question that this thing can scale infinitely you can you can compose other composites infinitely that's it you just added a new feature this in-memory cache look up before making a file system request which can be slow and it didn't have to change any other part of your system just the composition just the composition route thus you have an open closed system yes you can add this new behavior the in-memory caching without changing any of your components you don't need to change the composite you don't need to change the remote data source you don't need to change the persistent cache you don't need to change the clients you just add a new behavior getting injected in a composition root that's it total modularity total freedom that's it that's the composite pattern next question what is the decorator design pattern so the decorator design pattern is also a structural design pattern and it offers a way of adding behavior to a component without changing that component so you are extending a specific object not the type of that object this is very important you're decorating an instance not the class exactly right because then you would extend the whole class the whole type know here we're talking about one instance exactly because if you change your class implementation every instance is gonna get this new behavior but if you decorate you decorate a specific instance and it changed the behavior or you add behavior to debt instance only without altering the whole class it's a very powerful concept because imagine if you didn't do that and you wanted to add some logic in the whole time all the if statements and the extra state that you might have there or sub classing for you know when you shouldn't be supposed to subclass in the first place so the Creator pattern just gives you tremendous flexibility and freedom for basically just that one instance and this is possible because the creator's share the same interface with the object decorate or the ducati right for example the decorator pattern is very handy for cross-cutting concerns like logging debugging profiling analytics tracking security authentication threading for example when trying to profile how long an operation takes or you want to track some user actions like every time you press a button you want to track that action all those cross-cutting concerns can be moved to decorators does it separate the cross-cutting concern from your application logic that's it and that should be your signal by the way if you see a class violating the sing responsibility principle then perhaps you can use the decorator pattern and extract any added logic or users of single tones as you said tracking logging all these things are usually done with Singleton's but why would you pollute your component with these things when you can clearly isolate them in just one instance of this type that you're working with and that's the again that's the power of the decorator pattern it allows you to reinforce the single possibility principle or maintain open closed nature in your components that's it not example it's very common to sink bases defensively dispatching to the main queue before performing some UI update yes because it can only perform UI updates in the main thread yes and since you don't know if your service would be returning things in the main thread just offensively always dispatch a synchronous calls in the main thread yes the problem is that this is gonna make your whole UI code ugly rot in those dispatch kills you can introduce bugs that is very hard to trace you can hold your view in memory for longer than it should it might be dispatching on the main queue even though it's already in the main queue so it's doing work it doesn't need to make the user experience worse so instead you can move all dispatch to a centralized place in the composition route yes by using liquor ATIS exactly and this is this is a prime example of what it means to make a change to a single instance rather than a whole class of objects the whole time right because imagine you you have a tableview controller and you are fetching something and you want to update in the you want to dispatch in the main queue now that's that's dispatching logic based on on your on the server right so why would you have that in a UI that supposedly is reusable and perhaps it doesn't need that so what you can do is whenever you need that you can wrap it in a decorator and just use it for the case at hand that's it so you move to dispatch to a component that knows you need to dispatch that's it and that's not in the network client know ideally move it to a decorator in the composition route that's all your components are much more testable as well does it need to be concerned about threading when you're testing are you why you're concerned about threading when you're testing threading code in the composition route so next question what is the facade design pattern okay the facade is a structural design pattern that provides a unified interface to a set of interfaces in a subsystem so when you have a system there is quite complex to interact with yes can create a facade to simplify the communication that's it for example a system that exposes too many interfaces or components that need to work in a very specific way for things to work correctly if you move this responsibly to the clients most likely they're gonna get this wrong and get bad results does you move all this complexity to a simple interface where the clients can perform simple operations and get what they want so you hide the complexity of a complex system in a simple unified interface that's it the key word here is hide you're hiding all the complex things that your client does not need your client will need just probably a single interface so you create this abstraction in a sense with a single interface all the complexity from your clients for example if you ever interacted with core data you know how hard it is to instantiate the core data stack correctly with the right hierarchy passing the right migration details manage data model and etc it's a complex stack to instantiate and interact with thus Apple provides us a bunch of facades to deal with that complexity for example nowadays we have the NS persistent container for instantiating a pretty default stack for core data which solve is probably 90% of the use cases you can still go back to the old ways of the stash ad all the object graph yourself and creating the context hierarchy as well you can still do that but you have this facade that drastically simplifies the instantiation and management of their core data stack which means most apps will get a correct behavior the behavior they expect because previously when you had to create the whole stack by hand a lot of apps would end up with inconsistent data just because they were doing something wrong in the composition in the setup there are more api's exposed thus there is a higher probability of using wrong those api's yeah so the facade solves it partially because you don't have all this API is to interact with you just have one API or two depending the case yeah depending on the use case you literally just pass your data model name and that's it you pass a string and you're done yes so a facade is a simplified interface to interact with a complex system another example in core data is the persistence coordinator so from the Apple Doc's the persistent store coordinator is designed to present a facade to the managed object context such that group of persistent stores appears as an aggregate store that's it very how it so next question what is the strategy design pattern the strategy design pattern is a behavioral design bother and it defines a family of algorithms encapsulating each one of them and using them interchangeably so he hides the specific algorithms from the clients yes exactly so let's say you have multiple ways of performing an operation and depending on some state of some data some conditions in which you use one or the other but I don't want to move this with most ability to the client they want the client choosing which algorithm to use yes thus you use this strategy design pattern to decouple the client from a family of strategies or algorithms as the composite design pattern it relies heavily in polymorphism and that's the basic mechanism for encapsulating these algorithms or strategies into single components and using them interchangeably later on exactly so you can reuse the strategies in different clients instead of duplicating a lot of eath else or duplicating the conditions that's gonna make you choose one over written over the other yes for example let's say you want to fetch some data in your iOS app but depending on the connectivity state for example if it's Wi-Fi or 4G we want to load the data from different sources or from different endpoints because if you are on Wi-Fi you're happy to download high quality images where if you are on 4G you want lower quality images to save data instead of having this if else logic in the clients that's going to make the request you create a polymorphic interface that your strategy is going to implement and then you can have a Wi-Fi strategy a 4G strategy and this is going to be decided in this strategy layer not by the client right does you decouple this decision from the client we simplifies the client and allows you to add new strategies in the future for example on 3G strategy of 5g strategy and etc without changing the client or the polymorphous interface because the interface the client is going to depend on should not leak details about specific or concrete strategies so you can also use this latitude pattern to decide between algorithms depending on low battery or if the battery is fully charged if you have space on disk or not or if you want to perform different kind of logic depending on some customer settings like if the user requests you to save data you can use a strategy there's going to request less data less often and so on you know decouple your application from those device details like battery state an activity state does your code is much cleaner easier to test yes exactly your code is conforming to the solar principles you create single sponsibility self-contained components your clients without having this knowledge of the whatever strategy whatever algorithm whatever logic you have you want to encapsulate and not just that but you can extend that logic you can add more and more and more in the future without having to change the code that you have already in your clients so it's it's the decoupling there is something special indeed because it allows you to branch out in many different logic forms basically your application and you can just add the new branch of logic every single time rather than going back and changing stuff so I mean just all the cases that you mentioned are everyday use cases if you want to check the battery if you want to check the connectivity signal all these things now imagine how would you do these things if you weren't to use the strategy pattern or a similar butter if-else everywhere if exactly like we're talking about thousands of lines troubling your view controllers and with evils and flags boolean's properties state yeah it's gonna make your cold very hard to test as well because you need to set the system in a specific state that's it simulates that state and the UI level yes at the UI level or at any other level there is not supposed to do this kind of logic so the strategy pattern makes your system open closed yes it's open for extension and closed for modification which means you can add new behavior or even remove behavior without having to change your system it just composed it differently that's it that's it next question what is the chain of responsibility design pattern so the chain of responsibility is a behavioral design pattern which avoids coupling between the sender of a request and the receiver of a request so the sender and the handler the sender and the handler that's correct by providing more than one handlers right but the client that makes the request don't know that there's more than one handler that's that's exactly right so it gives a chance for more than one handler to handle that request that's it and the handlers are decoupled from the requesters and vice versa of course so it creates a chain of objects and why is it called a chain that's very similar to a linked list yes exactly because a handler has a reference to the next handler and the next handler has a reference only to the next handler into the next handle into the next handler that's it so if anyone in the responder chain cannot handle the request it asks the next responder to handle it and if the other responder cannot handle it it keeps asking down the chain until you find a responder that can handle the request and then it stops yes and as iris developers we are familiar with this concept even if we do know that it's the chain of responsibility pattern or not yes with you UI responder so the UI responder is an implementation of the chamber's possibility design pattern exactly we have a hierarchy of components from UI application to UI view to UI view controller all implementing the you are responder type for example iOS apps receives and handles touch events or motion events using a chain of responder objects in a responder object is any instance of subclasses of the UI responder abstract class as you said common subclasses or you are responder UI view which includes UI window you have UI view controllers UI application the application delegate etc that's it so when your app receives touch or a motion event it's gonna delegate that to the first responder yes and if you cannot handle it it's going to ask the next responder and if this responder cannot handle the request is gonna ask the next one and the next one at the next one until it finds someone that can handle the event so that's the chain responsibility design pattern and how its implemented in iOS with UI kit that's it next what is the observer design pattern the observer pattern is a behavioral design pattern defining a one-to-many dependency between objects where one object changes its state then all other dependency objects are notified of this change right so you have an object that can be observed and you have observers that can subscribe to state changes yes keyword subscribe that's exactly right they are saying basically I want to listen for changes or I want to be notified of any changes on specific properties of a specific object and that's a very popular design pattern in iOS as well exactly for a long time we have for example key value observing or kvo where you can subscribe or observe state changes for properties of objects so at the time the property or that state changes you can receive a notification and as I said it's a one-to-many relationship we can have many observers for the same observable object yes and more recently with combined we also have other implementations of the observer pattern there is even an observable object protocol right for observing changes in an object so in Swift ey when you bind it with an observable object every time there's a change in the object the view will remain there itself for example so that's it other implementations you can also find with rx Swift and other popular frameworks where you can observe state changes and react to it yes that's that's exactly right so next question what is the singleton design pattern the most popular one probably yes and the singleton design pattern is a creational design pattern that ensures a class has only a single instance and it provides a point of access to that instance right in that shared instance should not be accessed from anywhere in your app if you do that's an anti-pattern ideally you should inject instances or dependencies into your components instead of accessing global instances directly thus you don't couple your system with a specific instance you can replace it and make your system more open closed so there's nothing wrong with a single toe pattern but any of those patterns if you abuse it it's gonna give you negative returns right so that's it when should you use the single toe pattern when you want to guarantee there's only one instance not for convenience of accessing that instance yes and as a framework creator like apple with your accession you can give a convenience shared instance that your clients can use out of the box but that doesn't mean that as a consumer of the API should access the share instance from anywhere in your app you can also inject that instance into your components because it's a dependency and dependency should be explicit yes to improve maintainability to make your system open closed and easier should test in maintain if you want to know more about dependencies you should check out our dependency injection podcast that's it in the DI podcast we type deep into your dependency injection and patterns you can apply to manage your dependencies effectively next question what is the Builder pattern another popular pattern in iOS right and the Builder design pattern is another creational design pattern it creates or builds things right exactly allowing you to create complex components but by hiding all the complexity right so when you have a component that it's hard to create mm-hmm you can use the Builder pattern to make it easier for clients to create that component that's it for example creating a URL it's quite complex there's a bunch of rules in the URL standards right and complying to all those rules it's very hard to do there's encoding rules length rules protocols domains pass and etc so to guarantee that you create a URL correctly with all the properties you want you can use URL components which is an implementation of the Builder pattern for creating URLs yes so we instantiate our URL component and you can set query parameters domains protocols and ask the URL components to create a URL for you so then you are only concerned with the data you want to pass to create the URL yes in the URL components the builder hides all the complexity of validating and generating standardized URL that's it and you can do this step by step first set the query parameters then you set the protocol that's it so gives you a step by step way it simplifies the process of creating complex components next question should I learn all design patterns by heart should I know all of them should i memorize all design patterns I think we established that already no certainly you don't need to memorize the whole catalogue at the same time you should be familiar with some of the most important structural or behavioral so you don't need to memorize everything but at least the main ones understand them so when you are solving a problem get the catalog in check if any of those patterns can help you solve your problems yes exactly and as you progress in your career and you're gonna be exposed to more and more problems you're just gonna stumble upon more and more design patterns so that's it for today you want to learn more go to academy dot essential developer.com let us know your thoughts your feedback and your comments and we'll see you again next time bye y'all see ya [Music]
Info
Channel: Essential Developer
Views: 2,889
Rating: undefined out of 5
Keywords: ios, swift, ios development, ios app development, xcode, tdd, architecture, advanced ios development, iphone, ipad, advanced swift, clean code, unit testing, testing, solid principles, uikit, ios testing, advanced ios, advanced testing, mvc, design patterns, how to, how to become, coaching, senior ios developer, iOS lead essentials, podcast, coredata, mvvm, mvp, viper, clean iOS architecture, singleton, observer, decorator, adapter, builder, chain of responsibility, composite, design patterns ios
Id: dyjWREvBBj4
Channel Id: undefined
Length: 43min 22sec (2602 seconds)
Published: Thu Nov 28 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.