OOP is not that bad
Object-oriented programming (OOP) draws both praise and sharp criticism, with many engineers arguing that its real problem is not objects themselves but inheritance-driven designs that create tight coupling, fragile base classes, and hard‑to‑evolve hierarchies. Commenters contrast this with functional and data‑oriented styles that favor small composable functions, explicit state, and clear data transformations, while noting that these can introduce their own complexity around effects, performance, and refactoring. A recurring theme is that modern “best practice” tends to blend paradigms—using composition over inheritance, treating objects mainly as modular boundaries, and reserving heavy OOP or pure FP techniques for the cases where they clearly pay off.
Scope of the Debate
- Most comments distinguish “OOP the paradigm” from “OOP as practiced” in class‑hierarchy-heavy languages (Java, C++, etc.).
- The original article’s logger example is seen as highlighting trade‑offs between OOP and functional effects handling, not proving one paradigm superior.
Inheritance, Tight Coupling, and Composition
- Widespread agreement that inheritance—especially deep or implementation inheritance—is a major source of tight coupling and “fragile base class” problems.
- Many argue that inheritance works only in small, single‑author codebases; in teams it creates brittle hierarchies and painful refactors.
- “Prefer composition over inheritance” is repeated often: use interfaces/traits and object composition instead of taxonomic class trees.
- Some go further: coupling methods to mutable state is framed as the core modularity problem in OOP; FP’s separation of data and functions is presented as inherently more modular.
Functional Programming vs Imperative/OOP
- FP advocates claim functions and immutable data behave like “Lego bricks”: easy to recombine without refactoring primitives.
- Critics respond that FP often requires broader structural changes when requirements change (e.g., adding new state or behavior), while imperative code can be locally patched.
- There is back‑and‑forth about whether FP really forces “rewrite-only” development or simply demands better decomposition.
- Performance concerns arise around multiple passes (map/filter chains, multi-loop code), with counterpoints about laziness, fusion, and compilers optimizing away overhead.
Logging Example and Effects
- Several commenters show alternative Haskell/FP designs (functions, records, effect systems) that match or exceed the OOP logger flexibility, arguing the article’s FP side is unidiomatic or overly constrained.
- Others say the pain is about effect systems vs direct side effects, not FP vs OOP; once you adopt structured effects, you pay a complexity cost in any paradigm.
Pedagogy, Patterns, and Culture
- Many blame how OOP is taught: early focus on class taxonomies, design patterns, and inheritance rather than modularity, interfaces, and composition.
- GoF patterns and “pure OOP” curricula are criticized as having encouraged over‑engineered, brittle designs.
- Several propose a “middle road”: functional core with an imperative/OOP shell, or multi‑paradigm languages (e.g., Rust, Kotlin, Scala, C#) used pragmatically rather than dogmatically.