---
title: "04 — Foundational Patterns and Principles — OOP, SOLID, and the MV* Family"
uid: foundational-patterns-and-principles
tags: ["oop", "solid", "mvp", "patterns", "roadmap:software-architect", "mvvm", "design-principles", "mvc"]
excerpt: "Patterns and principles aren't rules to memorize — they're proven separations of concern. Each one draws a line through a system so changing one part doesn't drag another."
date: 2026-08-13T03:27:42+0000
source: https://www.aveshina.my.id/en/blog/foundational-patterns-and-principles
---

Vocabulary to memorize before interviews was how I treated the foundational patterns cluster, and it stayed dead on the page. The model that made it useful: **these are proven separations of concern, not rules** — each one is a way of drawing lines through a system so that changing one part doesn't drag another with it [1]. Once I stopped reciting definitions and started asking "what line does this pattern draw, and why," the whole cluster collapsed into one idea applied at different scales.

Patterns and design principles are the bridge between high-level architecture and practical implementation [1]. They're proven solutions to common problems, and an architect uses them as a shared language to discuss trade-offs without re-deriving everything from scratch.

## OOP: organizing code around objects

Object-oriented programming organizes code around objects that combine data and behavior, using **encapsulation** (bundling data with the code that works on it), **inheritance** (one type building on another), and **polymorphism** (the same name doing different things per type) [2]. The point is to model real-world entities and relationships so related code stays together and reusable. Most enterprise architecture patterns and languages rely on OOP as a foundation — it's the default paradigm of Java, C#, Kotlin, and the .NET stack [2].

The separation OOP enforces is between an object's _interface_ (what it promises to do) and its _implementation_ (how it does it). That separation is what lets one part of a system depend on a contract rather than a concrete detail, and it's the foundation the rest of this post builds on.

## SOLID: five principles for maintainable OOP

SOLID is the five-principle checklist an architect runs when reviewing a design for long-term maintainability [3]:

- **S**ingle Responsibility — a class should have one reason to change.
- **O**pen/Closed — open for extension, closed for modification.
- **L**iskov Substitution — subtypes must be substitutable for their base types without breaking behavior.
- **I**nterface Segregation — many specific interfaces beat one fat interface.
- **D**ependency Inversion — depend on abstractions, not concretions.

Following these leads to code that is easier to extend, test, and maintain as a system grows [3]. The thread connecting all five is the same one OOP draws at a smaller scale: keep parts decoupled by depending on narrow abstractions, not on broad concrete things. When a single class has five responsibilities, a change to one ripples into the other four — SOLID is the discipline of refusing that.

## The MV* family: separating UI from logic

MVC, MVP, and MVVM are patterns for separating an application's **data, logic, and user interface** into distinct layers [4]:

```figure
<svg viewBox="0 0 680 300" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Three UI-separation patterns side by side. Left: MVC — Model, View, Controller, where the controller handles input and updates the model, the model notifies the view. Middle: MVP — Model, View, Presenter, where the presenter holds view logic and talks to the view through an interface. Right: MVVM — Model, View, ViewModel, where the ViewModel binds data to the view automatically.">
  <defs>
    <marker id="p4arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
      <path d="M0,0 L10,5 L0,10 z" fill="#64748b"/>
    </marker>
  </defs>
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- MVC -->
    <text x="110" y="24" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">MVC</text>
    <rect x="40" y="40" width="80" height="40" rx="6" fill="#ccfbf1" stroke="#0d9488" stroke-width="1.5"/>
    <text x="80" y="64" font-size="11" font-weight="700" fill="#134e4a" text-anchor="middle">Model</text>
    <rect x="140" y="40" width="80" height="40" rx="6" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="180" y="64" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">View</text>
    <rect x="90" y="120" width="80" height="40" rx="6" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="130" y="144" font-size="10" font-weight="700" fill="#422006" text-anchor="middle">Controller</text>
    <path d="M80,80 L80,118" fill="none" stroke="#64748b" stroke-width="1.3" marker-end="url(#p4arrow)"/>
    <path d="M180,80 C180,100 150,108 130,118" fill="none" stroke="#64748b" stroke-width="1.3" marker-end="url(#p4arrow)"/>

    <!-- MVP -->
    <text x="340" y="24" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">MVP</text>
    <rect x="270" y="40" width="80" height="40" rx="6" fill="#ccfbf1" stroke="#0d9488" stroke-width="1.5"/>
    <text x="310" y="64" font-size="11" font-weight="700" fill="#134e4a" text-anchor="middle">Model</text>
    <rect x="370" y="40" width="80" height="40" rx="6" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="410" y="64" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">View</text>
    <rect x="320" y="120" width="80" height="40" rx="6" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="360" y="144" font-size="10" font-weight="700" fill="#500724" text-anchor="middle">Presenter</text>
    <path d="M320,80 L320,118" fill="none" stroke="#64748b" stroke-width="1.3" marker-end="url(#p4arrow)"/>
    <path d="M410,80 C410,100 380,108 360,118" fill="none" stroke="#64748b" stroke-width="1.3" marker-end="url(#p4arrow)"/>

    <!-- MVVM -->
    <text x="570" y="24" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">MVVM</text>
    <rect x="500" y="40" width="80" height="40" rx="6" fill="#ccfbf1" stroke="#0d9488" stroke-width="1.5"/>
    <text x="540" y="64" font-size="11" font-weight="700" fill="#134e4a" text-anchor="middle">Model</text>
    <rect x="600" y="40" width="80" height="40" rx="6" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="640" y="64" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">View</text>
    <rect x="550" y="120" width="80" height="40" rx="6" fill="#ede9fe" stroke="#7c3aed" stroke-width="1.5"/>
    <text x="590" y="144" font-size="10" font-weight="700" fill="#4c1d95" text-anchor="middle">ViewModel</text>
    <path d="M590,80 L590,118" fill="none" stroke="#64748b" stroke-width="1.3" marker-end="url(#p4arrow)"/>
    <path d="M610,118 L610,82" fill="none" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3 3" marker-end="url(#p4arrow)"/>

    <text x="340" y="210" font-size="11" fill="#475569" text-anchor="middle" font-style="italic">MVC: controller routes input · MVP: presenter owns view logic · MVVM: ViewModel auto-binds data</text>
    <text x="340" y="232" font-size="10.5" fill="#64748b" text-anchor="middle">the difference is what sits between the View and the Model, and how tightly</text>
  </g>
</svg>
```

