Senior Python + AI — Technology Roadmap
Checklist format. Tick what you can explain and defend under questioning, not what you’ve used.
Every theme links to the notes that answer it. Same convention as Company B (AdTech) — prep map and Tech Check — Theme Navigation: tick the box once reviewed, bold is the primary note, the rest add depth.
Priority: 🔴 core (asked in most interviews) · 🟡 important (asked for your target roles) · 🟢 breadth (nice to have)
Layer 1 — Foundations
🔴 Python
- Data model —
__new__,__init__, descriptors,__slots____init__vs__new____slots__Metaclasses__eq__vs__hash__ - MRO / C3 linearization, cooperative
super()super()and the MROstaticmethod vs classmethod - Refcounting + generational GC, reference cycles,
weakrefMemory model and GCweakrefMemory profiling - The GIL — what it protects and what it doesn’t; free-threaded buildsThe GILFree-threading in 3.14Why Python is slow
- Generators,
yield from, the iterator protocolGenerators and iterators - Context managers,
contextlib,ExitStackcontextlibDecorators and context managers -
functools—lru_cachetraps,singledispatch,cached_propertyfunctoolsfunctools.wraps - dataclass vs attrs vs Pydantic — when eachdataclass vs attrs vs Pydanticdataclasses
- Profiling — cProfile, py-spy, memrayProfiling basicsMemory profilingProduction debugging
🔴 Python Typing
- Protocol vs ABC — structural vs nominalProtocol vs ABC
-
TypeVar,ParamSpec,Concatenate, genericsTypeVar and genericsParamSpec and Concatenate -
@overload,TypedDict,Literal,SelfTypedDict and LiteralAnnotated and TypeGuardOptional and Union - Variance — covariant / contravariant / invariantTypeVar and generics(§ Variance)
- PEP 695 syntax —
class Foo[T],type X = ...TypeVar and generics(§ PEP 695 syntax)Free-threading in 3.14 -
mypy --strict/ pyrightmypy vs pyright
🔴 Python Async
- Coroutine vs Task vs FutureCoroutinesEvent loop internalsConcurrency vs parallelism
-
TaskGroup(3.11+) vsgathervsas_completedTaskGroup - Cancellation semantics —
CancelledError,shield,asyncio.timeout()Cancellation and timeouts - Blocking the event loop — detection and fixes (
to_thread, executors)to_threadand executorsCPU vs I/O boundAsync optimisation - Backpressure —
Semaphore, boundedQueueQueuesSemaphores and locks - Strong task references — fire-and-forget is a GC bugTaskGroupDebugging async
- anyio / structured concurrencyanyio and trio
- Async DB — asyncpg, psycopg3, SQLAlchemy
AsyncSessionAsync SQLAlchemyAsync AWS
🔴 Testing
- pytest fixtures, scopes, parametrize, conftestFixturespytest conceptsparametrize
- monkeypatch /
mock.patch— patch where it’s looked upmock and patchMocking external APIsTest doubles - pytest-asyncio strict vs auto modepytest-asyncio
- testcontainers — real Postgres/Redis in testsIntegration testsContract testing
- Hypothesis — property-based testingHypothesis
- Coverage — and why 100% isn’t the goalCoverageTest pyramid
🔴 Git
- Rebase vs merge — when eachMerge vs rebase
- Interactive rebase — squash, fixup, reorder, editInteractive rebase
-
reflog— recovering “lost” commitsReflog recoveryDangerous commands - cherry-pick, revert vs reset —
--soft/--mixed/--hardreset vs revertcherry-pick - bisect — regression huntingBisect
- stash, worktreesStashWorktrees
- Conflict resolution, rerereConflict resolution
- Branching strategy — trunk-based vs GitFlowBranch strategiesPR workflow
- Conventional commits, pre-commit hooksHooks
🔴 Bash / Linux
- Pipes, redirection, xargs, process substitutionPipes and redirectionFind and xargs
- grep / sed / awk / jq / findgrep / sed / awkFind and xargs
- Process management — ps, top/htop, signals, kill, nohupProcess managementSignals and traps
- systemd basics, journalctlSystemd servicesCron and systemd timers
- Networking — curl, dig, netstat/ss, lsof, tcpdumpTroubleshooting tools
- Permissions, users, chmod/chownFile permissions
- Disk/memory — df, du, free, iostatProcess managementBash commands
- Script hygiene —
set -euo pipefail, traps, quotingExit codes and strict modeQuoting and expansionBash scripting essentials - SSH, keys, tunnels, scp/rsyncSSH
🔴 Docker
- Image vs container vs layer; layer caching orderDocker image layersImage vs container
- Multi-stage builds, slim/distroless base imagesMulti-stage builds
-
.dockerignore, build context sizeDocker image layersDocker - Volumes vs bind mountsVolume types
- Networking, port mapping, docker-composeDocker networkingDocker compose
- Healthchecks, restart policiesDocker composeScaling in docker
-
ENTRYPOINTvsCMD, PID 1 and signal handlingDockerSignals and traps - Non-root users, secrets — never in ENVPurpose of containerizationSecrets and supply chain
- Image size optimisation for Lambda / ECSMulti-stage buildsLambda
🟢 Kubernetes
- Pods, Deployments, Services, IngressPods and DeploymentsIngress and networking
- ConfigMaps, SecretsConfigMaps and Secrets
- Liveness vs readiness probesProbes and HPA
- Resource requests/limits, HPAProbes and HPA
- kubectl debugging — logs, exec, describe, port-forwardKubernetes interviewKubernetes basics
Layer 2 — Backend
🔴 FastAPI
- ASGI spec, Starlette underneathWSGI vs ASGIFastAPI overview
- Middleware order and execution flowMiddleware
-
Depends— sub-dependencies, per-request caching, yield teardown orderDepends -
dependency_overridesfor testingTesting FastAPI -
lifespan— not the deprecatedon_eventFastAPI overviewDeployment - BackgroundTasks vs Celery — the durability boundaryBackgroundTasks vs Celery
- StreamingResponse / SSE, WebSocketsServer-sent eventsWebSocketsAsync performance
- Auth — OAuth2, JWT, scopes, JWKSFastAPI authJWT authPyJWT
- Exception handlers,
RequestValidationErrorException handlers -
httpx.AsyncClient+ASGITransportin testsTesting FastAPIaiohttp vs httpx - Deployment — uvicorn/gunicorn workers, graceful shutdownDeploymentgunicorn and uvicorn
🔴 Pydantic v2
-
field_validatorvsmodel_validator— before / after / wrapValidation modes -
computed_field,model_config,from_attributesPydantic in practiceResponse models - Serialization aliases,
exclude_unset/exclude_noneResponse modelsPydantic in practice - pydantic-settings for configPydantic in practiceDjango settings
- Request / response / DB model separationResponse modelsSQLModel
- v1 → v2 migration differencesPydantic v1 to v2dataclass vs attrs vs Pydantic
🔴 SQLAlchemy 2.0
- Core vs ORM,
select()styleCore vs ORM2.0-styleselect() - Session lifecycle, identity map, unit of workSession lifecycleUnit of workEngine and session
- Eager loading — selectinload, joinedload, subqueryloadLoading strategiesThe N+1 problem
- Async session — and why lazy loading raisesAsync SQLAlchemy
- Relationship config, cascadesRelationshipsCommon pitfalls
- Connection pooling — NullPool behind PgBouncerSQLAlchemy poolingConnection pooling
- Alembic — autogenerate limits, data migrations, branchingAlembicZero-downtime migrations
🟡 Django + DRF
- QuerySet laziness and result cachingQuerySetsDjango ORM
- select_related vs prefetch_related,
Prefetch()select_related vs prefetch_relatedDjango relationships - N+1 detection — assertNumQueries, debug toolbarN+1 in DRFThe N+1 problem
-
F(),Q(), Subquery/OuterRef, annotate vs aggregateF()Q()Django ORM -
transaction.atomic,select_for_update,on_commitDjango ORMBulk operationsSQL transactions - Zero-downtime migrations,
AddIndexConcurrentlyZero-downtime migrationsDjango migrations - DRF — serializers, viewsets, permissions, throttling, paginationViews and viewsetsSerializersPermissionsThrottlingDRF pagination
- Async views,
sync_to_async/async_to_syncAsync Django - Why you avoid signals for business logicSignals
🔴 API Design
- REST resource modelling, status codesREST principlesStatus codesPUT vs PATCH
- Idempotency keysIdempotency keysIdempotent endpointsIdempotent payments
- Pagination — offset vs keyset/cursorVersioning and paginationDRF pagination
- Versioning strategiesVersioning and paginationVersioning
- Rate limiting algorithms — token bucket, sliding windowRate-limiting algorithmsRate limiter designnginx rate limiting
- OpenAPI, typed client generationOpenAPI and typed clientsDRF schema
- Webhooks — retries, ordering, poison messagesTimeouts and retriesDead-letter queuesTransactional outbox
- 🟢 gRPC / GraphQL — when they beat RESTProtocol comparisongRPCGraphQL
Layer 3 — Data
🔴 PostgreSQL
- MVCC, bloat, VACUUM / autovacuumVACUUM and autovacuumWAL and checkpoints
- Index types — B-tree, GIN, GiST, BRIN, partial, coveringIndex typesIndexes
- Composite index column order — the leftmost prefix ruleIndexesWhy your index is not used
-
EXPLAIN (ANALYZE, BUFFERS)— estimated vs actual rowsEXPLAIN ANALYZEHow a query runs - Join types — nested loop, hash, mergeHow a query runsEXPLAIN ANALYZE
- Isolation levels, lock types, deadlock diagnosisIsolation levelsIsolation anomaliesSQL transactions
-
SELECT ... FOR UPDATE SKIP LOCKED— the job-queue patternAdvisory locksJob scheduler design - Pooling, PgBouncer modes, prepared-statement conflictsConnection poolingSQLAlchemy pooling
- Partitioning, JSONB, CTEs, window functions, LATERALWindow functions and CTEsRecursive CTEsSharding and partitioningMaterialized views
- Monitoring —
pg_stat_statements,pg_stat_activityEXPLAIN ANALYZEWhy your index is not used
🔴 pgvector
- Distance operators —
<->,<=>,<#>, and index/operator matchingpgvector in productionEmbeddings - HNSW —
m,ef_construction,hnsw.ef_searchHNSW and ANN indexespgvector in production - IVFFlat —
lists,ivfflat.probes, build-after-loadpgvector in productionHNSW and ANN indexes - Recall vs latency tuningHNSW and ANN indexesVector databases
- Filtered vector search — the recall trapVector databaseskNN vector search
- Quantization — halfvec, binarypgvector in productionQdrant in production
- Hybrid search — tsvector + vector via RRFHybrid search and rerankingpgvector in production
🔴 Redis
- Data structures beyond strings — sorted sets, hashes, streams, HLLRedisPub/sub and streams
- Cache-aside pattern, TTL + jitterPython patternsDistributed cache
- Cache stampede and its fixesCache stampede
- Lua scripts for atomicityPython patternsRedis
- Pub/sub vs StreamsPub/sub and streams
- Distributed locks — and why they’re harder than they lookRedlock critiqueAdvisory locks
- Persistence (RDB/AOF), eviction policiesPersistence and memoryClustering and HA
🔴 Celery
- Broker vs result backendCeleryBroker comparison
-
acks_late+ idempotent tasksCelery idempotencyCelery - Visibility timeout and duplicate executionCelery idempotencySQS consumers
- Prefetch multiplierCeleryRabbitMQ
- chain / group / chordCanvas pitfalls
- Retries, time limits, DLQ handlingCelery retriesDead-letter queuesExchanges and DLX
- Pass IDs, never ORM objectsCelery in interviewsCelery idempotency
- 🟢 Alternatives — arq, Dramatiq, Temporalarq and DramatiqTemporal vs celeryWorkflows vs activities
Layer 4 — Cloud & Ops
🔴 AWS
- Lambda — cold starts, provisioned concurrency, layers, limitsLambdaCompute comparison
- API Gateway — stages, canary deployments, authorizersAPI Gateway patternsAPI Gateway
- ECS / Fargate — task definitions, service discoveryECS placementFargateService discovery
- SQS — standard vs FIFO, DLQ, redriveSQS consumersSQS
- SNS, EventBridgeEventBridgeSNSStep Functions
- RDS, RDS Proxy — the Lambda connection-storm problemRDSAurora backtrackConnection pooling
- S3 — presigned URLs, lifecycle, event notificationsS3
- Cognito — user pools vs identity poolsCognitoOIDC and OAuth2 flows
- IAM — roles vs users, least privilege, assume-roleIAM role patternsIAM
- Secrets Manager vs Parameter StoreRotation and Parameter StoreParameter Store
- CloudWatch Logs Insights, X-RayCloudWatch cost patternsDistributed tracing
🔴 CI/CD
- GitHub Actions — workflows, matrix, caching, OIDC to AWSGitHub ActionsSelf-hosted runners
- Test / lint / typecheck gatesPipeline design patternsCI/CD basicsTest data and CI
- Container build + push pipelinesPipeline design patternsSecrets and supply chain
- Deployment strategies — blue/green, canary, rollingDeployment strategiesProgressive delivery
- Migration ordering in deploysZero-downtime migrationsDeployment strategies
🔴 Observability
- Structured logging + correlation IDsStructured loggingCorrelation IDs
- OpenTelemetry — traces, spans, context propagationOpenTelemetrySampling strategiesJaeger
- RED / USE metricsRED and USE metricsPrometheus
- Prometheus + Grafana basicsPrometheusGrafana
- Alerting on symptoms, not causesSLOs and alertingChoosing a tool
- Sentry / error trackingSentryCost and FinOps
🟢 IaC
- Terraform basics — state, modules, plan/applyTerraform stateModules and compositionplan and apply
- AWS CDK or SAM — for Lambda-heavy stacksCloudFormation vs TerraformCloudFormation
Layer 5 — Frontend (the fullstack claim)
🟡 TypeScript
- Interfaces vs types, unions, discriminated unionsNarrowing and guardsTypeScript pitfalls
- Generics, utility types,
unknownvsanyTS genericsUtility typesStrictness flags - Generating clients from OpenAPIOpenAPI and typed clientsREST vs GraphQL vs tRPC
🟡 React
- Hooks rules and why they existRules of HooksUseful hooks
-
useEffectdeps + cleanup,useMemo/useCallbackuseEffectMemoisation heuristicsReact Compiler - Reconciliation and
keyReconciliationThekeypropReact fiber - Server state (TanStack Query) vs client state (Zustand)Server vs client stateTanStack QueryZustand
- Consuming SSE / streaming with abortConsuming SSEAbort and races
🟢 Next.js
- CSR / SSR / SSG / ISRRendering modesNext.js rendering
- App Router, React Server ComponentsReact Server ComponentsRSC in depthApp Router layout
- Streaming SSR with SuspenseStreaming SSRSuspense for data
Layer 6 — AI / LLM (the differentiator)
🔴 LLM Fundamentals
- Tokenization, context windows, token budgetingTokenizationContext windowsContext management
- Temperature, top-p, structured output / JSON modeFunction callingLLM JSON validationThe chat API
- Function / tool calling mechanicsFunction callingHallucinations and tools
- Prompt caching — and its cost impactGateway and cachingKV cacheProvider abstraction
- Streaming, cancellationThe chat APIStreaming modesServer-sent events
- RAG vs fine-tuning vs long context — the decision treeFine-tuning vs RAGWhat RAG solves
🔴 RAG
- Parsing — PDF, tables, OCR; unstructured, doclingDocument parsingMultimodal
- Chunking — fixed, recursive, structural, semantic, contextual retrievalChunking
- Small-to-big / parent-document retrievalRAG architecture patterns(§ Parent-document retrieval)Chunking
- Embedding model selection, MTEB caveats, asymmetric searchEmbeddingsFine-tuning embeddingsModel routing
- Hybrid retrieval + RRFHybrid search and reranking
- Reranking (cross-encoder) — the retrieve-50-rerank-5 patternHybrid search and rerankingRAG architecture patterns
- Query transformation — HyDE, multi-query, decomposition, rewritingRAG architecture patterns(§ Pre-retrieval techniques)What RAG solves
- Context ordering (lost-in-the-middle), dedupContext windowsContext management
- Citation enforcement + validationOutput validationHallucinations and tools
- Abstention promptingHallucinations and tools(§ Explicit I-don’t-know license)What RAG solves
🔴 Evaluation
- Retrieval metrics — recall@k, precision@k, MRR, NDCGAgentic RAG and eval(§ Retrieval metrics)Choosing the metricRecommender systems
- Generation metrics — faithfulness, relevance, context precision/recallAgentic RAG and eval(§ End-to-end metrics)Why LLM eval is hard
- RAGASEval tooling(§ RAGAS)
- LLM-as-judge biases — position, verbosity, self-preferenceLLM-as-judge
- Building golden datasets without labelsBuilding eval setsAgentic RAG and eval(§ Build a golden set)
- Evals in CI as regression testsBuilding eval setsEval tooling
- Production signals — feedback, abstention rate, score distributionsOnline evalMonitoring and drift
🔴 Agents
- The bare agent loop, framework-freeThe agent loopWhat is an agent
- Tool design — naming, descriptions, error-as-contentFunction calling(§ Tool design)Agent failure modes
- LangGraph — state + reducers, nodes, conditional edges,
CommandState and reducersNodes and routingWhy LangGraph - Checkpointers (Postgres), durable execution, time travelCheckpointersDurable execution
- Interrupts / human-in-the-loopHuman in the loopDurable execution
- Subgraphs, streaming modesStreaming modesSubgraphs
-
create_react_agentinternals — and when to drop to a custom graphcreate_react_agentWhy LangGraph - Memory — short-term windowing/summarisation, long-term write policyMemory strategiesContext management
- Multi-agent patterns — and why you usually shouldn’tMulti-agent patternsMulti-agent frameworks
- Trajectory evaluationAdvanced agent patternsAgent failure modes
🔴 MCP
- Tools vs resources vs promptsMCP fundamentalsBuilding a server
- Transports — stdio, HTTP/SSEThe stateless-core specMCP fundamentals
- Writing a server (Python SDK)Building a serverSecuring MCP
- Auth for remote serversSecuring MCPThe stateless-core spec
- Security — tool descriptions are untrusted inputSecuring MCPPrompt injection
🔴 LLM Security & Ops
- Prompt injection — direct and indirectPrompt injectionRed teaming
- Retrieved content is untrusted inputPrompt injectionRAG assistant design
- PII redaction in / outPII and complianceAI governance
- Tool allowlists, spend caps, sandboxingOutput validationAdvanced agent patternsSandboxing agents
- Output schema + groundedness validationOutput validationLLM JSON validation
- Tracing — Langfuse / LangSmith / OTel GenAITracing platformsLLM observability
- Cost attribution, model routing, fallback chainsCost attributionModel routingProvider abstraction
Suggested order
| When | Focus | Why |
|---|---|---|
| Now | MCP server → RAG eval harness | Small, named gaps, and both produce artifacts |
| Next | PostgreSQL tuning → pgvector benchmarking | Strongest depth signal, already your stack |
| Then | Async correctness → FastAPI internals | Asked everywhere, cheap to solidify |
| Ongoing | Django ORM → Frontend → system design out loud | Breadth maintenance |
Keep a decisions.md per project: what you chose, what you rejected, why.
Interview stories are hard to manufacture under pressure and trivial to harvest
from notes.
Coverage note
Checked 2026-08-21: every theme above resolves to at least one existing note — nothing on this roadmap is uncovered by the corpus. Where a theme lives inside a larger note rather than its own file, the section name is given after the link.