MuTasim

Mereology for Developers

⌛ 8 min read

It has been a while since I posted anything here. Life has been a mix of code reviews, discussions about philosophy, and too much coffee. But today I wanted to write something a bit different. I have been thinking about how philosophy and tech overlap, and one idea has been stuck in my mind for weeks.

Lately I have been reading more philosophy and theology, and one topic that caught my attention is mereology, which is the study of parts and wholes. What surprised me is how closely this connects to the way we build software systems. It feels like the more I learn about it, the more the structure of code starts to make sense in a new way.

Mereology

Here are the basics. Mereology (from the Greek word μέρος, meaning "part") is a branch of metaphysics that asks simple but important questions. What makes something a part of something else? When do parts come together to form a whole? And is a whole just the sum of its parts, or is it something more?

Aristotle helped shape this topic by separating matter from form. Think of a statue. It is not only a block of marble (the matter). It is marble that has been shaped into something meaningful (the form). Without that structure, the parts do not tell us much.

Later philosophers took this further and built different ways of thinking about parts and wholes:

  • Mereological Universalism: Any collection of parts forms a whole. So your laptop and my coffee mug could count as a single object.
  • Mereological Nihilism: Composite objects do not exist at all. Only the most basic particles are real, and everything else is just a way of speaking.
  • Restricted Composition: Wholes exist only when parts are connected in the right way. Not every set of parts can count as a unified object.

Here is where it links to software development. These ideas are not just abstract theory. They reflect the same questions we deal with when we design modules, components, or services, and when we decide how smaller pieces should come together to form a complete system.

The Component Question

Let's talk about React, Vue, Svelte, or any framework that uses components. When you split your UI into smaller pieces, you are already doing mereology. You are asking questions like: What counts as a reusable part? Where does the boundary go? How do these parts come together to form something that feels complete?

Here is a simple example. Imagine you are building a product card:

ProductCard.tsx
export function ProductCard({ product }: ProductCardProps) {
  return (
    <div className="card">
      <ProductImage src={product.image} />
      <ProductTitle>{product.name}</ProductTitle>
      <ProductPrice amount={product.price} />
      <AddToCartButton productId={product.id} />
    </div>
  );
}

Look at what is happening here. We used a kind of mereological restriction. We decided that ProductImage, ProductTitle, ProductPrice, and the rest are real parts that should stand on their own. We could have placed everything inside one large component, but we chose not to. The reason is simple. Good parts should have clear roles and real reusability.

Now for the interesting question. Is ProductCard an actual whole, or is it only a useful name for a group of smaller pieces? If I refactor the code and place all the logic back into one file, does the sense of a complete whole disappear? A mereological nihilist would say the whole was never real and was only an idea. A universalist would say any grouping still counts. As pragmatic developers, we work somewhere in the middle, where composition only makes sense when parts are unified by purpose and context.

Endurantism vs. Perdurantism

Now let's go a bit deeper. In metaphysics, there is a debate about how objects continue to exist over time.

  • Endurantism: An object is fully present at every moment. You right now are completely you, and you tomorrow are still completely you. Same object, different time.
  • Perdurantism (sometimes called four dimensionalism): An object is stretched across time like a long shape. Each moment is only a part of that larger entity. So you right now are only one temporal part of the whole you.

It sounds unusual, but this maps neatly onto how we think about state in programming.

Endurantist Approach: Mutable State

endurantist-state.js
class Counter {
  constructor() {
    this.count = 0; // The object stays the same and only its properties change
  }
  
  increment() {
    this.count++; // Same object with updated state
  }
}

const counter = new Counter();
counter.increment();
console.log(counter.count); // 1

This reflects endurantism. The counter object stays the same over time. Only its properties are updated. This is common in object oriented code, in older versions of Vue, and in many libraries that focus on direct mutation.

Perdurantist Approach: Immutable State

perdurantist-state.js
function createCounter(count) {
  return {
    count,
    increment: () => createCounter(count + 1) // A new object each time
  };
}

let counter = createCounter(0);
counter = counter.increment(); // A new object that represents a new moment
console.log(counter.count); // 1

This reflects perdurantism. Each state is a separate temporal part. The counter you get after incrementing is not the same object. It is a new one that represents a new moment. Many functional approaches follow this pattern, including Redux, Zustand, and most immutable state patterns.

