DEV Community

Cover image for Object-Oriented Programming Is Not About Classes — It’s About Modeling Systems By André Blos Aliatti
André Aliatti
André Aliatti

Posted on

Object-Oriented Programming Is Not About Classes — It’s About Modeling Systems By André Blos Aliatti

Introduction

Many developers learn Object-Oriented Programming by focusing on syntax:

  • class
  • extends
  • implements

But this approach completely misses the real purpose of OOP.

Object-Oriented Programming exists to solve a fundamental software engineering problem:

How do we organize complex systems so they remain understandable and maintainable as they grow?

OOP is not about writing classes.
It is about modeling real-world concepts and responsibilities in software.

When developers skip this conceptual layer, systems quickly become hard to maintain, even if the code compiles and runs.

The Real Goal of OOP: Modeling the Domain

A software system represents a domain.

Examples:

  • a medical clinic system
  • an e-commerce platform
  • a financial management tool

Each domain has:

  • entities
  • behaviors
  • rules
  • constraints

OOP provides a way to represent those concepts and behaviors together.

For example, a medical system might include:

  • Patient
  • Doctor
  • Appointment
  • Prescription But these are not just data containers. They represent objects with responsibilities and behavior.

Bad design:

  • Patient
  • name
  • age
  • cpf

Good design:

Patient

  • registerAppointment()
  • updateAddress()
  • addMedicalRecord()

The difference is subtle but critical:

Objects should own behavior, not just store data.

Encapsulation Protects System Integrity

Encapsulation is often explained as “making fields private”.

That explanation is incomplete.

The real purpose of encapsulation is to protect invariants.

An invariant is a rule that must always remain true.

Examples:

  • an appointment cannot exist without a patient
  • a payment cannot be negative
  • a prescription must belong to a consultation

Without encapsulation, any part of the system can break those rules.

Example of fragile design:

appointment.date = null
appointment.patient = null

When invariants are protected through methods, the system becomes safer:

appointment.schedule(patient, date)

Now the object guarantees its own consistency.

Encapsulation forces developers to respect the model.

Responsibility Defines Good Design

One of the most important design questions in OOP is:

Who is responsible for this behavior?

When responsibility is unclear, developers tend to place logic:

  • in controllers
  • in utility classes
  • in services with hundreds of lines

This leads to a well-known problem:

anemic domain models

Example of poor design:

  • UserService
  • UserValidator
  • UserManager
  • UserUtils

While the actual User object contains nothing but fields.

In well-designed OOP systems, objects own their logic.

Cohesion and Coupling

Two fundamental concepts define how maintainable a system will be.

Cohesion

Cohesion measures how related the responsibilities of a class are.

High cohesion means:

A class does one thing and does it well.

Low cohesion results in “god classes”.

Example:

UserService

  • registerUser
  • generateInvoice
  • sendEmail
  • calculateTaxes

These responsibilities clearly belong to different parts of the system.

Coupling

Coupling measures how dependent components are on each other.

High coupling means:

small changes ripple across the system

refactoring becomes dangerous

testing becomes difficult

Good OOP design aims for:

  • high cohesion
  • low coupling

Behavior Is More Important Than Data

One of the biggest misconceptions in OOP is treating objects as data structures.

This happens frequently in modern frameworks where objects are used as DTOs.

Example:

class Order {
public int quantity;
public double price;
}

Then logic is implemented elsewhere:

OrderService.calculateTotal(order)

But the behavior clearly belongs to the object itself.

Better design:

order.calculateTotal()

The object becomes responsible for its own behavior.

OOP Is the Foundation of Modern Architecture

Many modern architectures rely on solid OOP concepts:

  • Domain-Driven Design (DDD)
  • Clean Architecture
  • Hexagonal Architecture
  • Layered Architecture

All of them assume developers understand:

  • responsibility

  • abstraction

  • separation of concerns

  • domain modeling

Without this foundation, architectural patterns become ceremony rather than design.

The Cost of Skipping OOP Fundamentals

Developers who rush through OOP often create systems that show the same symptoms:

  • bloated service classes
  • business rules scattered across layers
  • fragile refactoring
  • duplicated logic
  • growing technical debt

The system works — until it grows.

Then every change becomes expensive.

How to Actually Learn OOP

Instead of memorizing syntax, focus on:

1️⃣ Modeling real domains
2️⃣ Defining clear responsibilities
3️⃣ Protecting invariants
4️⃣ Reducing coupling
5️⃣ Writing objects with behavior

Small projects are the best way to practice this.

Build systems where objects represent real concepts.

Conclusion

Object-Oriented Programming is not a language feature.

It is a way of thinking about software.

When properly understood, it allows developers to build systems that:

  • remain understandable
  • evolve safely
  • scale in complexity

Skipping these fundamentals might feel faster in the short term.

But in software engineering, structure always wins over speed.

André Blos Aliatti

Developer documenting the process of learning software engineering fundamentals and building real systems.

Top comments (0)