Skip to main content

Programming, Software Craftsmanship

SOLID, DRY, KISS, YAGNI: Design Principles

·

DRY, KISS, YAGNI and SOLID software design principles shown as labeled acronym tiles

Software developers compress hard-won design lessons into short acronyms: SOLID, DRY, KISS, and YAGNI. These four name the rules that decide whether a codebase stays editable or rots into something nobody wants to touch. This guide explains each principle, shows it in Python, Java, and JavaScript, and marks where two principles collide so you know which one wins.

DRY, KISS, YAGNI and SOLID software design principles shown as labeled acronym tiles

Most of these terms describe one idea: change the code in one place, not ten. A class with a single job, a function that exists once, a feature you build only when the requirement is real.

DRY: Don't Repeat Yourself

DRY states that every piece of knowledge in a system has one authoritative representation. Andy Hunt and Dave Thomas named it in The Pragmatic Programmer in 1999. The point is not "never type the same characters twice"; the point is that when a rule changes, you change it in exactly one place.

Beginners print a multiplication table by writing one line per row:

print(7 * 1)
print(7 * 2)
print(7 * 3)
print(7 * 4)
print(7 * 5)
# ...and so on, ten lines for ten rows

Extend that table to 100 rows and you add 90 more lines. A loop collapses all of them into one statement that scales to any count:

for i in range(1, 11):
    print(7 * i)

The fix is structural, not cosmetic. Change the multiplier from 7 to 9 and you edit one literal instead of hunting through ten print calls. That single edit point is the whole value of DRY.

Where duplication hides

Repeated logic shows up in three places that scanning for identical lines misses:

  • Duplicated comments. A comment that restates what the code does duplicates the logic in prose. Change the code and the comment drifts out of date, so it lies to the next reader. Rename the variable or function until the code reads clearly, then delete the comment.
  • Duplicated data. Four near-identical branches for North, East, South, and West each hold the same movement rule. Pass the direction as a parameter and the rule lives in one move(direction) function instead of four copies.
  • Duplicated algorithms. Three functions that visit Hotel A, Hotel B, and Hotel C, each calling eat(), sleep(), and dance(), share one routine. Extract it.

That last case, in Java:

public void visitHotel(Hotel hotel) {
    eat(hotel);
    sleep(hotel);
    dance(hotel);
}

Now one method drives every hotel visit, and a change to the routine touches one place.

The opposite of DRY is WET, expanded as Write Everything Twice or We Enjoy Typing. The joke makes the cost obvious: every copy is one more place a bug can hide and one more edit you owe future-you.

KISS: Keep It Simple, Stupid

KISS says the simplest design that solves the problem is the right one. Kelly Johnson, an aeronautical engineer at Lockheed, coined the phrase. He demanded that a fighter plane be repairable in the field by an average mechanic with basic tools, because a design too clever to fix is a design that fails when it matters.

Code carries the same risk. The next person to read your function might be a teammate, a grader, or you in six months with no memory of why you wrote it. Antoine de Saint-Exupéry framed the target precisely:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.

Four habits keep complexity down:

  1. Name variables and functions for what they hold or do, so the name carries the explanation.
  2. Give each class one job, so its behavior fits in your head.
  3. Write a comment only when the code cannot explain itself, not as a default.
  4. Delete dead branches, unused parameters, and algorithms no path reaches.

Here is a four-line conditional that sets a label color, written in JavaScript:

if (isSuccess) {
    label.style.color = 'blue';
} else {
    label.style.color = 'red';
}

A ternary expresses the same logic in one readable line:

label.style.color = isSuccess ? 'blue' : 'red';

KISS has a limit. Ternaries that nest two or three deep are harder to read than the if block they replace, so simplicity is the goal, not brevity for its own sake. In the example above, one short expression beats four lines. Stack three ternaries and the four-line version wins.

YAGNI: You Aren't Gonna Need It

YAGNI says build the feature the current requirement asks for, and nothing you only predict you will need. Ron Jeffries, a founder of Extreme Programming, stated it directly: always implement things when you actually need them, never when you just foresee that you need them.

Speculative code is expensive in three ways. You spend time writing it now, you spend time testing it, and every later reader spends time understanding code that no path executes. Most predicted requirements never arrive, so that investment returns nothing.

Concrete cases where YAGNI applies:

  • The task asks you to validate the email and password fields. Validating the name field too, because a form might add it later, is speculative work. Skip it until the requirement is real.
  • A health app links active hospital databases. Writing logic for hospitals that closed years ago handles a case the data never produces.
  • One concrete case rarely justifies an abstract base class. Build the single class, and extract an interface only when a second real case appears.
  • An if/else whose else branch never runs in any tested scenario is a branch you can delete.

Developers break YAGNI for understandable reasons: an incomplete picture of the business, pressure to plan for situations that never occur, or a genuine case where changing the code later is costly enough to justify building ahead. The skill is telling a real future need from an imagined one.

SOLID: five rules for object-oriented design

SOLID bundles five principles that keep classes easy to extend and change. Robert C. Martin, known as Uncle Bob, assembled them, and Michael Feathers arranged the names into the acronym. Each letter targets a specific way that object-oriented code rots.

