The Power of Composition

Last updated Nov 25th, 2025
In this article, we explore composition: one of the 12 essentials of testing, design & architecture.

Quick question.

How often do you see this type of code?

composition conditional problem

If the answer is "a lot", that's okay - we've all been there.

Especially in the Code-First Phase of Craftship.

(Learn more about the 5 Phases in this free guide here)

However, if you're seeing this a lot, it's a good sign that you may be missing Composition, which is one of 12 Essentials that -- when balanced properly, tends to lead to testable, flexible, maintainable code...

... and when out of balance, tends to lead to significant issues that are REALLY hard to fix later on down the road.

In my estimation, nearly every problem you face in your codebase can be traced back down to at least one of the 12 Essentials.

This took me a long time to figure out, so I'll do my best to explain in a short email.

What is composition?

Composition is simply:

How your application “comes together.” How objects get created. How dependencies get wired. How environments boot.

You use composition every time you boot your app:

Boot in dev mode → you need composition

Boot in test mode → you need composition

Boot integration tests → you need composition

Boot in production → you need composition

Boot a CLI tool? → you need composition

Boot a worker? → you need composition

Composition is the grand configurer-er. The mechanism everything else sits on.

You know those little Russian Dolls? (they're called Matryoshka dolls).

Well, that's kinda how I see composition. Your application is composed from parts and wholes, coming together to fulfill a larger responsibility.

One environment wrapping the next, cleanly composed, cleanly booted.

It's quite beautiful, really.

And if structured correctly, you can design your application to spin up the right way, with the right parts, for the right context, in a simple way, from a single location (typically called the Composition Root).

This is immensely powerful, and also immensely debilitating if you don't have a composition root.

What most devs do

Most developers at the Code-First phase aren't yet aware of how important this essential is downstream, so they miss it.

Instead, you'll end up seeing things like:

  • imports scattered all over the place
  • mutating global state
  • using environment variable checks
  • hacking dependencies in place
  • coupling everything in a single controller or Express.js route

And yeah — it works…

until the moment you try to test it.

Or deploy it.

Or run it in a different environment.

Or swap a dependency.

Or add a new feature.

Then it turns into pain.

Ask me how I know 😅

This is one of the root causes behind fragile systems.

It's also at the root of why you can't write tests.

I honestly think that

Developers who say they “hate testing” don’t actually hate testing. They hate the mess they have to fight through just to test anything. But it comes from a lack of Composition and Horizontal Decoupling (another essential).

The benefits of composition

Clean composition gives you:

  • real testability
  • clean dependency inversion
  • multiple composable boot modes (dev, prod, ci, xyz)
  • more confidence when refactoring
  • the heart of a stable architecture
  • the ability to scale your codebase in a modular way (just add new modules)

For example, one of my favourite things is the ability to just boot my application the exact same way every time, simply specifying the context, and allowing the application to wire itself up properly behind the scenes.

Like this.

Composition Topics Web

How to fix it

It takes a few course modules to fully explain how to fix this without breaking everything, but in summary, the answer is to actually start using Abstraction properly.

A good place to start?

Start encapsulating stuff.

This is a big topic to explain, and there are a lot of smaller topics underneath it (see the below diagram)

Composition Topics Web

But you can begin to untangle this problem by implementing a Layered Architecture, slowly, and being more intentional about the entry points to your various execution environments.

My recommendation is to implement a single bootstrap location, like a "poor man's version of composition".

You'll notice that we lean heavily on Dependency Inversion / Injection for this.

Composition Topics Web

From here, we can begin to branch into more sophisticated forms of Composition.

But in my opinion, if you're at the Code-First level, this is a great start, in order to start to create some semblance of structure.

FAQ

“What if I’m not doing composition?”

You are. Everyone is to some degree. You can’t not compose your app.

The real question is:

Are you doing it intentionally or accidentally?

To what degree of consciousness are you composing your application?

“How important is this?”

It’s one of the 12 Essentials. Miss it and everything downstream gets harder. Just like all of the other ones.

“What are the levels?”

All Essentials have a scale of mastery from 1 to 10.

Sometimes the problem calls for a simpler solution, sometimes a more robust one. Discernment and wisdom to know the difference comes from awareness and practice.

Level 1: Everything in one file (Express controller, Next.js route, etc). It works — but costs you flexibility.

Level 10: Full-blown DI container, composable boot modes, multi-env testing layers, modules, compositional roots within modules, extremely modular.

Final notes

  • A student in the community built a great DI container. He's been using it in production with his team for over a year without any issues. Check it out 👉 https://github.com/webiny/di
  • Take a look at this solution that one of my mentorship students put together demonstrating how to use composition to compose your backend for testing and running production. https://github.com/trikitirem/ddd-forum-be. I especially like how he uses abstraction to abstract the composition root based on the context we run the application. Really, really nice implementation.

Thanks for reading,

Khalil


As a reminder,



Stay in touch!



View more in Enterprise Node + TypeScript