- **MVC** (Model-View-Controller) splits responsibilities between model, view, and controller — the controller takes input and updates the model, which notifies the view [4].
- **MVP** (Model-View-Presenter) replaces the controller with a **presenter** that handles view logic, usually talking to the view through an interface so the view stays passive [4].
- **MVVM** (Model-View-ViewModel) introduces a **view model** that binds data to the view automatically — the view subscribes to the view model's properties and updates itself without explicit manipulation [4].

Choosing between them depends on the platform and how much automatic data binding the framework supports. A framework with strong two-way binding (WPF, modern web frameworks) leans MVVM; a framework with thin views leans MVP; the classic web request/response cycle often leans MVC. The pattern is downstream of the platform, not the other way around.

## The single thread

Each of these — OOP, SOLID, the MV* family — is the same idea: **draw a line, depend on the narrow side of it.** OOP draws it between interface and implementation. SOLID polices it at the class level. The MV* family draws it between UI and logic. An architect who internalizes the underlying move (separate concerns, depend on abstractions) can re-derive any specific pattern; one who memorizes the names will misapply them when the platform doesn't match the textbook example.

## How I use this

In design reviews, I don't ask "did you use MVC." I ask "where does input get routed, and does the model know about the view." If the answer reveals tight coupling that violates the intended separation, that's the real issue — the pattern name on the diagram is secondary. SOLID I use as a checklist for specific smells: a class with five responsibilities, a fat interface, a direct dependency on a concrete class where an abstraction would do.

## References

[1] "Patterns and design principles," roadmap.sh — Software Architect. [Online]. Available: [https://roadmap.sh/software-architect/patterns--design-principles](https://roadmap.sh/software-architect/patterns--design-principles)

[2] "Object-oriented programming," Wikipedia. [Online]. Available: [https://en.wikipedia.org/wiki/Object-oriented_programming](https://en.wikipedia.org/wiki/Object-oriented_programming)

[3] Baeldung, "SOLID Principles," [Online]. Available: [https://www.baeldung.com/solid-principles](https://www.baeldung.com/solid-principles)

[4] A. Sinhal, "MVC, MVP and MVVM Design Pattern," Medium. [Online]. Available: [https://medium.com/@ankit.sinhal/mvc-mvp-and-mvvm-design-pattern-6e169567bbad](https://medium.com/@ankit.sinhal/mvc-mvp-and-mvvm-design-pattern-6e169567bbad)

```quiz
Q: What do MVC, MVP, and MVVM all fundamentally do?
- Cache data on the client for performance
- Separate an application's data, logic, and user interface into distinct layers
correct: 1
explain: All three are UI-separation patterns that divide data (Model), UI (View), and the logic between them (Controller/Presenter/ViewModel) so each can change independently.

Q: What is the key difference between MVP and MVC?
- MVP removes the Model entirely
- MVP uses a Presenter that owns view logic, usually via an interface, making the view more passive
correct: 1
explain: In MVP the Presenter handles view logic and talks to the View through an interface, whereas in MVC the Controller routes input and the Model notifies the View directly.

Q: MVVM is best suited to platforms that…
- have strong automatic (often two-way) data binding between a ViewModel and the View
- use only server-side rendering with no client state
correct: 0
explain: MVVM's defining trait is automatic data binding — the View subscribes to the ViewModel and updates itself. Platforms with strong binding (WPF, modern web frameworks) lean MVVM.

Q: The "S" in SOLID stands for Single Responsibility, which means…
- a class should have one reason to change
- a project should have a single architect
correct: 0
explain: Single Responsibility: a class has one reason to change. Multiple responsibilities in one class mean a change to one ripples into the others.

Q: What thread connects OOP, SOLID, and the MV* family?
- They all enforce separation of concerns by depending on narrow abstractions
- They all require a specific programming language
correct: 0
explain: Each draws a line and asks you to depend on the narrow side: OOP separates interface from implementation, SOLID polices it at class level, MV* separates UI from logic.
```