| Letter | Principle | Core rule | | --- | --- | --- | | S | Single Responsibility | A class has one reason to change. | | O | Open/Closed | Open for extension, closed for modification. | | L | Liskov Substitution | A subtype works anywhere its base type works. | | I | Interface Segregation | Many small interfaces beat one large one. | | D | Dependency Inversion | Depend on abstractions, not concrete classes. |

Single Responsibility Principle (SRP)

A class should have one reason to change. A class that formats a report and also saves it to disk has two reasons: a change to the layout and a change to the storage format both force edits to the same file. Split them. The formatter owns layout; a separate writer owns persistence.

Open/Closed Principle (OCP)

Code is open for extension and closed for modification. You add behavior by writing new code, not by editing code that already works and ships. A payment processor that grows a new if branch for each payment method violates OCP; one that accepts a PaymentMethod interface and gains support for a new method by adding a class follows it.

from abc import ABC, abstractmethod

class PaymentMethod(ABC):
    @abstractmethod
    def pay(self, amount: float) -> None: ...

class CardPayment(PaymentMethod):
    def pay(self, amount: float) -> None:
        print(f"Charged {amount} to card")

class WalletPayment(PaymentMethod):
    def pay(self, amount: float) -> None:
        print(f"Debited {amount} from wallet")

def checkout(method: PaymentMethod, amount: float) -> None:
    method.pay(amount)  # new methods need no edit here

Liskov Substitution Principle (LSP)

Any subclass must work wherever its parent type is expected, without surprising the caller. The classic counterexample is a Square that inherits from Rectangle: code that sets width and height independently breaks when handed a square, because a square forces both sides equal. The subtype violated a guarantee the base type made.

Interface Segregation Principle (ISP)

No client should depend on methods it never calls. A single Machine interface with print, scan, and fax forces a basic printer to implement fax it does not have. Split it into Printer, Scanner, and Fax, and each device implements only what it does.

Dependency Inversion Principle (DIP)

High-level modules depend on abstractions, not on concrete low-level classes. An order service that constructs a MySQLDatabase directly is welded to MySQL. Have it accept a Database interface, and you can swap in PostgreSQL or a test double without touching the service:

interface Database {
    void save(Order order);
}

class OrderService {
    private final Database db;          // depends on the abstraction
    OrderService(Database db) { this.db = db; }
    void place(Order order) { db.save(order); }
}

SOLID code reads clearly, survives changes by other developers, reuses cleanly, and tests well under an automated suite. For a deeper treatment with one worked example per letter, read our companion post on the SOLID principles of object-oriented design.

When principles collide

The four principles pull against each other, and knowing which one yields is the mark of an experienced developer. The conflicts are predictable.

  • DRY versus KISS. Removing a duplication sometimes costs more complexity than the duplication itself. Two three-line blocks that look alike but encode different rules are cheaper left apart than merged behind a parameter-heavy function with three flags. KISS sets the ceiling on how hard you push DRY.
  • DRY versus YAGNI. Building a generic, configurable helper to avoid a duplication you predict for later is speculative. Write the second copy when the second case is real, then extract. The rule of three says wait for the third occurrence before abstracting.
  • OCP versus YAGNI. Designing every class for extension points you might use someday produces abstraction nobody needs. Keep it concrete until a real second case forces the extension.

The resolution is the same each time: solve the problem in front of you with the simplest code that works, and refactor toward a principle when a second concrete case proves the abstraction earns its cost.

The secondary acronyms

Beyond the core four, several acronyms describe process, data, and design discipline. They appear in code reviews and planning meetings rather than in the structure of a single function.

Separation of Concerns (SoC)

Each part of a program handles one distinct job, and the parts stay independent. Edsger Dijkstra named the idea in his 1974 essay, calling it the only available technique he knew for ordering one's thoughts. In practice, SoC drives the layered architecture most applications use: a data-access layer, a business-logic layer, and a presentation layer, each changeable without breaking the others. SoC is the architectural cousin of the Single Responsibility Principle, applied to modules and layers instead of single classes.

Minimum Viable Product (MVP)

An MVP is the smallest working version of a product that delivers core value and collects real feedback. Frank Robinson coined the term in 2001, and Steve Blank and Eric Ries made it standard startup vocabulary. An MVP differs from a prototype: a prototype tests an idea and is often thrown away, while an MVP is a usable product that ships to early users and earns data on what to build next.

Proof of Concept (PoC)

A PoC answers one question before any product gets built: is this idea feasible at all? It is a demo or document that shows a single risky assumption can work, usually for internal stakeholders or a single decision-maker. The order runs PoC, then prototype, then MVP, then full product, with each stage reducing a different risk.

GIGO: Garbage In, Garbage Out

GIGO states that a program's output is only as good as its input. Feed inaccurate data in and you get inaccurate results out, no matter how correct the code is. George Fuechsel, an IBM programmer and instructor, is credited with popularizing the phrase. GIGO is why input validation, data cleaning, and sanity checks earn their place in production code.

Proof of Concept pamphlet handed over by a pizza shop owner as an analogy for software feasibility demos

DIE: Duplication Is Evil

