Object-Oriented Programming Principles
Object-Oriented Programming organizes code around objects with encapsulated state and behavior. Four pillars: encapsulation, inheritance, polymorphism, abstraction.The Four Pillars
Encapsulation
Expose behavior, hide state — prefer methods over public fields
Inheritance
“is-a” relationship; composition (“has-a”) is often more flexible
Polymorphism
Program to interfaces, not implementations
Abstraction
Name concepts at the right level of detail
Key Principles
- Liskov Substitution Principle: Subtypes must be substitutable for base types
- Favor composition over inheritance for behavioral reuse
SOLID Principles
SOLID is a mnemonic for five design principles that produce flexible, maintainable, testable object-oriented code.Single Responsibility Principle (SRP)
A class should have one, and only one, reason to change.
Open-Closed Principle (OCP)
Open for extension via interfaces, closed for modification.Liskov Substitution Principle (LSP)
Subtypes must honor the contracts of their base types.Interface Segregation Principle (ISP)
Many focused interfaces over one general-purpose interface.Dependency Inversion Principle (DIP)
High-level modules depend on abstractions, not concretions.Best Practices
Do
- Apply DIP via constructor injection — makes dependencies visible
- Create focused interfaces (ISP) per consuming use case
- Use OCP: extend via new classes/implementations, not by editing existing ones
Don't
- Apply SOLID dogmatically when it adds complexity without benefit
- Create thousands of tiny classes with no meaningful domain modeling
- Over-abstract prematurely — Rule of Three before extracting abstractions
Presentation Layer Patterns
MVC / MVP / MVVM
MVC, MVP, and MVVM are patterns for separating user interface concerns from application logic, improving testability and maintainability.- MVC
- MVP
- MVVM
Model-View-Controller
- Controller handles input, creates ViewModel, selects View
- Separates Models (data), Views (UI), and Controllers (input handling)
Advanced Architectural Patterns
CQRS & Eventual Consistency
CQRS separates commands (writes) from queries (reads), allowing each to be optimized independently. Eventual consistency accepts temporary data staleness in exchange for availability and scalability. Key Concepts:- Command side: validates, executes, emits domain events
- Query side: optimized read models (projections) from event store or replicas
- Eventual consistency: accept that reads may lag writes briefly
- Event Sourcing: store domain events as the source of truth, not current state
- Saga/Process Manager coordinates multi-step distributed transactions
Best Practices for CQRS
Do
- Design idempotent event consumers from the start
- Model commands as business intentions, not CRUD operations
- Use projection rebuilds as a data migration strategy
Don't
- Use CQRS as an excuse to avoid a proper domain model
- Implement Event Sourcing without understanding its operational complexity
- Ignore eventual consistency in UX — users need feedback on command outcome
Test-Driven Development (TDD)
TDD writes a failing test for a small behavior, makes it pass with minimum code, then refactors. The cycle produces well-tested, modular, dependency-inverted code.Red-Green-Refactor Cycle
- Red: Write a failing test for the next small behavior
- Green: Write minimum code to pass — resist over-engineering
- Refactor: Clean up with confidence — all tests still pass
Tests should be: Fast, Independent, Repeatable, Self-verifying, Timely (FIRST)
TDD Best Practices
Do:- Name tests as behavior specifications (given/when/then)
- Commit after each Green phase
- Run mutation tests on critical business logic with Stryker/PITest
- Write tests purely for coverage metrics after the fact
- Create tests that test implementation internals (brittle)
- Skip the Refactor step — it’s when design improves
Domain-Driven Design (DDD)
Domain-Driven Design aligns the software model with the business domain using a shared language (Ubiquitous Language) and tactical patterns for rich domain modeling.Strategic Patterns
Bounded Context
Explicit boundary within which a model is consistent
Ubiquitous Language
Shared vocabulary between domain experts and developers
Context Mapping
Relationships between bounded contexts
Anti-corruption Layer
Protects a bounded context from external models
Tactical Patterns
- Aggregate: Cluster of domain objects with a single root enforcing invariants
- Entity: Has identity and lifecycle
- Value Object: Defined by its attributes
- Domain Event: Records that something meaningful happened in the domain
- Repository: Abstracts persistence
DDD Best Practices
Do
- Involve domain experts in model design sessions (Event Storming)
- Keep aggregates small — load and modify only one aggregate per transaction
- Model domain concepts explicitly (no generic CRUD services)
Don't
- Create one giant bounded context for the whole system
- Use database tables as the domain model
- Introduce DDD tactical patterns without a genuine complex domain
Database Consistency Patterns
ACID Properties
ACID guarantees database transaction correctness:- Atomicity: All-or-nothing transaction semantics
- Consistency: Data moves from one valid state to another
- Isolation: Concurrent transactions do not see each other’s partial state
- Durability: Committed data survives failures
CAP Theorem
CAP Theorem states that distributed systems can only guarantee two of: Consistency, Availability, Partition Tolerance.Actor Model
The Actor Model structures concurrent systems as independent actors that communicate exclusively via asynchronous message passing, eliminating shared mutable state.Key Characteristics
- No shared state between actors — all communication is message-based
- Actors are highly scalable: millions on a single JVM with Akka
- “Let it crash” philosophy: supervisor trees restart failed actors
- Location transparency: actors can be local or remote transparently