devnotes.

Procedural vs. Object-Oriented Programming

Before OOP became dominant, most programs were written in a procedural style — a sequence of functions that operate on data structures passed between them. Data and the functions that manipulate it are separate.

Procedural style (pseudocode):

struct Account { balance, accountNumber }

function deposit(account, amount) {
    account.balance += amount
}

function withdraw(account, amount) {
    if amount > account.balance: error
    account.balance -= amount
}

myAccount = Account(balance: 100)
deposit(myAccount, 50)

Any function anywhere in the program can directly read or modify account.balance, since nothing enforces the relationship between the data and the logic meant to guard it. As programs grow, this makes it hard to guarantee data stays valid.

OOP style (pseudocode):

class Account {
    private balance

    function deposit(amount) {
        this.balance += amount
    }

    function withdraw(amount) {
        if amount > this.balance: error
        this.balance -= amount
    }
}

myAccount = new Account(balance: 100)
myAccount.deposit(50)

Here, balance can only be changed through deposit() and withdraw(), which can enforce rules (like never allowing a negative balance). The object is responsible for protecting its own integrity.

When each shines: procedural code is often simpler and faster for small scripts, one-off data transformations, or purely mathematical/functional logic. OOP tends to pay off as a codebase grows — when you need to model many related, stateful entities, enforce invariants, and organize code so multiple developers can work on different parts independently. Most real-world large systems, and even 'procedural-first' languages like modern PHP and Python, blend both styles pragmatically.

Procedural vs OOP: Key Differences Explained | DevNotes