codeEngineering
Async vs sync, type hints, project structure, and config — the foundations every Python service rests on.
1 item
Async vs sync — pick deliberately
async when the work is I/O-bound (DB, HTTP, queue calls) and you want concurrency on a single thread via the event loop.async def. One blocking call (requests.get, time.sleep, a sync DB driver) stalls the entire event loop. Offload with await asyncio.to_thread(...) or use an async-native library.Type hints are not optional
mypy (or pyright) in CI. Types catch a whole class of bugs before runtime and document intent for free.Project layout that scales
app/
api/ # routers / views — thin, no business logic
services/ # business logic, orchestration
repositories/ # data access; the only layer that touches the ORM
models/ # ORM models + Pydantic schemas
core/ # config, logging, security, settings
workers/ # background tasks, Temporal workflows
Keep routers thin: validate input, call a service, serialize output. Business logic lives in services; data access lives in repositories. This separation is what lets you swap FastAPI for Django, or Postgres for something else, without rewriting your domain.
Config & secrets
BaseSettings. Never hardcode; never commit secrets.Dependency hygiene
uv or poetry lockfiles). Reproducible builds matter.uv for speed; it's dramatically faster than pip for installs and resolution.