Beyond the God Class: Refactoring Python with Functional Composition
Overview
Python is a multi-paradigm language, yet many developers fall into the trap of using exclusively object-oriented patterns. This often results in "God Classes"—massive, bloated structures that handle everything from data storage to complex I/O and visualization. By shifting toward a functional style, we can decouple our logic, making our code more modular, easier to test, and significantly cleaner. This tutorial demonstrates how to strip a model down to its essential data and move complex behavior into pure functions and higher-order compositions.
Prerequisites
To follow this walkthrough, you should have a solid grasp of basics, including classes and functions. Familiarity with API concepts is helpful, as our example involves a word puzzle generator powered by an LLM. You should also understand the concept of a dictionary and how templates work in Python's string module.
Key Libraries & Tools
- : Used for data validation and easy dictionary conversion via
BaseModel. - : A core utility used to apply functions cumulatively to an item.
- : The underlying engine providing chat completions for puzzle generation.
- Typing Module: Specifically
CallableandAnyfor creating type-safe functional aliases.

Code Walkthrough
1. Stripping the God Class
We start with a PuzzleGame class that does too much. By extracting methods like filter_words and print_puzzle, we turn them into pure functions. This ensures the class only represents the state of the game, not the logic for displaying it or processing raw strings.
# Before: Part of a class
# After: A pure function
def filter_words(solution: str, words: list[str]) -> list[str]:
return [w for w in words if len(w) == len(solution)]
2. Implementing Function Composition
To avoid "parentheses hell"—where nested function calls like parse_json(chat(substitute(dict(puzzle)))) become unreadable—we implement a compose function. This higher-order function uses reduce to chain operations.
from functools import reduce
from typing import Callable, Any
Composable = Callable[[Any], Any]
def compose(*functions: Composable) -> Composable:
return lambda x: reduce(lambda v, f: f(v), functions, x)
3. Using Closures for Logic Grouping
Inside our main generate_puzzle function, we define closures. These are inner functions that remember the environment where they were created. They can access the puzzle object in the outer scope without needing it passed as an explicit argument, reducing boilerplate.
def generate_puzzle(topic: str, chat_fn: Callable):
puzzle = PuzzleGame(topic=topic)
def generate_string(prompt_template):
# Closure accessing 'puzzle' from outer scope
pipeline = compose(dict, prompt_template.substitute, chat_fn)
return pipeline(puzzle)
puzzle.title = generate_string(TITLE_PROMPT)
return puzzle
Syntax Notes
Notice the use of *functions in the compose definition. This is the star-args syntax, allowing the function to accept any number of positional arguments. We also utilize Type Aliases (like Composable) to make our higher-order function signatures readable. The lambda in our reduction is a closure, capturing the sequence of functions to be executed later.
Practical Examples
These techniques are invaluable when building wrappers or data processing pipelines. Instead of a monolithic class that handles a network request, parses JSON, and validates data, you can compose three distinct functions. This makes it trivial to swap your chat_fn for a mock function during testing without ever instantiating a complex object.
Tips & Gotchas
One common mistake is over-complicating the reduce logic. If a composition chain is too long, it can become hard to debug. Always name your intermediate closures (like generate_string) so that stack traces remain meaningful. While functional programming is powerful, keep your initializers simple; avoid long-running AI calls inside an __init__ method, as this makes your objects unpredictable and slow to instantiate.
- 33%· companies
- 33%· products
- 17%· libraries
- 17%· languages

Refactoring Object-Oriented to AWESOME Functional Code
WatchArjanCodes // 22:59
On this channel, I post videos about programming and software design to help you take your coding skills to the next level. I'm an entrepreneur and a university lecturer in computer science, with more than 20 years of experience in software development and design. If you're a software developer and you want to improve your development skills, and learn more about programming in general, make sure to subscribe for helpful videos. I post a video here every Friday. If you have any suggestion for a topic you'd like me to cover, just leave a comment on any of my videos and I'll take it under consideration. Thanks for watching!