Cathedrals and bazaars

In the third session we explore the tradition of modular software, from UNIX to the free software movement. Modularity is not a technical matter: it's a way of designing, thinking, and evolving products.

November 28, 20258 min read
Cathedrals and bazaars

In the third session of the product management program at Instituto Tramontana we explored one of the most influential metaphors in the history of software: the cathedral and the bazaar. This was an entirely hands-on session, with code in front of us, because some ideas can only be assimilated by doing.

Most digital products — though we see them as closed, clean, uniform applications — are made up of small pieces that connect to each other. They are not monolithic cathedrals: they are bazaars full of modules that interact. Understanding this difference, and knowing when to apply each model, is one of the most valuable skills for someone who leads product.

Two ways of building

The metaphor comes from Eric S. Raymond and his essay The Cathedral and the Bazaar, published in 1997. Raymond observed that there were two radically different ways of developing software:

In the cathedral, software is built in a centralized, planned, and closed manner. There is an architect (or a small group) who designs the whole. The blueprints are completed before laying the first brick. Code is released only when it's finished. It is the model of classic commercial software, but also of many internal projects within companies.

In the bazaar, software emerges like an open market. Small pieces, frequent changes, distributed contributions. "Release early, release often" is the mantra. Users are co-developers. Bugs are found quickly because many eyes are looking. It is the model of free software, of Linux, of projects that grow through the accumulation of contributions.

The goal of the session was not to judge which one is "better." Both styles coexist in all modern products, though not always explicitly. The tension between rigidity and flexibility appears in every design decision. Recognizing it is the first step toward managing it.

Participants working in pairs during the session

The UNIX tradition

Before Raymond, there was UNIX. And UNIX left us a design philosophy that continues to structure contemporary software. Three ideas summarize it:

Do one thing and do it well. Each tool, each module, each function should have a clear and bounded responsibility. Don't try to solve everything in a single place.

Connect simple pieces to obtain complex results. Power comes not from building giant components, but from being able to combine small components in unexpected ways. The UNIX pipe (|) is the symbol of this philosophy: the output of one program becomes the input of the next.

Treat everything as a flow. Inputs that transform into outputs. Data passing through stages. Information that flows. This way of thinking — which we already explored in the previous session with the producer-consumer paradigm — is the DNA of modular software.

The Art of UNIX Programming, also by Raymond, documents this tradition in detail. And The UNIX Programming Environment by Kernighan and Pike remains essential reading for anyone who wants to understand how to design software that lasts.

Software as assembly

Unlike monolithic constructions, modern systems are assembled, not "finished." They are:

  • collections of pieces with clear responsibilities,
  • components that evolve at different paces,
  • subsystems connected by interfaces,
  • replaceable parts without needing to redo the whole.

This idea has profound consequences for product. It means that good product management consists, to a large extent, of deciding where to place the boundaries and what shape the interfaces take. It's not a technical decision to be delegated to engineering; it's a design decision that affects everything: what can be changed easily, what requires coordination, what can evolve independently.

Focused participants taking notes

Why modularity matters

Modularity introduces concrete advantages that directly affect a product's ability to grow and adapt:

It reduces complexity. A system of a hundred thousand lines of code is unmanageable. A hundred modules of a thousand lines each can be understood one by one.

It bounds responsibility. If something fails, you know where to look. If something needs to change, you know what to touch. Clear boundaries are also cognitive boundaries.

It enables parallel work. Different teams can work on different modules without stepping on each other. This is one of the reasons why modular architectures scale better organizationally.

It facilitates experimentation. You can change a module, test it, and if it doesn't work, roll back. The cost of error is bounded.

It limits the impact of failure. A bug in a well-isolated module shouldn't bring down the entire system. Boundaries are also firewalls.

It improves the ability to explain. When you can describe your product as a composition of pieces with clear responsibilities, you can communicate it better — to users, to investors, to new team members.

But modularity also carries risks. Too much fragmentation leads to chaos. Heterogeneity without criteria produces systems where no one understands the whole. Modularity is a discipline, not an absence of rules.

Interfaces as a thinking tool

A module is understood by what it makes visible:

  • what it receives (input),
  • what it does (transformation),
  • what it returns (output).

Not by what happens inside. The inside is the black box we discussed in the first session.

This way of thinking is especially useful for product. It helps describe features without getting into implementation details. It allows delimiting responsibilities between teams: "you take care of making this module receive X and return Y; how you do it is your decision." It reduces the dependencies that slow down development.

APIs are the most visible expression of this principle. A well-designed API is a clear interface: it documents what goes in, what comes out, and what guarantees it offers. But the principle applies at any scale, from a function to a distributed system.

When the cathedral makes sense

The cathedral approach is not obsolete. There are contexts where centralized planning and strict control remain the best option:

  • When iron-clad coherence is needed. Security systems, payment platforms, critical infrastructure. Here, surprises are unacceptable.

  • When the domain requires few variations. If the problem is well-defined and doesn't change much, the cost of flexibility isn't justified.

  • When independence between pieces doesn't add value. Sometimes tight integration is exactly what you need.

  • When evolution must be tightly controlled. Regulation, compliance, audits. There are industries where "release early, release often" is not an option.

Understanding when the cathedral model is appropriate prevents the mistake of applying the bazaar by default, as if it were always superior.

Modern examples of modularity

The modular tradition is present in nearly all contemporary software:

  • APIs as borders between systems, contracts that allow pieces developed by different teams (or different companies) to work together.

  • Webhooks as extension mechanisms: "when X happens, notify me at this URL." The system opens up without exposing its internals.

  • Pipelines that transform data in stages, each with a clear responsibility.

  • Microservices, with all their complexities, are an expression of the principle of doing one thing and doing it well.

  • CLI tools that combine in scripts, exactly as in the 1970s.

  • Integrations that expand capabilities without touching the product's core.

All these patterns illustrate how the bazaar philosophy remains relevant, even though we now call it service architecture or API-oriented design.

Thinking in modules

The session ended with a reflection on why modularity is a useful framework for product decisions:

  • It forces simplification. If you can't describe what a module does in one sentence, it probably does too much.

  • It helps explain. "The product has three parts: X does this, Y does that, Z connects X with Y" is more useful than a diagram with a thousand boxes.

  • It delimits responsibilities. Both technical and organizational.

  • It reduces surprises. Clear boundaries are also clear expectations.

  • It allows exploration without redoing everything. You can experiment with one piece while the rest keeps running.

In an environment where systems are increasingly complex, thinking in modules is thinking better. It's not a technique; it's a way of seeing the world. And, as we saw in this session with our hands on the code, it's a way of seeing that turns complexity into something manageable.


Session practice

Hands-on exercise: Modularity in action. The entire session was practical, working on the program's repository. The session 3 exercise consisted of analyzing an existing system, identifying its modules, mapping its interfaces, and proposing improvements in the separation of responsibilities. We worked in pairs, with the code in front of us, discussing where the boundaries were and where they should be.

Homework: Continuation of the exercise, now working with data models and entities. The goal was to apply modularity principles to the data layer: identify the domain entities, define their boundaries, and design clear interfaces between them. A practical introduction to Domain-Driven Design by Eric Evans.

2026 © Íñigo Medina