Skip to the content.
Composition over Abstraction: Why Pipelines Win | AI Systems Design From Scratch

Connect with Amin Boulouma Official

AI Systems Design From First Principles - An implementation of AI Systems Design From First Principles | Product Hunt

🏠 Documentation Hub 📝 Engineering Blog 💻 GitHub Repository

Composition over Abstraction

Amin Boulouma, Software Engineer

The code snippet IOUtility.text_to_lines_generator(IOUtility.read_decoded(file_path)) is a classic example of function composition. Instead of creating a complex “God Object” or a deeply nested class hierarchy (over-abstraction), you are piping data through small, focused, and reusable functions.

The Concept: Composition vs. Abstraction

Analyzing Your Pattern

Your snippet is a perfect example of a data pipeline.

# The Nested Approach (Harder to read as it grows)
result = IOUtility.text_to_lines_generator(IOUtility.read_decoded(file_path))

# The Composed Approach (More readable for complex pipelines)
raw_data = IOUtility.read_decoded(file_path)
lines = IOUtility.text_to_lines_generator(raw_data)

Why this is superior to heavy abstraction:

  1. Loose Coupling: Each function is agnostic of the other. text_to_lines_generator doesn’t care where the text came from, only that it is a string.
  2. Testability: You can unit test read_decoded and text_to_lines_generator in isolation.
  3. Flexibility: If you want to change how you read files (e.g., adding encryption), you only change the first function in the chain, not the entire pipeline architecture.

Visualizing the Pipeline

In a composition-heavy architecture, you view your system as a series of transformations:

When to prioritize Composition

By avoiding excessive abstraction—such as creating an FileProcessor class that holds internal state—and favoring functional composition, you ensure your code remains agile and easy to debug.

Connect with Amin Boulouma Official