Free — no signup required

Composition vs. Inheritance

3 min read

The "Is-A" vs. "Has-A" Debate

In Object-Oriented Programming (OOP), Inheritance lets you define a base class and extend it. A Dog is an Animal, so it inherits all of Animal's properties and adds its own. This is powerful in languages like Python or Java, but it creates tight coupling — change the base class and every subclass is affected.

Terraform does not support inheritance. There is no mechanism to define a base-server module and have a web-server module extend it. This is a deliberate constraint, not an oversight.

Instead, Terraform relies exclusively on Composition: you build complex things by combining smaller, simpler things. A WebServer module doesn't extend a base — it contains a compute instance, a security group, and a load balancer. Each of those components can exist and be tested independently.

How Composition Works in Practice

The mental model shift is from "what does this inherit?" to "what does this contain?"

Inheritance thinking (not possible in Terraform):

BaseServer → WebServer (adds port 80)
BaseServer → DatabaseServer (adds port 5432)

Composition thinking (how Terraform actually works):

WebServer module
  ├── has a: Compute Instance module
  ├── has a: Security Group module
  └── has a: Load Balancer module

In code, this looks like a root module composing two child modules — a networking module and a compute module — where the subnet ID output by the first is passed directly as an input to the second. The networking module knows nothing about compute. The compute module knows nothing about how the subnet was created — it just receives an ID. Each module is independently testable, independently replaceable.

Composition Depth: When to Stop

A common mistake is over-composing: creating so many layers of modules that tracing a bug requires navigating five directories. A useful rule of thumb is the three-layer model:

  1. Root module — environment-specific configuration (prod, staging). Calls service modules.
  2. Service module — a logical unit of infrastructure (e.g., "web-app"). Calls resource modules.
  3. Resource module — a thin wrapper around one or two Terraform resources with sensible defaults.

Going deeper than three layers almost always creates more complexity than it solves.

Interview Tip

Interviewers frequently ask: "How do you structure Terraform modules for a large organization?" The trap answer is describing a flat structure or a single monolithic module. The strong answer describes the three-layer model — root, service, resource — explains that outputs flow upward and inputs flow downward, and mentions that each layer should be independently testable. Bonus points for mentioning that the service layer is where composition happens and where most business logic lives.

Key Point: Composition is not just a Terraform constraint — it is architecturally superior to inheritance for infrastructure because it keeps modules independently deployable and testable. The discipline is knowing when to stop composing and resist the urge to add a fourth layer of abstraction.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free