Week 7 Lesson
DRY, KISS, YAGNI, and Naming
Simple design is not lazy design. It is disciplined design.
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
// 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>;
}
}class OverdueTaskFinder {
findOverdue(tasks: Task[], today: Date): Task[] {
return tasks.filter(task => !task.completed && task.dueDate < today);
}
}Lab: Clarity Refactor
Scenario: You receive code with vague names, duplicated conditions, and several unnecessary abstractions.
Steps
- Rename variables and methods to reveal intent.
- Identify duplicated knowledge vs harmless similar code.
- Remove one abstraction that does not serve a requirement.
- 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.