0Pricing
Go Academy · Lesson

Composition over Inheritance

Go design philosophy.

Composition over Inheritance is a free Go Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Go Design Philosophy

Go deliberately omits class inheritance. The idiomatic approach is composition: build behavior by combining small types and interfaces.

Why Not Inheritance

Deep inheritance trees are brittle: a change in a base class ripples unpredictably. Composition keeps relationships explicit and flexible.

Has-a over Is-a

Instead of "a Manager is an Employee", model "a Manager has an Employee's data and capabilities" via embedding or fields.

package main

import "fmt"

type Employee struct{ Name string }

func (e Employee) Work() string { return e.Name + " works" }

type Manager struct {
	Employee
	Reports int
}

func main() {
	m := Manager{Employee{"Lin"}, 3}
	fmt.Println(m.Work(), "-", m.Reports, "reports")
}

Program to Interfaces

Define behavior with small interfaces, then accept them. Implementations are interchangeable and easy to swap or mock.

package main

import "fmt"

type Notifier interface{ Notify(msg string) }

type Email struct{}

func (Email) Notify(msg string) { fmt.Println("email:", msg) }

func alert(n Notifier, m string) { n.Notify(m) }

func main() {
	alert(Email{}, "deploy done")
}

Swapping Implementations

Because the function depends on an interface, you can pass any implementation without changing the function.

package main

import "fmt"

type Notifier interface{ Notify(msg string) }

type Email struct{}
type SMS struct{}

func (Email) Notify(m string) { fmt.Println("email:", m) }
func (SMS) Notify(m string)   { fmt.Println("sms:", m) }

func alert(n Notifier, m string) { n.Notify(m) }

func main() {
	alert(Email{}, "hi")
	alert(SMS{}, "hi")
}

Combining Behaviors

Embed multiple small components to assemble a feature-rich type from independent, testable pieces.

package main

import "fmt"

type Logger struct{}

func (Logger) Log(s string) { fmt.Println("log:", s) }

type Cache struct{ data map[string]string }

func (c Cache) Get(k string) string { return c.data[k] }

type Service struct {
	Logger
	Cache
}

func main() {
	s := Service{Cache: Cache{data: map[string]string{"k": "v"}}}
	s.Log("started")
	fmt.Println(s.Get("k"))
}

Dependency Injection

Pass dependencies (as interfaces) into constructors instead of hard-coding them. This is composition applied to wiring.

package main

import "fmt"

type Store interface{ Save(s string) }

type MemStore struct{ items []string }

func (m *MemStore) Save(s string) { m.items = append(m.items, s) }

type App struct{ store Store }

func NewApp(s Store) *App { return &App{store: s} }

func main() {
	app := NewApp(&MemStore{})
	app.store.Save("x")
	fmt.Println("saved")
}

Small Interfaces Win

The smaller an interface, the more types satisfy it and the easier it is to test. The bigger the interface, the weaker the abstraction.

Avoiding the Fragile Base Class

Without inheritance there is no base class to break. Each composed part evolves independently, reducing coupling.

Accept Interfaces, Return Structs

A common Go guideline: functions accept interfaces (flexible inputs) and return concrete structs (clear, usable outputs).

Composition Checklist

  • Model has-a, not is-a
  • Embed small components
  • Depend on small interfaces
  • Inject dependencies

Quick Check

Test your composition philosophy knowledge.

Recap

You learned Go's composition philosophy.

  • No inheritance; compose with embedding + interfaces
  • Model has-a over is-a
  • Program to small interfaces, inject dependencies
  • Accept interfaces, return structs

Frequently asked questions

Is the “Composition over Inheritance” lesson free?

Yes — the full text of “Composition over Inheritance” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.

What will I learn in “Composition over Inheritance”?

Go design philosophy. You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Go Academy?

No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Composition over Inheritance” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Go Academy lesson?

Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Struct Embedding
  2. Interface Embedding
  3. Method Promotion
  4. Composition over Inheritance
← Back to Go Academy