Dave recently used Golang for a project he was working on, and today he shares his experience of interfaces and design patterns in the language. We kick off the show by talking about the Gang of Four, where Mike reveals what we have long suspected – he’s not a real developer after all! We then talk about how Go is different from other languages in that you have to explicitly define the interface and then you have a file with an interface in it. This means that when you write the code that implements the interface, you don’t explicitly say what it’s doing. It's all a big secret! We also talk about why, with Go, it’s not that important to be super strict because you can use the interface to define what you want to implement from that specific interface. Along with this, we also get stuck into patterns, like strategy, which is super helpful for testing, and, factory which comes in handy when you want to find the object to make the code run. Interfaces and design patterns are things that you will have to use, especially when dealing with strictly typed languages, like Golang, so tune in to hear more!
Key Points From This Episode:
- Insights into Design Patterns (Gang of Four) and how the book is helpful.
- Mike’s experience of design patterns in Java: Code becoming spaghetti.
- Learn about how interfaces are defined in Go versus Java: Go keeps secrets!
- How Go defines the type of interface method as a strongly-typed language.
- Find out more about strategy, a design pattern that’s helpful for testing.
- Factory patterns: What they are and how they make things squeaky clean.
- Learn how the decorator pattern helps in Golang in the absence of inheritance.
- Why, in Golang, you don’t have to change the code to change the behavior.
Transcript for Episode 151. Interfaces + Design Patterns
[0:00:01.9] MN: Hello and welcome to The Rabbit Hole, the definitive developer’s podcast. Live, from the boogie down Bronx. I’m your host, Michael Nunez. Our co-host today.
[0:00:09.0] DA: Dave Anderson in dirty Jers.
[0:00:11.0] MN: Oh, yeah. Today, we’ll be talking about interfaces and design patterns. Recently, we spoke about programming language Golang, that Dave was really excited to work in and have gone through a lot of exercises and design patterns and interfaces. We're going to talk about that today and Dave is going to tell us his experience using interfaces and design patterns in Go. I imagine it's probably one of those languages that is strictly enforced uses of design patterns within the programming languages. Is that safe to say?
[0:00:39.2] DA: I mean, I don't think you need to use design patterns. You can totally just write everything in one method and then call it a day. You could do that.
[0:00:48.2] MN: The bolts of my bag just started to – Oh, God. No. Don’t do that.
[0:00:51.3] DA: I mean, you can use two objects, if you want to use two objects. That's fine too. I won’t judge you.
[0:00:57.8] MN: Other people may judge you. That's the problem.
[0:01:01.7] DA: Yeah. I mean, design patterns, I remember coming to a topic early on when I was getting into programming. There's that really heavy Gang of Four, gang of five?
[0:01:15.1] MN: No, it was a Gang of Four. I mean, I think there is a gang of five somewhere, but that's probably a gang in the Bronx. We got one –
[0:01:19.3] DA: It’s in the Bronx. Okay, you got to watch out for them. The gang of five will cut you.
[0:01:24.5] MN: Yeah, you got to watch out with the gang of five. The Gang of Four is design patterns. The gang of five –
[0:01:28.7] DA: Good advice. Got to get it right off, I wonder.
[0:01:33.0] MN: Yeah. It’s the Gang of Four.
[0:01:36.3] DA: Yeah. You come across that, I think – so you have a copy of that somewhere?
[0:01:40.2] MN: I may have read the PDF. I don't think I have a copy. I'm not a real programmer. I think you got me.
[0:01:46.6] DA: I mean, you got that profit budget. You have to spin that profit budget.
[0:01:49.6] MN: Yeah, I got to buy this book and reread it I mean, I read parts of it definitely on a PDF.
[0:01:55.0] DA: It makes a really good like monitor riser. It has good depth to it. Yeah, I mean, it's written in the 90s, primarily with small talk and Java. The code examples, they were hard for me to understand when I was starting out in programming. Then when you actually start working on an application like Ruby on Rails, or Django, or something like that, there's frameworks and patterns that are there. You just color in the lines all the time.
[0:02:29.4] MN: I definitely ran into all my exercises in design patterns when I was programming in Java. I see that a lot more. Java is one of those language where it's really strict to do things in design patterns, because if you are too loosey-goosey, I think your code becomes spaghetti, if that made sense to anyone out there.
[0:02:50.1] DA: Confident loose spaghetti.
[0:02:51.5] MN: Yeah, the loosey-goosey spaghetti, the spaghetts. In my time in Java interfaces are often used when you want your classes to follow a strict contract per se.
[0:03:03.9] DA: You have some set of methods that take some inputs and then always give some applet. Then my first encounter with interface was, “Okay, you have an interface for the database connection and the database connection implements these methods and theoretically, you could swap it out for some other database.” I have MySQL database, or I think at the time I had an Oracle database. They had the big money, which you put all the big money in the Oracle database.
Then one day, maybe they're like, “Wait. I don't want all the big money. I just want a MySQL or PostgresSQL SQL database, because there's my 10 users for the application. Why am I doing this?”
[0:03:40.8] MN: Why are we doing?
[0:03:44.3] DA: Like interfaces provide you that contract where you can swap something out in the future.
[0:03:47.7] MN: Yeah. I think the examples I see on the Internet when explaining what's an interface has to do with like, “Oh, if you had a shape interface that has methods called area, you can apply of square and a square will calculate the area different than say a triangle. But you can still ensure that when you call get area of something that is inherited, or as an interface of shape, then you know that you're going to get an area of that shape, whatever shape that is. It’s the idea.”
[0:04:18.5] DA: Yeah. Yeah. Yeah, that one's also used for inheritance too, but the same concept applies for interfaces. The reason why that this came up is because with Go, you don't actually have inheritance. You only have interfaces. You got to think about a lot. You have to use composition and interfaces in order to do the stuff you want to do.
[0:04:41.0] MN: Right, because what is a composition over inheritance? That's the thing.
[0:04:45.7] DA: Yeah. That's what we like, I guess.
[0:04:47.9] MN: You don’t want to couple yourself with the inheritance pattern.
[0:04:52.0] DA: Yeah, or hiding complexity and things like that. It's interesting how interfaces are differently implemented in Go or Java. In Java, you explicitly define the interface, so you say “This is an interface and these are the methods that are on it.” Then when you actually write something that implements those interfaces you say, “This class implements shape, then you write the shape method.”
In Go, it's a little different because you explicitly define the interface, so you have a file with an interface in it. Then when you write the code that implements the interface, you don't say that you're implementing the interface. It's a secret. You don't actually tell anyone.
[0:05:36.8] MN: Oh, no.
[0:05:38.7] DA: The compiler knows. It's an interesting combination between how interfaces happen in Python, where it's like a duck interface. It walks like a duck and it quacks like a duck, then –
[0:05:51.6] MN: It's probably a duck.
[0:05:52.4] DA: Probably a duck. Yeah. There's a lot of flexibility with that.
[0:05:56.7] MN: In Ruby, there isn't a keyword that deals with interfaces. Is that something that doesn't happen in Go as well, but you still follow the flow of an interface?
[0:06:08.5] DA: Go is a strongly typed language, so you will define the type that says what the interface methods are. You can use that on an argument for a function that you have. Say if you have a shape stacker and it takes a list of shapes that it’s going to work with, it doesn't have to take a list of circles or a list of squares, it'll take a list of shapes and it will only care about stacking up the areas that they have.
[0:06:34.8] MN: Oh, I see. Oh, that's interesting.
[0:06:37.3] DA: We’ll know that they have the area method and they can work with that. Explicitly defining the interface, gives you a good amount of however – when you put a name on something, then that really helps you see the pattern, or think about the pattern how it's used.
[0:06:53.5] MN: Yes. Naming things are important.
[0:06:57.9] DA: Python has just actually added something in Python 3.8, where they are slowly rolling out more features in the typing module and they have a thing called protocols, which is basically the same thing as the interface in Golang, where you can now give it a name and tell it what the structure of it is.
[0:07:17.1] MN: Oh, wow. Okay.
[0:07:18.8] DA: That's a completely different story.
[0:07:20.4] MN: Python 3.8. Look out for those protocols.
Obviously, you use a lot of interfaces in Go that as you mentioned before, will take a particular interface for a given class and it doesn't have to be super strict, because you can use the interface to define the things that you want to implement from that interface.
But I imagine design patterns is probably something you have to visit yet again and go. I think design patterns are the more strict the language is, the more likely you'll be dealing with design patterns. Is that safe to say? Because I imagine you probably ran through some in Go that was very important, or rather good to have, so that the code looks more cleaner than it could look like if you didn't use design patterns?
[0:08:02.6] DA: Yeah. I guess particularly with testing, there's one design pattern that we’re already talking about before. There's a design pattern called strategy, where if you have two objects and both of those objects implement the same methods, because they have the same interface, so the same inputs, the same outputs, but the implementation is different, then you can swap them in and out and not worry about it. That's super helpful for testing. If you have something that's going to call out to a database, or to the network, you don't want to do that maybe in your test. You just want to have it happen in a fake way.
[0:08:38.5] MN: Right. Using a strategy pattern can definitely help avoid having to go through much farther steps to the test where you can actually unit test that particular part of your code.
[0:08:48.8] DA: Right. If you don't have that forced on you like in Python, then maybe you'll reach for something like patching methods, or monkey patching things so that they behave differently.
[0:08:59.9] MN: Oh, man. Can have meta programming stuff that you do in Ruby, that's just crazy.
[0:09:05.7] DA: Right. I mean, you can do it, but you don't actually need to do it. You can use a design pattern, but maybe it's just easier for you to do some crazy meta thing.
[0:09:16.4] MN: One of the design patterns that I often see in different projects is the factory pattern. Besides the strategy as we've mentioned before, with factory pattern you're able to take an object and apply it different configurations of object depending on the input. If you're working on a solid Java project and chances are there will be factory patterns riddled all over it to make things look as clean as possible.
[0:09:41.7] DA: It’s just so clean.
[0:09:42.6] MN: Yeah. No, I mean, it just separates all the logic of what it needs to do in the factory and you just want the object to return exactly what it is that you need, but all the logic exists in the factory, which is nice. One of the design patterns that I see often in Java projects is definitely the factory pattern. I don't know if you had to deal with that in your Go project.
[0:10:04.0] DA: Oh, totally. We defined some factories. Java, you got to have factories and you got to have abstract factories too, factories for your factories.
[0:10:12.7] MN: Exactly. The bread and butter of design patterns right here is the factory pattern. Essentially, you give it some input. Suppose you had certain means of transport, depending on whether you're transporting goods via a truck, or a ship, you can still create those transports. Depending on your vehicle, it'll be treated differently. You just give it these different inputs and they’ll come back with the object necessary for you to run whatever method necessary to complete the code. Depending on what it is that you give it, it goes through this factory to figure out exactly what it needs to return and then you'll be able to call the methods necessary.
[0:10:51.1] DA: Right. In the simplest way, it could just be configuring an object in a different way based upon the inputs, like the same objects in different ways, or composing that object with different other objects. Or you could pair it with the strategy pattern, get some peanut butter for your jelly.
[0:11:10.0] MN: Oh, yeah. The best sandwich ever.
[0:11:14.5] DA: I think that the example of different modes of transport is a pretty good one, because maybe you have a cargo transport factory and you could get a vehicle that can load cargo and you can load cargo in the 18-wheeler, or a plane, or a ship, or on your bike, the implementation of how you do it is different. The basic idea is the same.
Yeah, another thing with interfaces and Go that's pretty important to know, like I mentioned before is that you don't have inheritance, that they just don't allow you to do it. You need to use composition, which people generally say is the way to go. You probably should just use composition, instead of inheritance.
[0:12:04.7] MN: I think the idea, that's definitely an opinion that someone had when creating Golang and was like, “We're doing it this way.”
[0:12:09.6] DA: Oh, yeah. Go is a series of opinions that are just baked into the compiler. You can't get around them.
[0:12:18.7] MN: It's a good opinion. I definitely respect that.
[0:12:23.5] DA: One of the design patterns is going to help you when you're doing composition, instead of inheritance is decorator. That's basically where you have something that influence an interface. It has something, like a collaborator that implements that interface that it takes as a argument when you're building it. It will defer to its collaborator, but also add some more behavior around that.
A pretty good example of this pattern is in the Go standard library, you have a pretty great HTTP library. This HTTP library has a function like, do for executing a request. It has all these different parameters for timeouts and things like that. If you drill into the code, there's different levels of collaborators and this. There's a very cool thing at the very bottom that does the request. It’s end-stage of your requests. Above that, there may be a timeout request that its job is just to pay attention to the time, send their requests. Then if too much time has passed, cancel the requests and go out. But it doesn't know how to send a request itself, which is it has something that knows how to send the request.
[0:13:42.3] MN: I see.
[0:13:43.2] DA: They have the same interface for doing it.
[0:13:45.4] MN: Which is the do method.
[0:13:47.2] DA: Something like that. Yeah.
[0:13:48.9] MN: Yeah. Oh, that’s awesome.
[0:13:50.1] DA: Yeah. That way of structuring your code, it can be pretty clean because you break up the functionality into really easily testable chunks, but you also get to a place where your code is really solid. The classic –
[0:14:06.6] MN: The acronym, not good piece, solid piece. More like the solid piece.
[0:14:11.9] DA: I think that's what they say, but –
[0:14:15.3] MN: I think this is probably where it derived from. But it is an acronym, right?
[0:14:19.0] DA: Oh, your code isn't solid? My code’s solid.
[0:14:21.1] MN: Yeah, my code is solid, bro. My code is always solid, bro. Even if it doesn't follow any of the SOLID, but trust bro, it’s solid.
[0:14:28.6] DA: The important one there is open/closed, where it's open for extension, but closed for modification, where basically you don't have to change the code in order to change the behavior of a thing. You can compose it with other things to make the behavior different in a certain situation.
[0:14:45.9] MN: The open/closed principle is I guess, in the SOLID acronym, the one that gets use the most for the decorator pattern?
[0:14:52.4] DA: Right.
[0:14:52.4] MN: Or in general.
[0:14:53.2] DA: That’s the one that is most apparent for that one, I guess.
[0:14:56.0] MN: I never forget the acronym of the SOLID principle. For anyone who has forgotten, the SOLID principle are the following; single responsibility principle, open-closed principle, Liskov Substitution Principle, the Interface Segregation Principle and the Dependency Inversion Principle. Who forgets that? Not this guy. Mm-mm. No way. Uh-uh.
[0:15:19.4] DA: Nope. There's a lot of words there.
[0:15:21.5] MN: There's a lot of words there. I think this might be a sneak peek, but we should go over each one of those SOLIDs in the future.
[0:15:27.9] DA: Sure. I think we talked about it at least one time before, but I got to check my tats.
[0:15:33.5] MN: You got to check the tats, bro. I don't know. It’s probably somewhere in the awkward space like in your back that you can't touch or see. Oh, my God. Check it out. Moving the office. I'll have that. See to turn around, because I could check. Cool, interfaces and design patterns are definitely things that you will have to use, especially when dealing with strict typed languages, definitely use them, definitely in Java as Dave has been mentioning throughout the podcast. We're using them in Go. If you have a favorite design pattern, I'd love to hear it. I’m curious to hear –
[0:16:02.0] DA: Which design pattern when you get the UML for a tattooed body?
[0:16:08.7] MN: What design pattern describes you? You won’t believe number four.
[0:16:13.7] DA: Is there a BuzzFeed quiz for that?
[0:16:15.0] MN: We should make one. Yeah, if you have a design pattern that we may have missed, feel free to hit us up.
[0:16:22.8] DA: Also, a big thanks to a friend of the show, Connor Benham for drilling me on these design patterns.
[0:16:29.8] MN: Oh, yeah. It's like a design pattern boot camp with that guy.
[0:16:32.8] DA: Oh, yeah. That’s the strategy.
[0:16:34.8] MN: That’s a design pattern. This guy design patterns.
[0:16:39.6] DA: Well, I looked it up and there's no which design pattern are you quiz. That's something that we need to do.
[0:16:46.3] MN: Yeah, we need to build that before we release this episode, because someone else is going to do that.
[0:16:51.3] DA: So much pressure. Or we could release it and someone else could do it. Let us know if you build it.
[0:16:56.1] MN: There you go.
[END OF INTERVIEW]
[0:16:57.1] MN: Follow us now on Twitter @radiofreerabbit, so we can keep the conversation going. Like what you hear? Give us a five-star review and help developers just like you find their way into The Rabbit Hole. Never miss an episode, subscribe now however you listen to your favorite podcast. On behalf of our producer extraordinaire, William Jeffries and my amazing co-host, Dave Anderson and me, your host, Michael Nunez, thanks for listening to The Rabbit Hole.
Links and Resources:
Our seasoned cross-functional agilists work with you to develop technology, ship product and deliver value. We leverage our diverse expertise across industries and throughout the organizational growth cycle to your benefit. We bring best practices, emergent practices and creative solutions to your problems.