Level up your
code quality
Micro-lessons on clean code, design patterns, and clean architecture — with examples in Python and TypeScript.
Pick your language. One micro-lesson at a time — 5 to 12 minutes each.
Choose your language
Developers spend 10× more time reading code than writing it. — Robert C. Martin
Object Calisthenics
Nine rules to transform how you write object-oriented code.
9 lessonsClean Code
Write readable, maintainable code that other developers will love.
47 lessonsDesign Patterns
Reusable solutions to common software design problems.
23 lessonsClean Architecture
Structure systems so that business logic is independent of frameworks.
50 lessonsAll lessons
Object Calisthenics
Use First-Class Collections
Any class containing a collection should have no other member variables — wrapping collections gives filtering, sorting, and rules a semantic and cohesive home.
Keep All Entities Small
No class over 50 lines, no package over 10 files — small classes fit on one screen, force focus, and naturally organize into cohesive packages.
Don't Abbreviate
Abbreviations mask deeper problems — if a name is too long to write out, the method has too many responsibilities. Names should be one or two clear words.
Don't Use the Else Keyword
Replace if/else with guard clauses and early returns — else is usually a sign of unclear flow that can be simplified into a straightforward sequence.
Don't Use Getters/Setters/Properties
Tell, don't ask — instead of getting data to make decisions outside the object, tell the object what to do and let it use its own data.
One Dot per Line
Based on the Law of Demeter — don't reach through an object's internals. Ask the object to do the work instead of navigating its parts.
One Level of Indentation per Method
Each method should do one thing at one level of abstraction — nested control structures are a sign to extract a method.
No Classes with More Than Two Instance Variables
Limiting state to two instance variables dramatically increases cohesion — if you need more, decompose into a hierarchy of collaborating objects.
Wrap All Primitives and Strings
A raw int or string has no domain meaning — wrapping it in a class like Money or Email lets the compiler enforce intent and gives behavior a natural home.
Clean Code
Class Organization
Classes should be small, focused, and have a single reason to change.
The Clean Code Mindset
Why clean code is a professional discipline — and how dirty code silently destroys teams and companies.
Clean Concurrency Strategies
Write concurrent code that is correct, readable, and free of subtle data-race bugs.
Clean Error Handling
Error handling is a separate concern — keep it isolated so your main algorithm stays readable.
Clean Unit Testing
Tests are first-class code — dirty tests become as costly to maintain as production code.
Comment Heuristics
Identify and eliminate bad comments; write the rare good one with precision.
Concurrency: Client-Server Model
Structure client-server concurrent systems to isolate shared state and avoid subtle threading bugs.
Concurrency: Deadlock & Starvation
Recognize and eliminate the four conditions that produce deadlock in concurrent systems.
Deadlock: The 4 Conditions
A deadlock requires all four Coffman conditions simultaneously — break any one and deadlock becomes impossible.
Concurrency: Jiggle Testing
Race conditions hide in timing gaps — shaking execution order with random yields and multi-platform runs forces them into the open.
Don't Repeat Yourself
🔒Every piece of knowledge must have a single, authoritative representation in the codebase.
Duplication & Abstraction
🔒Recognize hidden duplication and choose the right abstraction to eliminate it.
The 5S Philosophy in Code
🔒How the Toyota 5S manufacturing philosophy maps to professional software craftsmanship — naming, organization, cleaning, standardization, and discipline.
Framework Analysis
🔒Understand what a framework does before using it — read the source, not just the docs.
Function Heuristics
🔒Apply the F1–F4 heuristics to keep functions minimal, focused, and side-effect-free.
Abstraction Levels & Dependencies
🔒Keep high-level policy separate from low-level detail, and ensure base classes never depend on derived classes.
Coherence & Clarity
🔒Apply the same pattern everywhere, avoid conceptual clutter, and never couple unrelated concerns.
Conventions & Magic Numbers
🔒Follow team coding standards religiously and replace every magic literal with a named constant.
Environment & Truth
🔒Build systems that compile in one step, run all tests in one step, and never lie through suppressed warnings.
Expressiveness & Algorithms
🔒Use explanatory variables, precise names, and a deep understanding of the algorithm to make code speak for itself.
Feature Envy
🔒A method that spends most of its time reading another class's data belongs in that class.
Logic & Polymorphism
🔒Make all dependencies explicit, and replace if/switch chains with polymorphic dispatch.
Noise & Organization
🔒Eliminate excessive information, dead code, and vertical distance to keep every file easy to scan.
Placement & Statics
🔒Put every function in the class most interested in it, and keep static methods truly stateless utilities.
Selectors & Intent
🔒Boolean and enum selector arguments obscure intent — split them into focused, well-named functions.
Heuristics Catalog Overview
🔒A curated catalog of code smells and refactoring heuristics drawn from Clean Code chapter 17.
G16: The Obscured Intent
🔒Code that tries to be clever is code that fails to communicate — density and brevity at the cost of clarity are not virtues.
G21: Understanding the Algorithm
🔒Tests passing is not the same as understanding — clean code requires you to fully grasp why the algorithm works before you commit it.
G22: Logical to Physical Dependencies
🔒Never let a module silently assume a value from another — make every dependency explicit and declared in code.
Java-Specific Heuristics (J1–J3)
🔒Three Java-focused heuristics: avoid wildcard imports, never inherit constants, and prefer enums over integer constants.
Legacy Code Refactoring
🔒Safely transform tangled legacy code by adding tests first and refactoring in small steps.
The Art of Naming
🔒Write names that reveal intent, avoid confusion, and make code searchable.
Naming Heuristics
🔒Apply the N1–N7 heuristics to write names that are accurate, unambiguous, and searchable.
The Necessary Evil of Comments
🔒Code is the only source of truth — comments lie as the code evolves.
Objects vs Data Structures
🔒Objects hide data behind behavior. Structures expose data. Mixing both creates hybrids nobody wants.
Programmer Ethics & Attitude
🔒Quality is a professional responsibility — not something you deliver when time allows, but the non-negotiable minimum of your craft.
Pure Functions
🔒A pure function always returns the same output for the same input and changes nothing outside itself.
Responsibility Selectors
🔒Use the Single Responsibility heuristics to detect and split overloaded classes and modules.
SerialDate: Cleanup & Transformation
🔒Apply successive refinement to the SerialDate class — test, rename, extract, and simplify.
SerialDate: Diagnosis
🔒A case study in reading legacy code critically — find the smells before touching anything.
The 4 Rules of Simple Design
🔒Kent Beck's four rules, in priority order, for a design that is always ready to evolve.
Small Functions
🔒Functions should do one thing, do it well, and do it only.
Style & Format as Communication
🔒Code formatting is a communication act — structure files so any developer can navigate them in seconds.
Successive Refinement
🔒Start with working code, then refactor iteratively — never write clean code in one pass.
System Boundaries
🔒Third-party code belongs at the edge — wrap it so it never pollutes your business logic.
The Three Laws of TDD
🔒Master the red-green-refactor micro-cycle: write a failing test first, then only the code needed to pass it.
Testing Heuristics
🔒Apply the T1–T9 heuristics to write complete, meaningful, and maintainable test suites.
Design Patterns
Abstract Factory: Families of Objects
Create families of related objects without specifying their concrete classes — guarantee compatibility between products from the same family.
Adapter: The Interface Translator
Make incompatible interfaces work together — wrap an old or external class behind the interface your system expects without modifying either side.
Bridge: Decoupling Abstraction
Split a large class into two independent hierarchies — abstraction and implementation — so both can evolve without affecting each other.
Builder: Step-by-Step Construction
Construct complex objects step by step — the same construction process can produce different representations using a fluent interface.
Chain of Responsibility
Pass a request along a chain of handlers — each handler decides to process it or pass it to the next, decoupling sender from receiver.
Command: Encapsulating Requests
Transform a request into a standalone object — enabling undo/redo, queuing, logging, and deferred execution of operations.
Composite: Tree Structures
Compose objects into tree structures and treat individual objects and groups uniformly — iterate a file system the same way whether it's a file or a folder.
Decorator: Adding Superpowers
Add behavior to objects dynamically by wrapping them — compose capabilities instead of creating an explosion of subclasses.
Facade: The Friendly Face of the System
Provide a simplified interface to a complex subsystem — hide the chaos behind a single clean entry point without removing the complexity for those who need it.
Factory Method: The Virtual Constructor
Delegate object creation to subclasses — decouple the client from the concrete classes it instantiates.
Flyweight: Sharing to Save Memory
🔒Fit more objects in RAM by sharing common state — separate intrinsic (shared) from extrinsic (unique) data to avoid duplicating heavy objects.
Iterator: Traversing Collections
🔒Traverse elements of any collection without exposing its internal structure — the client never needs to know if it's a list, tree, or graph.
Mediator: Centralized Communication
🔒Restrict direct communication between objects — force them to collaborate through a mediator to reduce chaotic many-to-many dependencies.
Memento: Undo with Snapshots
🔒Capture and restore an object's internal state without violating encapsulation — implement Undo by storing snapshots of past states.
Observer: The Subscription System
🔒Let objects subscribe to events and be notified automatically — decouple event producers from consumers without either knowing about the other.
Prototype: Object Cloning
🔒Copy existing objects without depending on their classes — clone complex configurations instead of rebuilding them from scratch.
Proxy: The Control Intermediary
🔒Provide a substitute that controls access to another object — use for lazy loading, access control, logging, or caching without changing the real object.
Repository Pattern
🔒Abstract data access behind an interface so your business logic never knows whether data comes from a database, cache, or API — and testing becomes a one-liner swap.
Singleton: The Single Instance
🔒Ensure a class has only one instance and provide a global access point — but overuse creates hidden global state and makes testing painful.
State: Behavior Based on State
🔒Allow an object to alter its behavior when its internal state changes — replace state conditionals with polymorphic state objects.
Strategy: Algorithm Swapping
🔒Define a family of algorithms, encapsulate each in its own class, and make them interchangeable at runtime — eliminate conditionals by selecting behavior through composition.
Template Method: Algorithm Skeleton
🔒Define the skeleton of an algorithm in a superclass, but let subclasses override specific steps without changing its structure.
Visitor: New Operations Without Changing Classes
🔒Add new operations to an object hierarchy without modifying the classes — the visitor carries the operation, the elements just accept it.
Clean Architecture
ADP: The Acyclic Dependencies Principle
No cycles allowed in the component dependency graph — cycles cause the morning-after syndrome and prevent isolated builds and tests.
Architectural Boundaries: Drawing Lines
Architecture draws lines between what matters (business rules) and what doesn't (technical details) — these lines protect core business logic from changes in external tools.
What is Architecture? Lifecycle Support
Architecture's primary purpose is to support the system's lifecycle — development, deployment, operation, and maintenance — to maximize productivity and minimize lifetime cost.
Anatomy of a Boundary: Crossing Boundaries
When crossing an architectural boundary, source code dependencies must point opposite to the flow of control — polymorphism enforces this regardless of who calls whom.
Business Rules and Entities
Critical Business Rules would exist even without a computer — Entities encapsulate these rules and data, forming the most stable, UI-and-persistence-agnostic heart of the system.
Clean Embedded Architecture: Avoiding Firmware
Software doesn't wear out, but hardware becomes obsolete — a Hardware Abstraction Layer prevents business logic from becoming firmware trapped on a specific processor.
The Component Tension Diagram
REP, CCP, and CRP pull in opposite directions — architects must balance these tensions as the project evolves from development focus to reuse focus.
Components: The Unit of Deployment
Components are the smallest deployable units — JARs, DLLs, Gems — the building blocks of a plugin architecture where modules connect at runtime.
Component Cohesion: The Common Reuse Principle
Don't force users of a component to depend on things they don't need — depending on a component means depending on everything it contains.
Decoupling Modes: Source, Deployment, and Service
Decoupling can happen at source code, deployment, or service level — good architecture lets you start as a monolith and evolve into services if boundaries are well-defined.
The Dependency Rule in Clean Architecture
🔒Source code dependencies can only point inward — nothing in an inner circle can know anything about an outer circle, keeping the business core stable and reusable.
The Details: Database, Web, and Frameworks
🔒The database, web layer, and frameworks are delivery mechanisms — a good architect postpones these decisions and keeps business rules independent to avoid a costly technology marriage.
Device Independence
🔒Tying business logic to specific I/O devices is a costly mistake — architecture should be agnostic to whether data comes from cards, terminals, files, or APIs.
DIP: The Dependency Inversion Principle
🔒Source code dependencies should point only to abstractions — Abstract Factories create the architectural boundary between volatile concrete code and stable policy.
Dependency Inversion: Control Over Dependencies
🔒With interfaces, architects make source-code dependencies point against the control flow, granting absolute power over module coupling.
The Eisenhower Matrix in Development
🔒Architecture is important but rarely urgent. Developers must defend good structure against short-term business pressure.
Architecture Layers: Entities and Use Cases
🔒Entities hold critical business rules that exist across the enterprise; Use Cases orchestrate application-specific flows and are isolated from UI and database changes.
Functional Programming: The Value of Immutability
🔒Functional programming disciplines assignment. Immutability eliminates race conditions, deadlocks, and concurrent update issues at the architectural level.
The Goal of Architecture and Design
🔒Design and architecture are the same thing — their true measure is the effort required to meet client needs while minimizing lifetime cost.
The Humble Object Pattern
🔒Split hard-to-test from easy-to-test behavior — the Presenter prepares all logic into a testable ViewModel; the View is a humble object that only renders what it receives.
The Devil Is in the Implementation Details
🔒The best architecture fails without disciplined use of access modifiers — the compiler is your strongest ally in enforcing Clean Architecture rules across the team.
Interface Adapters and Data Passing
🔒Interface Adapters convert data between the format use cases understand and the format external systems need — boundaries are always crossed with simple DTOs, never raw entities or DB rows.
ISP: The Interface Segregation Principle
🔒Don't depend on things you don't use — fat interfaces force unnecessary recompilation, coupling, and vulnerability to failures in unrelated code.
Keep Options Open
🔒A good architect maximizes the number of decisions not yet made — separating policy from details so database and framework choices can be postponed until more is known.
Layer Decoupling
🔒Separate what changes at different rates — UI, application business rules, domain business rules, and database each change for different reasons and should be horizontal layers.
LSP: The Liskov Substitution Principle
🔒Subtypes must be substitutable for their base types — LSP violations at the architectural level force expensive special-case logic into the design.
The Main Component: The Ultimate Detail
🔒Main is the dirtiest, lowest-level component — the entry point that wires all dependencies and hands control to the clean architecture above it.
The Main Sequence: The A/I Balance
🔒Components should balance Abstraction (A) and Instability (I) — the Pain Zone (stable+concrete) and Uselessness Zone (abstract+unstable) are architectural anti-patterns to avoid.
OCP: The Open/Closed Principle
🔒Software artifacts should be open for extension but closed for modification — adding new behavior should add code, not change existing code.
OOP: The Reality of Encapsulation
🔒OOP didn't invent encapsulation — C had perfect encapsulation before C++ and Java actually weakened it with header file requirements.
Package by Component: The Hybrid Approach
🔒Group all responsibility for a clean feature boundary into one package — internal persistence and logic stay private, the compiler enforces what's visible to the rest of the system.
Organizational Strategies: Package by Feature
🔒Group code by domain feature — top-level packages reveal the business, every feature is co-located, and searchability dramatically improves as the system grows.
Organizational Strategies: Package by Layer
🔒The simplest code organization groups by technical layer (web/service/repository) — easy to start but hides business intent and allows accidental cross-layer shortcuts.
Partial Boundaries: Anticipation Strategies
🔒Full architectural boundaries are expensive — partial boundaries using Strategy or Facade patterns preserve future separation points without the full upfront cost.
The Peripheral Anti-Pattern
🔒The peripheral anti-pattern occurs when infrastructure code talks directly to other infrastructure code, bypassing the domain — like the Paris ring road, traffic flows around the city instead of through it.
Policy and Level
🔒Level is the distance from inputs and outputs — the farther from I/O, the higher the level. Source code dependencies should always point toward the highest-level, most stable policies.
Polymorphism: The Power of Plugins
🔒Polymorphism lets you treat external dependencies — database, UI, I/O — as interchangeable plugins, making core logic device-independent.
Ports and Adapters (Hexagonal Architecture)
🔒The inside is the domain; the outside is infrastructure — outside depends on inside, ports speak the domain's language, and adapters translate between domain and external systems.
Programming as Science: Falsifiability and Testing
🔒Tests don't prove correctness — they prove absence of known incorrectness. Good architecture produces easily falsifiable modules.
Programming Paradigms: Discipline, Not Tools
🔒The three paradigms — structured, object-oriented, and functional — impose discipline by removing capabilities, not adding them.
Component Cohesion: REP and CCP
🔒REP groups classes released together; CCP groups classes that change together for the same reason — both mirror SRP at the component scale.
SAP: The Stable Abstractions Principle
🔒A component should be as abstract as it is stable — the most stable components should be pure interfaces so they can be extended without modification.
Screaming Architecture
🔒Your folder structure should reveal what the system does, not what framework it uses — a health system screams 'Health', not 'Rails'.
SDP: The Stable Dependencies Principle
🔒Depend in the direction of stability — a volatile component should never be depended upon by a stable one, or that stability is permanently compromised.
Services and Microservices: Are They Architecture?
🔒Services don't define architecture — a service with poor internal structure is just an expensive function call. True architectural boundaries can exist inside a monolith or across services.
SRP: The Single Responsibility Principle
🔒A module should be responsible to only one actor — preventing changes for one department from accidentally breaking another.
Structured Programming: Discipline over Direct Control
🔒Dijkstra proved unrestricted goto is harmful. Sequence, selection, and iteration alone are sufficient for correct, decomposable modules.
The Test Boundary
🔒Tests are the outermost architectural circle — fragile tests that couple to implementation details make the system rigid; a Test API decouples test structure from application structure.
The Two Values of Software: Behavior vs Structure
🔒Software derives value from behavior and structure. A perfectly working but rigid system will fail when requirements change.
Use Case Decoupling
🔒Use cases are vertical slices that cut through all layers — decoupling them lets each evolve independently without one use case's changes colliding with another's.