SMALLTALK BEST PRACTICE PATTERNS

The Complete Developer Guide Based on

Kent Beck’s Classic 1996 Book

92 Patterns for Writing Clean, Readable, and Maintainable Object-Oriented Code

What Is Smalltalk Best Practice Patterns? A Developer’s Overview

Published in 1996, Smalltalk Best Practice Patterns by Kent Beck remains one of the most influential books ever written on low-level object-oriented design. While the title names Smalltalk, experienced developers across Java, Ruby, Python, JavaScript, and C# consistently cite it as essential reading precisely because its insights transcend any single language. Beck himself frames it simply: this is a book about the small things experienced, successful Smalltalk programmers do that beginners do not.

The book codifies 92 patterns — not architectural patterns in the GoF sense, but tactical, everyday decisions: how to name a method, when to decompose a conditional, how to represent state, when to use a collection idiom. Each pattern follows a consistent format: the problem, the forces in tension, and the solution. Together they form a system, a language for thinking clearly about code at the line-by-line level.

“The bottlenecks throughout development come from the limitations in human communication. When you program, you have to think about how someone will read your code, not just how a computer will interpret it.”

— Kent Beck, Smalltalk Best Practice Patterns

Who Should Read This Book
•  Smalltalk developers seeking a definitive style guide for professional-quality code
•  Java, Python, Ruby, or JavaScript developers who want to think more clearly in objects
•  Anyone who has read Refactoring by Martin Fowler and wants the underlying pattern vocabulary
•  Senior developers who want names and frameworks for things they explain from intuition
•  Engineering leads, teachers, and code reviewers who mentor others on OOP craft

1. Why Patterns? The Philosophy Behind the Book

Beck opens with a foundational claim: most software projects fail not for lack of architectural vision, but for the accumulation of small decisions made poorly. Every poorly named variable, every method that does three things, every conditional that could have been a message — these compound into codebases that resist change and defeat understanding.

Patterns are his answer. Not rules to memorize, but distilled wisdom that captures both the practice and the reasoning behind it. Each pattern in the book answers three questions: what problem are you facing, what are the competing forces (readability vs. performance, simplicity vs. extensibility), and what is the best solution given those forces.

“Most patterns are designed to preserve a balance between short-term and long-term needs.”

— Kent Beck

Beck draws a sharp distinction between this book and design-pattern books. Design patterns (like GoF) address the relationships between families of objects. This book addresses implementation patterns — the daily tactics of programming. Both are necessary. This book handles the level most developers work at most of the time.

2. Method Patterns: The Heart of the Book

Chapter 3 is the densest and most important section of the book, presenting 30 patterns for how methods should be written and organized. Beck’s central thesis here is that behavior is more important than state in object-oriented systems. Getting behavior right — through clean, communicative methods — is the primary craft of OOP.

Composed Method

The foundational pattern of the entire book. A method should do exactly one thing, and every line of the method should operate at the same level of abstraction. If a method is doing several things, decompose it into sub-methods, each named for its intention.

” Before: one method doing many things “processOrder self validateItems. total := 0. items do: [:each | total := total + each price]. discount := total > 100 ifTrue: [total * 0.1] ifFalse: [0]. self submitWithTotal: total – discount. ” After: Composed Method “processOrder self validateItems. self submitWithTotal: self discountedTotal. discountedTotal ^ self subtotal – self discount.

“Divide your program into methods that perform one identifiable task. Keep all of the operations in a method at the same level of abstraction.”

— Kent Beck

Intention Revealing Selector

Name your methods after what they accomplish for the caller, not how they accomplish it. The name should communicate intent so clearly that reading the call site requires no mental translation.

” Poor: reveals implementation “sortByBubbleiterateAndCompareAdjacentElements ” Better: reveals intention “sortByNamefindOldestCustomercalculateMonthlyRevenue

Query Method

Methods that test a condition and return a Boolean should be named with a form of “be” — is, was, will, can, has. This makes their use at call sites read as natural English and immediately communicates their purpose without comments.

isActive ^ status = #active hasOutstandingBalance ^ balance > 0 canReceiveMessages ^ self isActive & self hasValidEmail

Executing Message

When a method needs to express a choice between alternatives, use a message send rather than a conditional. This keeps each alternative in its own method and allows new alternatives to be added later simply by defining a new class — without touching existing code.

