Test-driven development uses a short cycle: write a test for the next behavior and observe its failure, implement enough to pass it, then refactor without changing the tested behavior. In a conventional implementation-then-test workflow, tests primarily assess code after it has been written; in TDD they also guide each small design increment. Tests accumulate into a regression suite, but passing them is not a universal correctness proof.[ref]
A good candidate is a deterministic priority queue operation with a precise contract. Before implementation, test that inserting two equal values permits two minimum deletions and only then leaves an empty queue. The expected result is objective, cheap to check and useful for finding the duplicate-loss bug in a set-based representation.
An exploratory decision about whether an editor's toolbar feels usable is a poor candidate for TDD alone: the desired behavior and human evaluation criteria may not yet be settled, and an executable assertion does not replace user observation. Prototypes and usability evaluation can establish the design before stable behavioral properties are tested automatically. The distinction is the availability of a useful repeatable test oracle, not a claim that interface software is inherently untestable.
A code smell is an easily noticed feature that suggests a deeper design problem worth investigating. It is neither a proven bug nor an automatic instruction to rewrite the code. Context determines whether the symptom is troublesome.[ref]
Duplicate code can indicate that the same knowledge has several maintenance sites: a correction made to one copy may be forgotten in the other. If the copies represent the same responsibility, extract that responsibility into one shared operation or component. Merely looking similar is insufficient; accidentally similar code with independent purposes should not necessarily be coupled.
Feature envy occurs when an operation depends mainly on another object's data rather than the responsibilities of its own class. For example, an editor view might implement a text-policy decision by repeatedly inspecting document internals. Move that decision to the document, or extract and move the relevant part, so behavior sits with the data and responsibility it actually uses. Duplication suggests consolidating repeated knowledge; feature envy suggests moving a responsibility between objects. These are different design actions, and both can be refactorings that preserve observable behavior.[ref]
The Observer pattern lets interested observers subscribe through a common interface to a subject's events or state changes. The subject notifies registered observers, which perform their own reactions; subscriptions can later be removed. A document model can thereby update multiple editor views without containing explicit knowledge of each view class.
It avoids tightly coupling the subject to every concrete consumer. Adding another view does not require adding a new view-specific call inside core model logic. Notifications should expose a coherent updated state, and unused observers should unsubscribe. The pattern does not itself prevent feedback cycles: observers that update each other's sources can still cause repeated or reentrant notifications. The supplied buttons and containing frame use this subscription-and-reaction design through Scala Swing.
Inside the supplied MainFrame, after both buttons and the label are defined, add:
private var clickCount = BigInt(0)
listenTo(button1, button2)
reactions += {
  case ButtonClicked(source) if (source eq button1) || (source eq button2) =>
    clickCount += 1
    label.text = "Total button clicks: " + clickCount.toString
}
The invariant is that clickCount equals the total number of handled click events from the two buttons. It starts at zero; each matching event increments it exactly once and refreshes the label. The buttons' existing self-listeners can still change their own text independently. Listening to both publishers is necessary: their listenTo(this) calls subscribe each button to itself, not the frame to both buttons. Updating the label is not another button click, so it does not recursively increment the counter. An arbitrary-precision integer keeps the count exact without a lifetime overflow bound.[ref]
The supplied layout already contains the label, so no additional component is needed. Before any click it retains its initial zero-click message; afterwards it displays the cumulative count across both buttons.

Articles by others on the same topic (0)

There are currently no matching articles.