🎙 Develpreneur Podcast Episode

Audio + transcript

Cohesion and Coupling in Object-Oriented Programming

In this episode, we discuss the concepts of cohesion and coupling in object-oriented programming. We explore the trade-off between convenience and speed and how decoupling functionality from data can improve system design.

2021-03-13 •Season 14 • Episode 476 •Cohesion and Coupling in Object-Oriented Programming •Podcast

Summary

In this episode, we discuss the concepts of cohesion and coupling in object-oriented programming. We explore the trade-off between convenience and speed and how decoupling functionality from data can improve system design.

Detailed Notes

In this episode, we delve into the concepts of cohesion and coupling in object-oriented programming. Cohesion refers to the extent to which a class contains related methods and data, while coupling refers to the extent to which classes are dependent on each other. We explore the trade-off between convenience and speed, and how decoupling functionality from data can improve system design. The concept of flyweights is introduced as a way to decouple functionality from data and reuse it as needed. We also discuss the importance of considering the trade-off between convenience and speed when designing object-oriented systems.

Highlights

  • The concept of cohesion and coupling in object-oriented programming.
  • Big objects versus small objects and the trade-off between convenience and speed.
  • The idea of decoupling functionality from data and reusing it as needed.
  • The importance of considering the trade-off between convenience and speed when designing object-oriented systems.
  • The concept of flyweights and how they can be used to decouple functionality from data.

Key Takeaways

  • Cohesion and coupling are key concepts in object-oriented programming.
  • Decoupling functionality from data can improve system design and reduce complexity.
  • The trade-off between convenience and speed is a critical consideration in object-oriented system design.
  • Flyweights can be used to decouple functionality from data and reuse it as needed.
  • System design should balance the need for convenience with the need for speed.

Practical Lessons

  • Design object-oriented systems with decoupling in mind.
  • Consider the trade-off between convenience and speed when designing object-oriented systems.
  • Use flyweights to decouple functionality from data and reuse it as needed.

Strong Lines

  • Decoupling functionality from data can improve system design and reduce complexity.
  • The trade-off between convenience and speed is a critical consideration in object-oriented system design.
  • Flyweights can be used to decouple functionality from data and reuse it as needed.

Blog Post Angles

  • How to design object-oriented systems with decoupling in mind.
  • The importance of considering the trade-off between convenience and speed in object-oriented system design.
  • Using flyweights to decouple functionality from data and reuse it as needed.

Keywords

  • Cohesion and coupling
  • Object-oriented programming
  • Decoupling functionality from data
  • Flyweights
  • Convenience and speed
