Becoming the Best Software Engineer: Pythonic Stamp Coupling

Spread the love

In this blog post, you will learn what stamp coupling is and why it is important. Also, you will see a pythonic code sample that exemplifies the concept, and what you can do to improve your code so that it is coupled by data instead of being coupled by stamping. This blog post is part 2 of a series on pythonic coupling. To read part 1 of this series on pythonic coupling, read my previous blog post on Becoming the Best Software Engineer: Pythonic Data Coupling.

What Is Stamp Coupling and Why Is It Important?

Stamp coupling is a fairly low type of coupling that occurs when modules share a composite data type, such as a record or object, and not all the attributes are used (Ingeno, 2018). It differs from data coupling because data coupling involves passing primitive data types between modules, whereas stamp coupling involves passing composite data types between modules.

It is important to understand the concept of stamp coupling because it is considered permissible, yet it is a tighter coupling compared to data coupling. This is because when an entire record or object is passed to another module, the module must be aware of how to interact with the record or object, which means there is a tighter coupling. If changes are made to the record or object, then all the modules that interact with it must be updated.

An Example of Pythonic Stamp Coupling

The pythonic stamp coupling example shows a stamp coupling between a person module and emails module. It’s a simple example where a person’s email is added to the emails module given a person object.

The following is the code for the person.py module:

class Person:
    def __init__(self, name : str, email : str):
        self.__name = name
        self.__email = email
    
    @property
    def name(self) -> str:
        return self.__name

    @property
    def email(self) -> str:
        return self.__email

    def __str__(self) -> str:
        return f"Person ({self.__name},{self.__email})"

The following is the code for the emails.py module:

from person import Person

class Emails:
    def __init__(self):
        self.__emails = []
    
    def add_email_from_person(self, person : Person):
        self.__emails.append(person.email)
    
    def __str__(self) -> str:
        output = "Emails:\n"

        for email in self.__emails:
            output = output + email + "\n"
        
        return output

The following is the code for main.py, which shows how the modules interact:

from person import Person
from emails import Emails

def main():
    # Create a person object.
    person = Person("Gary Drocella", "[email protected]")

    # Create an emails object.
    emails = Emails()

    # Add an email given a person object. The line of code below 
    # exhibits stamp coupling.
    emails.add_email_from_person(person)

    print(emails)


if __name__ == "__main__":
    main()

The above code will instantiate a person object and emails object, and then a person’s email is added to the emails object by passing a person object as an argument to the method add_email_from_person. In the example, the person object is the stamp. The implementation of the add_email_from_person method is tightly coupled with the person module, so if the name of the email property were to change, then the emails module will also need to change.

How Can We Make This Code Better?

We can make this code even better by moving from stamp coupling to data coupling. The implementation of the emails module becomes the following:

class Emails:
    def __init__(self):
        self.__emails = []
    
    # pass an email as an argument instead of the entire person object. 
    def add_email(self, email):
        self.__emails.append(email)
    
    def __str__(self):
        output = "Emails:\n"

        for email in self.__emails:
            output = output + email + "\n"
        
        return output

The implementation of main.py becomes the following:

from person import Person
from emails import Emails

def main():
    # Create a person object.
    person = Person("Gary Drocella", "[email protected]")

    # Create an emails object.
    emails = Emails()

    # Add an email given the person's email. This is the example 
    # of data coupling. Data coupling is more preferred than 
    # stamp coupling.
    emails.add_email(person.email)

    print(emails)


if __name__ == "__main__":
    main()

In the above code sample, you can see that an email is passed as an argument to the add_email method given the person’s email instead of passing the entire person object as an argument. Now, the person module and emails module are coupled by data, which is a looser coupling compared to stamp coupling. This means the code becomes easier to test and maintain, which are major benefits.

That concludes this blog post on stamp coupling. You learned what stamp coupling is and why it’s important. Also, you were given an example that exemplifies stamp coupling, and you learned how to fix the example so that it exhibits data coupling, which improves it.


If you found this blog post to be valuable, then you should consider doing the following:

  • Share the blog post!
  • Subscribe to my blog!
  • Consider buying me a coffee!

Subscribe

* indicates required

Intuit Mailchimp


References

Ingeno, J. (2018). Software architect’s handbook. Packt Publishing.


Posted

in

by