” Instead of: “display type = #circle ifTrue: [self drawCircle]. type = #square ifTrue: [self drawSquare]. ” Prefer: “display self shape display.

Other Key Method Patterns

• Method Object — when a method grows too large or uses too many temporary variables, promote it to its own class with #compute

• Guard Clause — return early from a method when preconditions fail, instead of nesting all logic in conditionals

• Interesting Return Value — return a meaningful result from methods that modify state, so callers can chain or use the result

• Around Method — wrap a template behavior with before/after hooks to communicate pre- and post-conditions

• Composed Method + Debug Printing — every object should implement a readable #printOn: for use in debugging

3. Naming Patterns: The Most Undervalued Skill in Programming

Beck devotes substantial attention to naming — of methods, variables, parameters, and classes — because names are the primary interface between code and the human mind. A well-named method requires no comment. A well-named variable makes its purpose obvious at a glance.

Beck’s Core Naming Principles
•  Name variables after the role they play in the computation, not their type
•  Name methods after the intent they fulfill for the caller, not their implementation
•  Use full English words; abbreviations save keystrokes and cost understanding
•  Boolean-returning methods start with is, was, will, can, has, or should
•  Methods that convert objects start with as (e.g., asString, asArray, asFloat)
•  Superclass names are simple and general; subclass names qualify the parent
•  Constructor methods describe the result, not the parameters (e.g., Date today)

“You don’t have to be a programming wizard to pick good names, you just have to have good judgment.”

— Kent Beck

A common mistake Beck identifies: naming a variable after its type (aString, theList) rather than its role (customerName, pendingOrders). The type is already communicated by the class; the name should communicate meaning.

4. State Patterns: Managing Instance Variables with Discipline

Chapter 4 presents 20 patterns for how objects should manage their state — their instance variables and temporary variables. Beck’s guiding principle: state should always be encapsulated behind behavior. Objects communicate through messages, not direct variable access.

Common Instance Variables

Only store values in instance variables that the object needs to remember between messages. Temporary state that is used only within a single method computation belongs in temporary variables, not instance variables.

Lazy Initialization

Delay the initialization of an instance variable until it is first accessed. This avoids the cost of computing values that may never be needed, and it simplifies initialization methods.

preferences preferences isNil ifTrue: [preferences := UserPreferences default]. ^ preferences

Default Value Method

Define a method that returns the default value for a variable. This centralizes defaults, makes them self-documenting, and allows subclasses to override them without changing initialization logic.

defaultTimeout ^ 30 defaultCurrency ^ Currency USD

Other State Patterns

• Temporary Variable — use temporary variables (local to a method) to hold intermediate computation results and communicate intent within the method

• Collecting Temporary Variable — when building up a result through iteration, use a single well-named variable initialized before the loop

• Role Suggesting Temporary Variable Name — name temps after the role they play in the computation, not what they hold

• Explain Temporary Variable — extract a sub-expression into a named temporary variable to explain what it computes

5. Collection Patterns: Mastering Smalltalk’s Most Powerful Feature

Beck dedicates an entire chapter to collections — 27 patterns — because Smalltalk’s collection hierarchy is one of its greatest strengths. The message-based collection API enables expressive, declarative code that communicates intent at a high level. These patterns translate directly to modern languages: Ruby’s Enumerable, JavaScript’s Array methods, Python’s list comprehensions, and Java’s Streams all embody the same ideas.

Core Collection Message Patterns

PatternUse WhenExample (modern equivalent)
do:Iterate over all elements for side effectsforEach() / for…of
collect:Transform every element into a new collectionmap()
select: / reject:Filter elements matching a conditionfilter()
detect:Find the first matching elementfind()
inject:into:Fold a collection into a single valuereduce()
anySatisfy:Test if any element matches a conditionsome()
allSatisfy:Test if all elements match a conditionevery()

Collection Idiom Patterns

• Duplicate Removing Set — use a Set when you need a collection with no duplicates, rather than checking for duplicates manually

• Temporarily Sorted Collection — sort only when you need sorted output; keep the underlying collection unsorted

• Stack — use a Stack (with addLast: / removeLast:) for LIFO access patterns, such as undo stacks or tree traversal

• Queue — use a Queue (addLast: / removeFirst:) for FIFO patterns such as task queues or breadth-first traversal

• Lookup Cache — cache results of expensive computations in a Dictionary to avoid recomputation

