Week 7 Lesson

DRY, KISS, YAGNI, and Naming

Simple design is not lazy design. It is disciplined design.

DRYKISSYAGNIpremature abstractionintent-revealing nameleast surprise

Learning Objectives

  • Apply DRY without creating harmful abstractions.
  • Use KISS and YAGNI to avoid overengineering.
  • Improve names so code communicates intent.
  • Recognize when duplication is cheaper than premature abstraction.

Lecture Notes

Students often hear “Don’t Repeat Yourself” and immediately remove every piece of similar-looking code. DRY is really about duplicated knowledge. If the tax rate appears in ten files, that is dangerous duplicated knowledge. If two screens happen to have similar button code but are changing for different reasons, forcing them into one abstraction may create coupling that hurts more than it helps.

KISS means keep it simple. Simple does not mean careless. A simple design has fewer moving parts, clearer names, and fewer hidden assumptions. Complexity should be earned. Add complexity when a real requirement demands it, not because the developer wants to show off a pattern, framework, or clever trick.

YAGNI means You Aren’t Gonna Need It. It warns against building future features too early. A developer might create a plugin system, event bus, abstract factory, and microservice boundary for a class project that only needs a local task list. That design may sound professional, but if it slows understanding and adds no real value, it is overengineering.

Naming is one of the cheapest and most powerful design tools. Names such as data, handle, process, manager, and thing usually hide meaning. Better names tell the reader what role something plays: OverdueTaskFinder, PaymentReceipt, CourseEnrollmentPolicy, InventoryReorderService. A good name reduces the need to inspect implementation details.

The Principle of Least Surprise means code should behave the way a reasonable developer expects. If a method named getUser also creates a user, sends an email, and charges a card, the name lies. Design is not just structure; it is communication.

Worked Example: Avoiding premature abstraction

Before
// Over-abstracted before the app needs it
interface UniversalProcessor<TInput, TOutput> {
  execute(input: TInput): Promise<TOutput>;
}

class AbstractTaskPipelineFactoryManager {
  create(): UniversalProcessor<any, any> {
    // nobody understands this yet
    return {} as UniversalProcessor<any, any>;
  }
}
After / Better
class OverdueTaskFinder {
  findOverdue(tasks: Task[], today: Date): Task[] {
    return tasks.filter(task => !task.completed && task.dueDate < today);
  }
}
Design lesson: The second design is small and clear. It solves the actual current problem and can be refactored later if real variation appears.

Lab: Clarity Refactor

Scenario: You receive code with vague names, duplicated conditions, and several unnecessary abstractions.

Steps

  1. Rename variables and methods to reveal intent.
  2. Identify duplicated knowledge vs harmless similar code.
  3. Remove one abstraction that does not serve a requirement.
  4. Write a short explanation of how the code became easier to read.

Deliverables

  • Before/after code
  • Naming improvements list
  • Removed overengineering note

Assignment

Take a small program you wrote before. Rename at least ten items and remove or simplify one unnecessary abstraction. Submit a reflection.

Discussion Prompts

  • Can DRY go too far?
  • What makes a name honest?
  • Why do developers overengineer?

Week 7 Quiz

Use these as quick checks after the lesson.

Question 1

DRY is mostly about avoiding duplicated:

Question 2

YAGNI warns against:

Question 3

KISS means:

Question 4

A name like processData is weak because:

Question 5

Premature abstraction can:

Student Notes

Saved in this browser only.