Software Design Patterns in Go
Glossary
108 terms from Software Design Patterns in Go, in plain words, each with the chapter that teaches it.
A
- Abstract factory
- A value with several make methods that builds a whole family of matching parts, such as a carrier and a label printer for the same company. It is a heavier alternative to a simple factory, which is enough in most cases.
- Adapter
- A small type that holds an outside library object and offers the methods your code expects. At Kettle & Crane, `UpsCarrier` adapts the UPS rate service, which answers in cents, to the `Carrier` interface, which answers in dollars.
- Anti-pattern
- A common answer to a design problem that looks reasonable but causes more trouble than it solves. Examples are the god object and spaghetti code.
- Architecture patterns (MVC, hexagonal, CQRS, microservices)
- Patterns that apply the same design ideas, such as separating responsibilities and depending on interfaces, to whole systems rather than single types. Examples are MVC, hexagonal architecture, CQRS and microservices.
B
- Behavioral pattern
- A pattern about how objects share work, decisions and messages. Strategy and Observer are examples.
- Blank identifier
- The name `_`, which throws a value away. It can be used in `var _ DiscountRule = Wholesale{}` to make the compiler check that a type satisfies an interface.
- Builder
- A pattern that collects the parts of a value one call at a time and then makes the finished value, checking it at the end. `OrderBuilder` adds a customer, items and a carrier, and `Build()` refuses an order with no items.
C
- Cache
- A saved answer that is reused instead of asking again. For example, a `CachedCarrier` remembers a quote per number of lines, so the real carrier is asked only once.
- Chain of responsibility
- A pattern where a request passes along a line of handlers, and each one deals with it (for example by rejecting it) or passes it on. Kettle & Crane's order checks `hasItems`, `knownCarrier` and `underLimit` form such a chain.
- Characterization test
- A test that records what existing code does today, right or wrong, so a redesign can't change it without you noticing. For example, a test can pin the old order totals 467.5, 42.6 and 31.25.
- Closure
- A function that remembers variables from the place where it was created. `percentOff(10)` returns a function that remembers `pct`, so one helper can make any percentage discount.
- Cohesion
- How well the things inside one piece of code belong together. A function that only works out shipping has high cohesion, and one that prices, ships, saves and emails has low cohesion.
- Command
- A pattern that turns an action into an object that knows how to do it (`Run`) and reverse it (`Undo`). Stored on an undo stack, commands let the cart page offer an Undo button.
- Composite
- A pattern where a single item and a group of items answer the same method, and the group asks each part and adds up the answers. A gift `Bundle` and a `Line` both have `Price()`, so bundles can nest.
- Composition
- Building a value from other values it holds and hands work to ("has-a"). A `Product` with a pricing part and a wrapping part is composed, so new behavior is a new part instead of a new type.
- Composition root
- The one place, usually `main`, that builds the real parts and hands them to the code that needs them. For example, `main.go` creates the repo, bus and clock and wires them into `OrderService`.
- Constructor function
- A plain function, named like `NewOrderLog`, that builds and returns a ready-to-use value. Go has no constructors, so this is the convention; it is where dependencies are passed in.
- Constructor injection
- Passing a value its dependencies as arguments to its constructor function (`NewOrderLog`), so it keeps them for its whole life instead of making them itself.
- Copy-paste programming
- Repeating the same code in many places instead of writing one shared function. A bug fixed in one copy then keeps happening in the others.
- Coupling
- How much one piece of code depends on the details of another. If shipping code reaches inside discount code, changing one may break the other, so you want loose coupling.
- Creational pattern
- A pattern about how values get made, moving the "which type, with which settings?" decision into one place. Factory and Builder are examples.
D
- Decorator
- A wrapper with the same interface as the object it wraps; it does a little extra work (such as logging) and passes the call on. Because the interface is unchanged, decorators can stack.
- defer
- A Go keyword that schedules a call to run when the surrounding function ends, such as `defer f.Close()` right after `os.Open`. It works like a template method because the closing step is fixed and always runs.
- Delegation
- Handing a job to a part you hold. `Product.Total` delegates to its pricing part and its wrapping part, then adds their answers.
- Dependency
- Anything code needs to do its job, such as a database, a notifier or the clock. The old `placeOrder` fetched all of its dependencies itself.
- Dependency injection
- Giving code the dependencies it needs, usually as arguments, instead of letting it find or make them. This lets tests pass a fake notifier and a fixed clock, so they need no disk or email.
- Dependency inversion principle (DIP)
- The SOLID principle that high-level code (order rules) shouldn't depend on low-level details (printing, mail servers). Both depend on an interface, and you pass the detail in.
- Design pattern
- A named, reusable solution to a common design problem. It isn't a library or code to copy but a shape for your code, and the name lets a team describe a whole design briefly.
- DI container
- A library that builds objects from a list of rules. Go programs rarely need one, because plain constructor calls in `main` stay readable.
E
- Easy to change
- The goal of design: when the business changes, the change touches one small, obvious place and nothing else breaks. Loose coupling and high cohesion get you there.
- Embedding
- Listing a type inside a struct with no field name so the outer type gets its fields and methods promoted. It is Go's nearest thing to inheritance, but the inner type's methods can't be overridden from outside.
- Error value
- Go's way to report an ordinary failure: a function returns an `error` as its last result, and the caller checks it. Go keeps `panic` for programmer mistakes.
- Event
- Something that happens, announced by name so listeners can react, such as `"order_placed"`. The code that announces it doesn't know who listens.
- Event bus
- The subject in the observer pattern: a value that keeps listeners under event names and calls each one when `Emit` is called. The order code announces "order_placed" without knowing who listens.
F
- Facade
- One simple function or type in front of several parts, so callers make a single call. `checkout` prices, quotes shipping and saves, so callers don't repeat those steps.
- Factory method
- A pattern where the code that uses a part lets something else decide which object to make. Because Go has no subclasses, a function field plays that role, as in `Shipment{makeCarrier: ...}`.
- Fake
- A simple working stand-in for a real part, such as the in-memory `MemoryRepo` or a notifier that keeps its messages in a slice. Tests use fakes to avoid touching the disk or sending email.
- Fixture
- The setup a test needs, built fresh for each test. In Go a helper such as `newService(t)` can play this part, so no test sees another's orders.
- Fragile base class
- The problem where changing an inner type quietly breaks every outer type that embeds it. Adding sales tax to `Product.Total` would wrongly tax wholesale products too.
- Framework
- Code that runs your program and calls your code when needed. `go test` is a framework because it finds and calls your `TestXxx` functions.
- Function literal
- An unnamed function written in place, such as `func(a, b Order) int {...}`. It can be stored in a variable or passed to another function like `slices.SortFunc`.
- Function type
- A named type whose values are functions of a given shape, such as `type Discount func(subtotal float64) float64`. Any function of that shape can be stored in a field or passed around.
G
- Gang of Four
- The nickname of the four authors of the 1994 book *Design Patterns*, which named 23 patterns in three families.
- Global mutable state
- Data at package level that any code can change. A shared `FreeShippingAt` setting changed by one test makes later tests see the new value, so results depend on test order.
- go test
- The Go command that finds every `TestXxx(t *testing.T)` function in files ending `_test.go` and runs them. `./...` means every package below the current folder.
- go.mod
- The file that marks the root of a Go module and names it (for example `module kettle`). Commands like `go test` must be run from a folder containing or below it.
- God object
- One type or package that does far too much, such as a `Shop` with 40 methods for pricing, stock and email. The fix is to split it by reason to change.
- Golden hammer
- Using one favorite tool for every problem, such as an interface or a factory for everything. Pick the simplest tool that fits each problem instead.
- Goroutine
- A function running concurrently with others in Go. They matter for singletons because `sync.Once` keeps a singleton safe even when several goroutines ask for it at once.
H
- Handler
- One link in a chain of responsibility: it deals with a request or passes it on. In `net/http`, a handler is the code that answers a web request, such as `listOrders`.
- Has-a / is-a
- The two ways to relate types. "Is a" is inheritance (a promo card is a gift card; Go has none), and "has a" is composition (a product has a pricing rule). If the answer is "has a", compose.
- Hook
- The step a template method leaves for the caller to supply. In Go the simplest hook is a function passed in, such as `formatRow` in `makeReport`.
- httptest
- A standard-library package for testing web handlers without a real network. It lets you send a fake request to a handler and read the recorded response.
I
- Implicit satisfaction
- A Go type implements an interface just by having its methods, with no `implements` written anywhere. The compiler checks it, so a missing method is a build error.
- Inheritance
- A way to build a type by extending another ("is a"). Go has no inheritance; embedding is its nearest thing, and Go chose composition on purpose.
- Injected clock
- A function passed in that returns the time (`func() time.Time`), so a test can pass one that always says 4:00 p.m. You pass `time.Now` without brackets, not `time.Now()`.
- Interface
- The set of methods that code expects a value to have, whatever the concrete type. In Go a type satisfies an interface implicitly, and small interfaces defined where they are used work best.
- Interface segregation principle (ISP)
- The SOLID principle that code shouldn't depend on methods it doesn't use. Keep interfaces small, such as separate `Quoter` and `Tracker`, so a simple carrier needs no fake methods.
- Inversion of control
- A framework calling your code instead of your code calling it. `go test` calls your tests, and `net/http` calls the handlers you registered.
- Iterator
- A way to step through a collection one item at a time without showing how it is stored. Every `for range` loop uses one, and since Go 1.23 an `iter.Seq` is a function that calls `yield` once per item.
J
- JSON
- A text format for storing structured data. The old module wrote its orders to `orders.json` using `json.MarshalIndent` for readable output.
K
- KISS
- "Keep it simple": of two designs that both work, choose the one that's easier to read.
L
- Library
- A set of tools your code calls, so your code stays in charge. `sort.Slice` and `fmt.Println` are examples.
- Liskov substitution principle (LSP)
- The SOLID principle that anything fitting a type must work wherever that type works. A `LockedCard` that panics in `TopUp` breaks the promise of the `Card` interface.
- Listener
- A function called when its event is emitted. For "order_placed", `sendEmail` and `logSale` are listeners.
M
- Magic number
- A number in code with no name to say what it means, such as `75` and `0.85` in the old `placeOrder`. Give it a named constant like `freeShippingAt`.
- Method chaining
- Calling methods in a row, each returning the same pointer so the next call can follow on. `OrderBuilder` uses it: `NewOrderBuilder().ForCustomer(ana).Add(...).Build()`.
- Middleware
- Code every web request passes through as a chain, such as logging or login checks, each able to stop the request. In Go it is written `func(http.Handler) http.Handler`, and it acts as a decorator.
- Mock
- A test stand-in that also records how it was called so the test can check it. It differs from a plain fake, which only stands in for a real part.
N
- net/http
- Go's standard-library package for web servers. A mux (`http.NewServeMux`) keeps a registry from request patterns such as `GET /orders` to handlers and calls them when requests arrive.
O
- Observer
- A pattern where the code that something happens in (the subject) keeps listeners and calls each one when the event occurs. New reactions, such as Alex's packing slip, are added without touching the emitting code.
- Open/closed principle (OCP)
- The SOLID principle that code should be open for extension but closed for modification. You add behavior with new code, such as a new discount type, instead of editing code that already works.
- Over-engineering
- Building more structure than the problem needs, such as an interface, factory and registry for a single discount.
P
- Panic
- A crash that stops the program, which Go keeps for programmer mistakes; other failures return an `error`. Writing to a nil map, or the locked card's `TopUp`, panics.
- Plugin
- Code a framework runs for you that adds a feature without changing the framework, such as a database driver that registers itself on import. It is the open/closed principle applied to a whole tool.
- Pointer receiver
- A method declared on a pointer type, like `func (b *OrderBuilder) Add(...)`, so the call changes the original value instead of a copy. It suits builders, repositories and the event bus, which must keep their changes.
- Premature abstraction
- Adding an interface or factory before you have two or three real cases. It guesses what will vary, and a wrong guess is harder to undo than plain code.
- Prototype
- A pattern that makes new values by copying a ready-made one and changing a little. In Go, assigning a struct copies it, so Bloom Café's weekly template can be copied and tweaked into a holiday order.
- Proxy
- A wrapper with the same interface as the real object that controls access to it. It might create the object only when needed, check permissions or cache answers.
- Publish/subscribe
- Another name for the observer pattern: the subject publishes events and listeners subscribe to them, with a message system between sender and receiver.
R
- Registry
- A table from names to values or functions, looked up when needed. The `carriers` map and a web mux's pattern-to-handler table are registries.
- Repository
- A type that stores and finds things so nothing else knows how they are stored. `MemoryRepo` keeps orders in a slice, and a `SqliteRepo` (SQLite is a small single-file database) or `JsonRepo` with the same methods could replace it.
- Rule of three
- The first time, just write the code; the second time, notice the repeat; the third time, extract the shared part. By then you know what really varies.
S
- Service locator
- A global registry that code reaches into to fetch its dependencies, such as `registry["repo"]`. It hides the dependencies again and forces tests to change the global, so injection is preferred.
- Shallow copy
- A copy that duplicates a struct's own fields but still shares any slice or map inside it. Copy those by hand with `slices.Clone` or `maps.Clone`, or a change to the copy alters the original's items.
- Simple factory
- One function that knows every type and returns the right one for a name. `createCarrier("ups")` looks the name up in a map of maker functions and returns a ready carrier, or an error for an unknown name.
- Single responsibility principle (SRP)
- The SOLID principle that a piece of code should have one reason to change. Pulling `priceItems` and `applyDiscount` out of `placeOrder` is an example.
- Singleton
- A type that allows only one instance and hands everyone that same instance. In Go a package-level variable built once with `sync.Once` does the job, but changeable shared values become global state.
- SKU
- A product's code in the shop's stock list, such as `ESP-5LB` or `MUG-BLUE`. It is the first field of an `Item`.
- slices.Clone
- A standard-library function that returns a new slice with the same elements (`maps.Clone` does the same for maps). It lets a repository's `All()` return a copy that callers can't damage.
- SOLID
- The best-known set of five design principles, named by their first letters: single responsibility, open/closed, Liskov substitution, interface segregation and dependency inversion. They are guides, not laws.
- Spaghetti code
- Code so tangled with ifs, globals and jumps that you can't follow one path through it. Small one-job functions, Strategy and State help.
- State
- A pattern for things whose allowed actions depend on their status. In its lightest form it is a transitions map plus one `moveTo` function; the textbook form makes each state a type with the same methods.
- State machine
- Something that is always in exactly one of a fixed set of states, with rules for moving between them. An order goes placed, paid, shipped, delivered, and can be cancelled only before it ships.
- Strategy
- One interchangeable way of doing a job, where all strategies have the same shape so the user doesn't care which it gets. In Go it is usually a function, such as a `Discount` chosen by `discountFor`.
- Structural pattern
- A pattern about how objects fit together: connecting pieces not made for each other, or wrapping one object in another. Adapter and Decorator are examples.
- Stub
- A test stand-in that returns fixed answers, such as a clock that always says 4:00 p.m.
- Subject
- In the observer pattern, the object whose events listeners subscribe to; it keeps the listeners and calls them. An `EventBus` is an example of a subject.
- sync.Once
- A Go standard-library type whose `Do` method runs a function the first time it's called and never again, even with several goroutines. It builds a singleton on first use.
T
- t.Helper()
- Testing helpers on `*testing.T`. `t.Helper()` makes a failure point at the calling test instead of the helper, and `t.TempDir()` gives a temporary folder that is cleaned up after the test.
- Table-driven test
- A Go test that lists inputs and expected outputs in a slice of structs and loops over them. `TestSameTotalsAsBefore` has one row each for Bloom, Ana and Cy.
- Template method
- A pattern that fixes a job's steps in one place and leaves one step, the hook, for the caller to supply. In Go the hook is usually a function passed in, as with `formatRow` in `makeReport`.
- Transition
- An allowed move from one state to another, such as paid to shipped. A transitions map lists the legal moves for each state.
- Tree
- A structure of items containing smaller items, like bundles inside bundles, down to single lines. Composite data forms a tree.
- Type explosion
- A new type for every mix of choices, so the number of types multiplies: two yes/no choices make 4 types and three make 8. Composition avoids it by making each choice a part.
U
- Undo stack
- A slice of commands already run, with the newest last. Undo takes the last one off and reverses it.
W
- Wrapper
- A value that holds another and stands in front of it. Adapters, decorators and proxies are all kinds of wrapper.
Y
- YAGNI
- "You aren't gonna need it": don't build for a future need until it's real. Most guessed needs never come, or come in a different shape.