During PyCon Austria 2026, I presented the combinator design pattern and showed how to structure logic as composable units rather than hard-coded flows.
The Programming Problem
When sophisticated logic is embedded within entities, it violates the Single Responsible Principle and makes systems harder to evolve. Every new requirement forces a modification rather than an extension. The core issue is modeling the logic as control flow rather than as composable units. This leads to rigid systems that resist change.
The Combinator Pattern Solution
By treating the logic rules as first-class objects, we can compose them like LEGO blocks into richer behavior. This enables flexible, extensible validation and logic pipelines.
I was lucky to meet highly talented professionals who were curious to learn about the Combinator design pattern and chose to attend my talk.
Slides from the Talk
The presentation of my talk is available for download at shareslides.net. It includes conceptual framing and concrete Python examples.
The Code Samples
You can find below the code samples I was using in my talk. I strongly recommend that you execute the code. It will assist you with improving your understanding of this specific topic.
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, List
@dataclass(frozen=True)
class ValidationResult:
valid: bool
errors: List[str]
@staticmethod
def success() -> ValidationResult:
return ValidationResult(True, [])
@staticmethod
def failure(message: str) -> ValidationResult:
return ValidationResult(False, [message])
def merge(self, other: ValidationResult) -> ValidationResult:
return ValidationResult(
valid=self.valid and other.valid,
errors=self.errors + other.errors,
)
class PasswordRule:
def __init__(self, validator: Callable[[str], ValidationResult]):
self._validator = validator
def validate(self, password: str) -> ValidationResult:
return self._validator(password)
def __call__(self, password: str) -> ValidationResult:
return self.validate(password)
def and_(self, other: PasswordRule) -> PasswordRule:
def combined(password: str) -> ValidationResult:
return self.validate(password).merge(other.validate(password))
return PasswordRule(combined)
def or_(self, other: PasswordRule) -> PasswordRule:
def at_least_one(password: str) -> ValidationResult:
result = self.validate(password).valid or other.validate(password).valid
return ValidationResult.success() if result else ValidationResult.failure("Password must match at least one rule.")
return PasswordRule(at_least_one)
def min_length(length: int) -> PasswordRule:
return PasswordRule(
lambda password: (
ValidationResult.success()
if len(password) >= length
else ValidationResult.failure(
f"Password must be at least {length} characters long."
)
)
)
def has_uppercase() -> PasswordRule:
return PasswordRule(
lambda password: (
ValidationResult.success()
if any(ch.isupper() for ch in password)
else ValidationResult.failure(
"Password must contain at least one uppercase letter."
)
)
)
def has_lowercase() -> PasswordRule:
return PasswordRule(
lambda password: (
ValidationResult.success()
if any(ch.islower() for ch in password)
else ValidationResult.failure(
"Password must contain at least one lowercase letter."
)
)
)
def has_digit() -> PasswordRule:
return PasswordRule(
lambda password: (
ValidationResult.success()
if any(ch.isdigit() for ch in password)
else ValidationResult.failure(
"Password must contain at least one digit."
)
)
)
def has_special_char() -> PasswordRule:
special_chars = set("!@#$%^&*()-_=+[]{};:,.<>?/|\\")
return PasswordRule(
lambda password: (
ValidationResult.success()
if any(ch in special_chars for ch in password)
else ValidationResult.failure(
"Password must contain at least one special character."
)
)
)
def no_whitespace() -> PasswordRule:
return PasswordRule(
lambda password: (
ValidationResult.success()
if not any(ch.isspace() for ch in password)
else ValidationResult.failure(
"Password must not contain whitespace."
)
)
)
if __name__ == "__main__":
password_policy = (
min_length(8)
.and_(has_uppercase())
.and_(has_lowercase())
.and_(has_digit())
.and_(has_special_char())
.and_(no_whitespace())
)
passwords = [
"abc",
"password123",
"Password123",
"Password123!",
"Password 123!",
]
for password in passwords:
result = password_policy.validate(password)
print(f"Checking password: {password!r}")
if result.valid:
print(" Valid password")
else:
print(" Invalid password")
for error in result.errors:
print(f" - {error}")
print()
#password = "abC"
#policy = min_length(8).or_(has_uppercase())
#print(policy.validate(password).valid)
Functional Programming
The functional programming paradigm is my favorite one. I have been teaching functional programming for many years. I usually use the Scala programming language. This talk was a great opportunity to combine the beauty of Python with the power of functional programming.
The combinator pattern encourages a shift in how we think about software design. Instead of embedding logic into structures, we compose it. This small conceptual change can lead to systems that are significantly more flexible, testable, and aligned with fundamental design principles.







