2.3 Remove Duplication
In the previous lesson, we noticed a common code smell in our app: duplication. Duplication can be one of the most dangerous code smells as it increases your chances of making mistakes in your code. In Swift there are a number of ways to refactor to remove duplication—in this lesson we will be using the Protocol Extension feature.
1.Introduction2 lessons, 05:00
2.Building the Foundation3 lessons, 27:38
3.Creating the User Interface7 lessons, 1:06:19
4.Application Logic6 lessons, 37:10
5.Conclusion1 lesson, 00:38
2.3 Remove Duplication
In the previous lesson we started to build out some of our models and we created a reminder and a stage. And one thing that we introduced was a bit of a problem and I want to spend a moment fixing that problem right now just to show you. That there's usually no better time than the present when it comes to coding mistakes and things that are sometimes considered code smells, and there's really no better time to fix those things than as soon as possible. So the code smell that I introduced in the previous lesson, is that of duplication. So we literally cut and copied and pasted this duration property from Reminder, and stuck it over in Stage. Because we felt like the concept of translating an integer representation of seconds into a more human readable string property, or string value was going to be very beneficial but we didn't do it in a very. Reasonable way, or in a very easily maintainable way, cuz the problem now is that if I ever want to change the representation, I'm gonna have to change it in two places. And heaven forbid I copy this in other places and I have more instances of this duplication. And just a lot of problems can come from that. Now within Swift there's several different ways that we can solve this. We can use base classes. We could use extensions. We could use protocols in combinations thereof. And so we're gonna take a couple of those, and I'm gonna show you a nifty little trick to be able to get around this concept of duplication. All right, so really what I want do is, I want to take this block of code, even this property is fine, too and put it somewhere else so that it's just in one place and I can reuse for both Reminder and for Stage. So one of the interesting ways that we can do that, is by introducing a protocol. So, let's go ahead and come into RemindMe. And let's just create a new group. And we'll just call this protocols. Now, you don't have to break things up this way, but I think it definitely helps when you're maintaining this code or maybe handing off to someone else, so that they know where to look and so things were kind of logically place in certain places. All right, so let's create a protocol. We're gonna create New file, and this is gonna be a Swift file we'll select next and now we need a name. A name for, in this case you could call just about anything you want. But what is this going to do, well. What we want to do in, what's the common piece of functionality that lives in both the reminder and the stage that we want to be dealing with when it comes to duration. The answer to that is the seconds. So we'll just call this something like seconds container, maybe. You could change that if you want, but I think that's a reasonable name. So now, we're going to create this protocol in here, and this protocol we'll just call seconds container. And the seconds container is going to have a single property, and it's going to be that seconds that we talked about. So we'll say var seconds and this is going to be an integer and we're gonna say that this is going to define a get. Now, we can't have a get and a sent in anything that's going to abide by this protocol or implement this protocol, that's fine. But we at least need to have a get because we need both implementations. The implementation of this duration however we decide to do it, needs access to the seconds so that's how we're gonna design this. So let's come over here to reminder, and we're going to put a colon after the class name, and we're gonna say that this is a seconds container. And we are in compliance because we do have a seconds variable That is an integer, and this is providing a get. So everything continues to work, I can go ahead and build that, and it will build. So, that's good. That's the reminder side of things. Now, on the stage side of things, we'll do the same thing. We'll say that this is a seconds container. All right, that's good. This should work as well because we have a seconds property in here. Now the seconds property by the way we defined it has both a getter and a setter by default which is fine because within our protocol we're saying we need to have a getter. Our seconds integer or variable property here needs to have a getter and we do and that's fine. We have a setter on it but that's really doesn't really make any difference when it comes to our protocol. Okay, so now we have two classes that both Adhere to the seconds container protocol well no big deal you say why does that make any difference how is that going to help us? Well the solution that we are going to use to share this code across these two classes is using something called a protocol extension so let's go ahead into RemindMe here and let's create another new group, and we'll just call this, Extensions. And the idea behind an extension here, is nothing more than, we are going to provide additional functionality on a particular type, that's all we're trying to say. All right, so we'll set, next, here and we're going to. Call this a SecondsContainerExtension or extensions, nah extension I think is fine. We'll create that and now in order to create an extension, we simply say extension and then we give the name of the type that we want to extend onto. So, in this case we want to extend the seconds container and what do we want to do. So within an extension you can provide properties. You can provide methods and what's going to happen then is, whatever type you're creating an extension for will be given that property or that method anywhere in your code, so that's pretty handy. So now what I can do, is I can come into either one Reminder, or Stage, and I'm just gonna grab this duration here, I'll copy this. We'll come over here and we'll paste this in. So now we're saying we're going to define an extension on the seconds container that is going to be called duration. It's going to return an optional string, and it's going to do that formatting that we talked about getting access to seconds, and the reason that we have access to the seconds property is because we are extending SecondsContainer, which has our seconds properties. So that's how all these things kinda fit together. So let's come into reminder. And we're going to get rid of this all together. We can save that. And then we can go ahead and get rid of this duration all together and save. Let's go ahead and build. So now what we've effectively done is we have taken that duplication. And we have moved it off into a single place into an extension that we now have access to. Anywhere that we might need that duration for any sort of class that implements or that adheres to the seconds container protocol.