Transcript Text
This is Building Better Developers, the Develop-a-Noor podcast. We will accomplish our goals through sharing experience, improving tech skills, increasing business knowledge, and embracing life. Let's dive into the next episode. Well, hello and welcome back. We are continuing our season when we're looking at practical object-oriented programming. In this episode, we are going to spend a little time on cohesion and coupling. We have mentioned these before, these options, and essentially what it boils down to is big objects versus small objects. We talked about this when we talked about design and the idea of bricks versus sand, but this is a little less extreme. This is a little more in the middle. It's one of those things that really makes sense and also does not have to be consistent 100% across your system. When you think about these two approaches, it basically boils down to you can either look at functionality for a class as something that is inherent to the class. It's an attribute. When you think of the has a type of discussion that we talked about where it was the idea of maybe a very simple thing like a value versus something more complex like another class that would be what a class has, it starts you down that road basically. The thing being, do we have, for example, just let's go back to that color because it's nice and simple. Do we have a color that's just a string or do we have a color and we can do manipulations on it? Maybe there's shading, light and dark and some sort of trans migration from one color to another. Those kinds of functions, do they exist as part of the color? Is there a color class or are those part of the, we'll call it like the owning class? If it's a graphical widget, does the widget have a method that we call that tells it to darken itself and does it handle it within the widget class or does the widget essentially in that case make a call to the color class that darkens that color? If it's within the class, that would be cohesion. It's bigger objects. They have more functionality built within the classes. If it's coupling, then we're building smaller classes and we are linking them together so that there is a way to work together with these smaller blocks as opposed to single larger blocks. Now what we run into as far as design is concerned when we're talking about these approaches really boils down to the idea that as we decouple things, as we make it, when it's cohesive, let's step back a second. In a cohesive class, in a larger class that has self-contained methods, the class data and the method are essentially one in the same. They're right next to each other. You don't have to pass data around. You set the values in your class. You call methods. Those methods have direct access to the values. When you decouple that functionality, then you run into the situation where you have to pass data around. That in itself is an interesting little problem to solve or concept to design around because we run into things like what data do we pass? Do we keep it small? Do we have specific values that we pass? Or do we maybe pass an entire class? That again, passing the entire class can be easy and allow you to do a lot of stuff as far as extending that class and all kinds of things related to the object-orientedness of that data that we're passing. You can pass just a pointer and then put a whole lot of stuff in the data and do things with it. Of course, the class itself that you pass may have functionality that you can provide, but then you're passing a whole class. If you're in a desktop environment, that may make sense. It may make sense to have a couple of big objects and they just basically interact with each other. You don't have to worry about passing data across a network or anything like that. It may change your memory footprint, but even then, actually, if you have fewer bigger objects overall, you're probably going to have better memory, less memory overall taken up than a lot of smaller objects just because of the overhead of a class in itself, of an object instance in itself. When you replicate an instance, you replicate everything. It's not just the data, it's all the methods and things like that. Now, that's not 100% replication because sometimes there are pointers and things like that. Systems do object-oriented languages in particular do things to prevent duplication of code and memory spaces when they can, when it makes sense. This is where we'll get into conversations later about the idea of static values and methods and things like that. In this case, we need to think through what do we want to do? It comes down to what are we going to use and how often. I think of it sort of like a workbench. If you think about it, if you go out to a garage or some shop or somewhere like that, or even probably your desk at work, it's roughly a workbench. There are things that we use regularly that we want to keep handy, and then there are things that we don't use as much so we can put them in a drawer or on a shelf or something like that. In memory, it's the same thing. We want to keep the things in memory that we use a lot. The things that we rarely use, then we'll store those off to disk somewhere. We can spend the time to load and unload those. A desktop's the same way. If you've got a workbench or a desktop, there's only so much space. You can think about it like if you've got a filing cabinet of some sort, then you've got files you're working on that are on your desk, and then you've got others that are going to be sitting in the file cabinet. We'll get to those when we need to, if we want to. We may even swap stuff out. It's like that in a design. There's going to be, we'll call them core classes, core bits of data, groups of data that we're going to work with. For example, if we are a customer relationship management application, the customer, a customer instance is something we're going to work with on a regular basis. Now, let's say we have backup utilities, backup and restore utilities. Those classes we're not going to use very often. We can push those aside a little bit. We work with that, and this translates into the cohesion and coupling discussion as far as is there data that we need to have available all the time, functionality that we want available essentially all the time, and is there data and functionality that we only need in certain cases? If it was some sort of a financial system, then our general ledger is maybe something we need to have available, that class and the methods around it we want available all the time. That would make sense to have a ledger class. I'm assuming a lot because obviously every design is unique, but in this case, we're going to assume that we're going to be in the ledger a lot. We have a ledger class, and there are certain functions that we're going to perform on that ledger on a regular basis. So it probably makes sense for those to be part of the ledger. Now, something like a year-end report, something that takes that ledger and then works with the data and generates a year-end report, that one doesn't need to be used as much, obviously. It's a year-end report. So maybe we have a year-end report class that we send data to, and it generates a report for us. That means when we normally have the ledger class, we have an instance of that ledger class, we don't also have to have in memory somewhere an instance of the annual report class. It's sort of a just-in-time usage of our data and even our methods, because remember, and it's easy to forget this, but when we build a class and we start passing a class around, not the data for the class, a class instance, it includes those methods and all the other stuff that is a part of what makes that class, that instance, that class. So it's not just some bits of data. Now, we can solve this with patterns like a flyweight or something like that, where we essentially distill the class, the class instance, down to just the data and sort of separate it from the functionality, and then we can ship that data across a network, send it across the wire, send it to other objects, and then they can actually, they can use that data to basically recreate the entire instance that we started with on one end, because it can go back and say, oh, here's, I've got the data, but here's all the methods that I need to do, I need to incorporate to make an actual full-blooded instance. And we see this with things like persistence and stuff like that, where we were able to persist it with just the data, but then when we reload it, then we load that data into the entire instance with all of the methods and functions that are a part of it. So we once again see where there is a trade-off between essentially convenience and even speed, because if calling a method has to go through a couple layers of internal calls or external calls to another class, there's time involved there. And we see a trade-off between that and essentially space and flexibility. If we build it all into the class, then that means that if we change it, we have to recompile the entire class. If it's some additional, some coupled piece of functionality, then we only have to worry about that coupled piece of functionality. Now that may be splitting hairs a little bit, because a lot of the systems we have these days can compile fairly quickly, but when you start scaling up to something very large, that can become an issue. So something to think about. Something that we want to make sure is part of our design process. Where does it make sense to gather functionality and data? Essentially what are the core chunks of data and functionality that we're working with? And where does it make sense to sort of offload those, to allow those to be a helper, some sort of coupling, so that we don't have to have that stuff available to us all the time. And then I'll wrap it up for this one. Challenge of the week. Take a look at some of your classes, and particularly if there's some large ones, if they're not super thin classes, ones that have methods on them, have some functionality, not just straight data. And consider what would it mean to pull some of that functionality out into some sort of helper kind of class to decouple some of that functionality and maybe thin down your main classes, your primary classes, the ones that you're using the most, and gather some of that functionality elsewhere so it only needs to be implemented. It only needs to be pulled in and instantiated, pulled into memory when you're actually using it so that you can use that tool and then set it back into the drawer or set it aside somewhere so you don't have to overflow your workbench. That being said, whether your workbench is empty or you're buried underneath it, it's time to return to it. So go out there and have yourself a great day, a great week, and we will talk to you next time. Thank you for listening to Building Better Developers, the Developer Nord podcast. For more episodes like this one, you can find us on Apple Podcasts, Stitcher, Amazon, and other podcast venues, or visit our site at developernord.com. Just a step forward a day is still progress, so let's keep moving forward together. Hi, this is Rob from Building Better Developers, the Developer Nord podcast. We're excited to be on Alexa now. You can enable us by simply saying, Alexa, enable Building Better Developers, and we will be there ready for you every time you want to listen to your now favorite podcast. Whether we are your favorite podcast or not, we would love to hear from you, so please leave a review on Amazon. Now back to the show.