Sign in

Stamp Coupling

The name stamp coupling is historical and refers to data structures that are “stamped” and passed around as a whole.

Think of records, structs, objects or data packets. Every time when you pass around class instances, technically you use stamp coupling.

But it is when only a part of the data in the stamp is used, when we call it out, because that is when problems might arise.

class Shape:
····def move(self) -> None:
········print("Move")

····def draw(self) -> None:
········print("Draw")

def move(shape: Shape) -> None:
····shape.move()
····shape.draw()

def redraw(shape: Shape) -> None:  # Too much information.
····shape.draw()                   # Only .draw() is used.

Objects of type Shape are accepted in functions move and redraw. Notice how redraw takes a shape but only uses draw from it.

That is the moment where we call-out there is stamp coupling going on. A solution could be to introduce a protocol class that functions as a interface.

from typing import Protocol

class Movable(Protocol):
····def move(self) -> None: ...
····def draw(self) -> None: ...

class Drawable(Protocol):
····def draw(self) -> None: ...

class Shape:
····def move(self) -> None:
········print("Move")

····def draw(self) -> None:
········print("Draw")

def move(shape: Movable) -> None:  # Exactly needed
····shape.move()
····shape.draw()

def redraw(shape: Drawable) -> None:  # Exactly needed
····shape.draw()

Yes, it introduces extra code but the coupling has become smaller. There is no risk of calling wrong methods in the functions anymore.

Written by Loek van den Ouweland on Jan. 7, 2026.