Skip to main content

Sign in to CleanKata

Track your progress, earn XP, and unlock every lesson.

By signing in you agree to our Terms of Use and Privacy Policy.

Design Patterns90 XP10 min

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.

Why this matters

When a service directly imports a database driver or fires raw SQL, the business rule and the storage plumbing are fused. You can't test the rule without a real database, you can't swap Postgres for Redis without rewriting the service, and every storage detail bleeds into the domain. The Repository pattern draws a clean line: define an interface that describes what the domain needs (find pending orders, save an order), then provide separate implementations for production storage and in-memory testing. The domain never imports a driver again.

Testing becomes trivial

With a repository interface in place, a complete unit test for OrderService needs no database, no network, no docker-compose. Inject an InMemoryOrderRepository, seed it with test data, and verify results — the test runs in milliseconds and never flakes. In production, inject PostgresOrderRepository via your DI container. Same service, zero changes.

💡Key takeaway

Repository hides the plumbing. Your domain speaks to an interface — swapping Postgres for in-memory, Redis, or a remote API is a one-liner in the DI wiring, not a rewrite of business logic.

🔧 Some exercises may still have errors. If something seems wrong, use the Feedback button (bottom-right of the page) to report it — it helps us fix it fast.

Hint: If your service imports a database driver or HTTP client, the domain is leaking into infrastructure. Define an interface, inject it, and watch the test suite become trivial.

✗ Your version

Repository Pattern — CleanKata — CleanKata