Neither approach is simply correct. Each one matches a different view of persistence and identity. Mutable state feels natural and often performs better. Immutable state makes reasoning and debugging easier. The right choice depends on your needs and how you think about objects over time.

Microservices vs. Monoliths

Now let's step back and look at software architecture. The debate between microservices and monoliths is basically a question of mereology.

Monolith thinking: The application is a single unified whole. The parts inside it, such as modules or layers, exist but are deeply connected. You cannot easily take out the authentication module and treat it as an independent unit. It is a part whose meaning comes from the larger structure. This reflects strong composition, where the whole gives the parts their purpose.

Microservices thinking: The system is built from many independent parts. Each service is its own complete unit that simply communicates with others when needed. The sense of a unified system appears only when they work together. This leans toward mereological universalism, since almost any group of services can be described as a system even if their connections are minimal.

microservices-philosophy.ts
// Service A - Autonomous
export class AuthService {
  private users: Map<string, User>;
  
  async authenticate(credentials: Credentials): Promise<Token> {
    // Self-contained logic with minimal coupling
    return this.generateToken(credentials);
  }
}

// Service B - Also autonomous
export class PaymentService {
  async processPayment(token: Token, amount: number): Promise<Receipt> {
    // Validates the token on its own and does not depend on AuthService internals
    return this.charge(amount);
  }
}

// The "whole" is mostly the communication between them
// So is this a unified system, or simply a collection of services?

The central question is simple. At what point do the parts truly form a whole? When does a group of microservices become a real system, rather than separate services on the same platform? Mereology helps us think about this. If there is no clear unifying principle, then the whole might not actually exist. You might only have parts that look connected on the surface.

The Mereological Restriction in Practice

This is where the philosophy becomes practical. Mereological restriction says that not every collection of parts deserves to be called a whole. Only certain groupings actually make sense together. In code, this idea shows up in a few important ways.

  1. Cohesion: Parts should belong together in a functional way. A component that mixes authentication UI with payment logic is breaking mereological rules. The pieces do not naturally unify.

  2. Encapsulation: A part should make sense on its own. If your ProductCard component only works after understanding a long chain of other files, it is not really a clean part. It becomes a tangled structure pretending to be modular.

  3. Purposeful Boundaries: Do not create components simply because the framework allows it. Ask yourself whether this separation reflects something real in the problem space. Or are you only following the idea that smaller components are always better?

bad-mereology.tsx
// ❌ Poor mereology: random splitting with no clear meaning
function ProductPage() {
  return (
    <div>
      <TopBit />        {/* What is this supposed to represent? */}
      <MiddleStuff />   {/* No clear purpose or domain meaning */}
      <BottomPart />    {/* Arbitrary naming without intent */}
    </div>
  );
}

// ✅ Better mereology: parts match real concepts in the domain
function ProductPage() {
  return (
    <div>
      <ProductHeader />      {/* Shows the product title and image */}
      <ProductDetails />     {/* Contains description and specifications */}
      <PurchaseActions />    {/* Handles cart and purchase controls */}
    </div>
  );
}

The difference is intentionality. Good architecture respects mereological limits and treats composition as something meaningful, not mechanical. It recognizes that not every possible split creates real parts. Only thoughtful boundaries create wholes that are easy to understand and maintain.

Why This Matters

You might be thinking something like: "Sure, parts and wholes, but my deadlines are still real"😂. The point here is that mereology gives us a useful way to think about problems we face almost every day in software work.

  • When should I split something into its own component, function, or service?
  • How can I tell whether my modules are actually decoupled?
  • Is my architecture meaningful, or is it just a collection of files that happen to sit together?

These questions go beyond engineering habits. They relate to deeper ideas about parts, wholes, and what makes something a unified entity. Philosophy has been exploring these questions for a very long time.

Studying this material has made me more thoughtful about boundaries in code. I am slower to create abstractions without purpose. And I find myself asking whether a separation reflects something real in the problem or whether it is only a separation on paper.

Wrapping Up

Mereology might look like a surprising topic to connect with software engineering, but it fits naturally. It underpins how we think about components, state, and architecture. Aristotle did not write about React, but he did write about parts and wholes, and that idea still matters.

When you refactor next time, try asking yourself a few simple questions. Are these parts meaningful? Does the whole feel like a real unity? If not, the structure might need another look.

Happy coding, and may your systems hold together in the best possible way. ✨