DIE restates DRY with a sharper edge, focused entirely on the costs of copied code. Each duplicate multiplies the work of a bug fix, since you patch the same defect in every copy, and it invites logical contradictions when copies drift apart. Duplication takes four forms worth recognizing:

  • Imposed duplication. The framework or constraint leaves no clean alternative.
  • Inadvertent duplication. The developer does not notice that two fields encode the same concept.
  • Impatient duplication. A copy-paste shortcut taken to save a few minutes.
  • Inter-developer duplication. Two people, or one person across two sessions, solve the same problem twice.

Regular code review and consistent naming conventions catch most of these before they spread.

BDUF: Big Design Up Front

BDUF means completing the full design before any implementation starts. It assumes requirements are known and stable, the design is sound, and problems surface during the design phase. The payoff is predictable budgeting and a clear development path. The cost is rigidity: when a client moves the goalposts, a fully specified design is expensive to change, and validating an untested design is hard until the code exists. Agile methods grew up as a direct reaction to BDUF on projects where requirements shift.

GeeksProgramming illustration of duplicated code blocks marked as defects to avoid

Why these principles matter for your coursework

Graders and interviewers read code for structure, not just correct output. A function that runs but repeats itself, mixes three jobs, or ships features nobody asked for signals a developer who has not internalized these principles. Clean structure is often the difference between a passing grade and a top one, and it is the first thing a technical interviewer probes.

The principles also compound. A class that follows SRP is easier to keep DRY, because its one job lives in one place. Code that respects KISS is easier to keep YAGNI-clean, because there is less speculative machinery to maintain. Learn the four core principles as a system, not as four isolated rules.

If a deadline is closing in and your code works but the structure is tangled, the developers at GeeksProgramming offer computer science homework help that includes a walkthrough of how the solution applies these principles, so you can defend it. We have worked with university students since 2014, across Java, C++, Python, JavaScript, SQL, and more, and you pay half upfront and half after you confirm the code runs. To see how principles turn into recurring solutions, our guide to software design patterns and our list of best practices for software development projects are the natural next reads.

Frequently asked questions

What are the four main software design principles?

The four most cited principles are SOLID, DRY, KISS, and YAGNI. SOLID is a set of five object-oriented design rules from Robert C. Martin. DRY removes duplicated knowledge. KISS favors the plainest design that works. YAGNI blocks features you only think you will need later.

What does SOLID stand for?

SOLID stands for Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. Each letter names one rule for writing classes and modules that stay easy to change. Robert C. Martin, known as Uncle Bob, popularized the set.

What is the difference between DRY and KISS?

DRY targets duplication: each piece of knowledge lives in one place. KISS targets complexity: the design stays as simple as the problem allows. The two conflict when removing a repetition adds an abstraction more complex than the duplication it replaces, and KISS sets the limit on how far DRY goes.

When should I apply YAGNI?

Apply YAGNI whenever you are tempted to build a feature, abstraction, or option because it might be useful one day. Build what the current requirement asks for and nothing more. Speculative code costs time to write, test, and maintain, and most predicted requirements never arrive.

Is DRY ever a bad idea?

Yes. Two pieces of code that look identical today can represent different business rules that diverge tomorrow. Merging them creates a false abstraction that forces unrelated changes through one shared function. DRY applies to duplicated knowledge, not to code that looks the same by coincidence.

Are these principles tied to one language?

No. SOLID, DRY, KISS, and YAGNI describe how to organize logic, so they hold across Java, C++, Python, JavaScript, and SQL. SOLID assumes classes and interfaces, so it reads most naturally in object-oriented code, while the other three apply to any paradigm.

What is Separation of Concerns?

Separation of Concerns is the rule that each part of a program handles one distinct job, so data access, business logic, and presentation stay in separate layers. Edsger Dijkstra named the idea in 1974, and it underpins SOLID by letting you change one concern without breaking the others.

Do I need to memorize every programming acronym?

No. Four principles carry most of the weight in code review and interviews: SOLID, DRY, KISS, and YAGNI. The rest, including SoC, MVP, PoC, and GIGO, describe process and data quality. Learn the four core principles deeply and recognize the rest by name.

SOLID DRY KISS YAGNI software design principles clean code separation of concerns object oriented design
Share: X / Twitter LinkedIn

Related articles

  • Programming

    Performance Metrics in Software Architecture

    Nine performance metrics software architects use to measure coupling, complexity, modularity, and sustainability when designing a software system.

    Feb 8, 2020

  • Case Study

    Autograder Fixed in Under 24 Hours: 100/100

    How our networking expert diagnosed a broken distance vector routing submission, fixed the output formatting bug, and delivered a 100/100 autograder score before the deadline.

    Sep 2, 2025

  • Programming

    Can You Get Caught Using Someone Else's Code?

    Yes, you can get caught. MOSS, JPlag, and Codequiry detect copied code even after renaming variables or restructuring. Here is what actually happens if you are.

    Jul 17, 2025

← All articles

Stuck on a programming assignment?

Get expert help in Java, C++, Python, JavaScript, SQL, and more. We deliver working code with a clear walkthrough so you can understand and defend it.