Skip to main content
Problem 20

Refactor Duplicate Validation and Decouple Database Access

MEDIUMREFACTOR
Refactoring+3

main.py has three handler functions: register_user, update_profile, and create_post. They all work — but the code has two problems.

First, the same username validation block is copy-pasted into all three handlers. If the validation rules ever change, you have to update three places and hope you don't miss one.

Second, every handler imports and instantiates Database directly. That makes them impossible to unit test without hitting the real database, and it tightly couples business logic to infrastructure.

Refactor both problems. Extract the shared validation into a validators.py module. Decouple the database dependency so handlers receive their save mechanism from the outside instead of reaching for it themselves.

Requirements
  • register_user, update_profile, and create_post must return identical responses to the originals for all valid and invalid inputs.
  • The username validation logic must not be duplicated — it must live in exactly one place.
  • A validators.py file must exist and contain the extracted validation logic.
  • main.py must not import Database from db.py.
  • Each handler must accept its save mechanism as an external dependency so tests can pass a mock without touching the real database.
Examples
Example 1
Input
register_user({'username': 'alice', 'email': 'a@b.com'}, save=mock_save)
Output
{'status': 'ok', 'data': {'username': 'alice', 'email': 'a@b.com'}}
Example 2
Input
register_user({'username': 'x'}, save=mock_save)
Output
{'error': 'username must be between 3 and 20 characters'}
Constraints
  • Do not change the response shape or error messages.
  • Do not modify db.py.
Follow-up

If you needed to support multiple database backends (Postgres, SQLite, in-memory), what would you change about the interface you designed?

Hints
Related Practice
Track
Backend Basics

Keep moving through related backend basics problems and build a stronger search-friendly practice loop around this topic.

View track →
Console output will appear here...