• Parsing Stream — use ReadStream to walk through a collection one element at a time during parsing

6. Class Patterns: Choosing Names and Hierarchies

Chapter 6 is brief but high-value: Beck presents two class naming patterns and the principles behind them. Good class names pay dividends throughout the lifetime of a codebase, because the class name is visible everywhere the class is used.

Simple Superclass Name

Give abstract base classes short, evocative, single-word names drawn from the problem domain. The name should communicate what the class represents at the conceptual level. Examples: Collection, Shape, Account, Transaction.

Qualified Subclass Name

Subclass names should qualify their parent. Start with the distinguishing quality, then reference the parent concept. This creates a naming hierarchy that communicates both the relationship and the specialization at a glance.

Collection        ” Simple Superclass Name ” OrderedCollection SortedCollection Set Account           ” Simple Superclass Name ” SavingsAccount   ” Qualified Subclass Name ” CheckingAccount BusinessAccount

7. Formatting Patterns: Code That Reads Like Prose

Beck includes a chapter on formatting conventions that are as important for Smalltalk as code style guides are for any language. His principle: formatting should serve the reader, not the author. The goal is to make the structure of the code visible at a glance.

Beck’s Formatting Principles
•  Inline Message Pattern: write the method signature on a single line when possible
•  Indented Control Flow: indent the bodies of conditionals and loops consistently
•  Rectangular Block: keep block bodies rectangular and visually distinct from surrounding code
•  Guard Clause: handle exceptional cases first and return early, before the main logic
•  Type Suggesting Parameter Name: name parameters after the type they should receive (e.g., aCollection, anInteger)
•  Cascade: use cascades to send multiple messages to the same receiver in sequence
•  Yourself: return self from a cascade to allow the result to be chained or assigned

“The purpose of formatting is not aesthetics. It is communication.”

— Kent Beck

8. All 92 Patterns: Quick Reference by Category

Beck’s book organizes 92 patterns across six categories. Here is a complete reference.

Methods (30 patterns)

• Composed Method — one method, one level of abstraction, one purpose

• Constructor Method — a class-side method that creates and returns a fully initialized instance

• Constructor Parameter Method — a factory method that takes parameters and delegates initialization

• Shortcut Constructor Method — a convenience constructor for the most common initialization case

• Conversion — a method named asX that converts self to another type

• Converter Method — an instance-side conversion method (asString, asArray, etc.)

• Converter Constructor Method — a constructor that accepts the object to be converted

• Query Method — a Boolean-returning method named isX, wasX, canX, hasX

• Comparing Method — =, <, >, hash — implement comparison methods consistently

• Reversing Method — a method that undoes the effect of another (enable / disable)

• Method Object — extract a complex method into its own class

• Execute Around Method — wrap a computation with before/after behavior

• Debug Printing Method — implement printOn: for every class

• Intention Revealing Selector — name methods after their intention, not their implementation

• Intention Revealing Message — send a message whose name explains the intent, even if it only calls one method

• Choosing Message — use polymorphic dispatch instead of a conditional

• Decomposing Message — extract a sub-computation to a separate method for clarity

• Delegation — pass a message on to a component object

• Pluggable Behavior — parameterize behavior using blocks or selectors

• Collecting Parameter — pass a collection to a method to accumulate results

State (20 patterns)

• Instance Variable — a variable that persists across messages

• Class Variable — a variable shared by all instances of a class

• Temporary Variable — a variable local to a single method

• Collecting Temporary Variable — a temporary used to accumulate results in a loop

• Caching Temporary Variable — a temporary that stores the result of an expensive call

• Explaining Temporary Variable — a temporary named to clarify what a complex expression computes

• Reusing Temporary Variable — reuse a temporary for conceptually different values when clearer

• Role Suggesting Instance Variable Name — name variables after their role, not their type

• Common State — put shared state in the superclass

• Variable State — use a Dictionary to hold variable numbers of attributes

• Indirect Variable Access — access all variables through accessor methods

• Direct Variable Access — access variables directly only within the class that owns them

• Getting Method — a method that returns the value of an instance variable

• Setting Method — a method that sets an instance variable

• Collection Accessor Protocol — use add:, remove:, includes: rather than exposing the collection

• Enumeration Method — provide a do: method on any class that holds multiple items

• Boolean Property Setting Method — use beActive / beInactive rather than setActive: true

• Role Suggesting Temporary Variable Name — name temps for what they represent in context

• Default Value Method — a method that returns the default value for a variable

• Lazy Initialization — initialize a variable on first access, not in initialize

Collections (27 patterns)

• Collection — choose the right collection class for the access pattern needed

• OrderedCollection — use when order matters and size varies

• RunArray — use for long sequences of repeated values (efficient encoding)

• Set — use when uniqueness is required

• Equality Method — implement = and hash consistently for objects used in Sets/Dictionaries

• Dictionary — use for key-value lookup

• SortedCollection — use when you need a permanently sorted collection

• Array — use for fixed-size, indexed sequences

• do: — iterate for side effects

• collect: — transform every element

• select: / reject: — filter elements by a condition

• detect: — find the first matching element

• inject:into: — fold a collection to a single value

• Duplicate Removing Set — accumulate unique values

• Temporarily Sorted Collection — sort on demand, store unsorted

• Stack — LIFO access pattern

• Queue — FIFO access pattern

• Searching Literal — use a literal collection for O(1) membership testing

• Lookup Cache — cache expensive lookups in a Dictionary

• Parsing Stream — use ReadStream to parse collections sequentially

• Concatenating Stream — use WriteStream to build strings or collections incrementally

Classes (2 patterns)

• Simple Superclass Name — one short word from the domain

• Qualified Subclass Name — quality + parent concept (SortedCollection, not SortedList)

Formatting (13 patterns)

• Inline Message Pattern — signature on one line

• Type Suggesting Parameter Name — anObject, aCollection, anInteger

• Indented Control Flow — consistent indentation for all control structures

• Rectangular Block — keep block bodies visually rectangular

• Guard Clause — handle exceptions first and return early

• Conditional Expression — use ifTrue:ifFalse: as an expression returning a value

• Simple Enumeration Parameter — name block parameters with a single letter when obvious (each, item)

• Cascade — send multiple messages to the same receiver

• Yourself — return self from a cascade to allow chaining

• Interesting Return Value — return a meaningful result from side-effecting methods when useful

9. Why This Book Still Matters in 2025

Smalltalk Best Practice Patterns was published nearly 30 years ago in a language that never achieved mainstream adoption. Yet it consistently appears on recommended reading lists for Python, Ruby, Java, and JavaScript developers. The reason is that Beck’s patterns operate at a level of abstraction that is genuinely language-independent.

The patterns in this book are the conceptual ancestors of many ideas developers now take for granted: the Single Responsibility Principle, the Law of Demeter, the Tell Don’t Ask principle, the Replace Conditional with Polymorphism refactoring in Martin Fowler’s Refactoring. Beck’s later book Implementation Patterns (2007) is essentially a Java-era restatement of the same ideas.

What Beck’s Patterns Influenced
•  Extreme Programming (XP): Beck’s later methodology grew directly from these low-level coding values
•  Test-Driven Development: the discipline of clean, testable methods comes directly from Composed Method
•  Refactoring (Fowler): many catalog entries reflect patterns named here first
•  Clean Code (Martin): the naming and method-decomposition principles echo Beck throughout
•  Modern language APIs: Ruby’s Enumerable, JavaScript’s Array methods, Python’s itertools all embody these collection patterns

“This book covers so many good habits and patterns that are universal to OOP that it’s worth it. Everything Beck said about naming, class design, method decomposition, and the way to think about problems applies in any modern language.”

— Goodreads reviewer, 2024

Further Reading & Resources

To go deeper into the ideas Beck introduced in this book, explore these highly recommended resources:

Smalltalk Best Practice Patterns on Amazon — The book itself. Prentice Hall, 1996.

O’Reilly Library: Smalltalk Best Practice Patterns — Digital access via O’Reilly Learning.

Blinkist Summary — Key ideas from the book in 15 minutes.

JavaScript Implementations on GitHub — Community project converting all 92 patterns to JavaScript.

Implementation Patterns by Kent Beck (Amazon) — Beck’s 2007 Java-era restatement of the same ideas.

Refactoring by Martin Fowler — The natural companion volume; shares deep conceptual roots.

Goodreads Reviews: Smalltalk Best Practice Patterns — See how developers across languages describe its impact.

Write code for the person who reads it next.

That’s what all 92 patterns are for.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *