Index

All lessons

254 lessons across 17 courses. Looking for something specific? Search and filter the catalog.

Advanced Git

  • Finding Regressions with git bisectBinary-search your history to the exact commit that broke something, then automate it with git bisect run, the exit-code contract, skip, terms, and replay.
  • Git in CI/CD PipelinesMake Git behave inside automation: shallow detached-HEAD checkouts and their four symptoms, diffing against the right base, porcelain output, credentials, and bot commits.
  • Git Notes, Archives, and BundlesMove what Git stores somewhere else: notes for metadata that cannot change a hash, archive for clean tarballs, bundle for a repository in one file, and custom subcommands.
  • Inside the Git Object ModelOpen .git with plumbing commands: blobs, trees, commits and tags, how a hash is computed, refs as files, revision syntax as graph arithmetic, and building a commit by hand.
  • Merge Strategies, Drivers, and rerereControl exactly how Git resolves a merge: ort and the other strategies, -s ours versus -X ours, custom merge drivers in .gitattributes, and rerere for recurring conflicts.
  • Rewriting History at ScaleA runbook for purging a secret or a huge binary from every commit with git filter-repo, extracting a subdirectory, and coordinating the force-push without breaking the team.
  • Scaling Git for Large RepositoriesDiagnose why a repository is slow — too much history, too many files, or too much binary — then apply partial clones, sparse checkout, git maintenance, or Git LFS.
  • Securing Your History with Signed CommitsMake every commit cryptographically attributable. SSH and GPG signing, allowed_signers, signed tags, host-side enforcement, and an honest account of what signing does not prove.
  • Submodules and SubtreesSeveral repositories, one build. Gitlinks and .gitmodules, the full submodule lifecycle and its honest list of pain, subtrees as the alternative, and when a registry beats both.
  • Working on Two Branches at Oncegit worktree: several working directories over one object database. How it works underneath, the failure modes, and the patterns worth adopting — without a second clone.

Advanced Python

  • Async I/O in AngerAsync context managers and iterators, connection pools, backpressure when producers outrun consumers, and bridging sync and async code without deadlocking.
  • Asyncio from the Event Loop UpCoroutines, tasks and the loop that drives them, what await actually suspends, and the single blocking call that stalls an entire async application.
  • Attribute Lookup and the MROHow Python finds an attribute, C3 linearisation, what super actually does in cooperative multiple inheritance, and what __slots__ changes about all of it.
  • Concurrency with Threads and Processesconcurrent.futures as the common interface, processes and the pickling constraint, sharing state safely, and the deadlocks that come from getting either wrong.
  • Descriptors and PropertiesWhat property is built from, the descriptor protocol underneath it, and using it deliberately for validation, laziness and computed attributes without turning a class into magic.
  • Distributing and VersioningWheels and source distributions, native dependencies and the platforms they force you to build for, publishing safely, and the supply-chain concerns that come with being a dependency.
  • Memory, Reference Counting, and Garbage CollectionWhen an object is actually freed, the cycles reference counting cannot collect, weak references, and why measuring memory in Python is harder than it looks.
  • Metaclasses and Class CreationWhat happens when a class statement executes, why __init_subclass__ and decorators solve most of what people reach for metaclasses to do, and the narrow cases that genuinely need one.
  • Metaprogramming and Its Limitsinspect, ast and code generation; why eval and exec are almost never the answer; and recognising the point where clever machinery costs more than the duplication it removed.
  • Performance EngineeringWorking from a profile: algorithmic wins first, then data structures, then the boundary where native code or vectorisation is the honest answer — with the measurement to justify it.
  • Structured Concurrency and CancellationTask groups that cannot leak a task, timeouts that actually stop work, and treating CancelledError as control flow rather than an error to swallow.
  • The Data Model and Dunder MethodsThe protocols behind Python's syntax: how len, in, iteration, comparison and arithmetic are all method calls, and how implementing them makes your types behave like built-in ones.
  • The GIL and What It Really BlocksWhat the global interpreter lock does and does not prevent, why threads still help for I/O, what free-threaded builds change, and how to choose between the models on evidence.
  • The Import SystemFinders, loaders and sys.path; packages and namespace packages; circular imports and the restructuring that fixes them; and deferring an expensive import without hiding it.
  • Typing at the Advanced LevelProtocols for structural typing, TypeVar and ParamSpec, overloads, variance, Self, and writing annotations that make a checker prove something rather than nod along.
  • Writing a Library Others Depend OnDesigning a public surface you can live with: what to expose, deprecation that gives people time, semantic versioning applied honestly, and shipping types with your package.

Advanced Testing

  • Contract Testing Between ServicesEnd-to-end tests across ten services do not scale. Consumer expectations verified against the provider, where the broker fits, and what contract tests deliberately do not cover.
  • Designing a Test StrategyA strategy is a set of decisions about where confidence comes from and what you are willing not to know. Writing one for a real system, and the trade-offs it has to name.
  • Ephemeral Environments and Test InfrastructureTest infrastructure is a product with users. Environments created per branch and destroyed after, seeding them quickly, and why a shared staging box becomes a queue.
  • Fuzzing and Generated InputFeeding a program input nobody would write, on purpose. Coverage-guided fuzzing, corpora, sanitisers, and turning a crash into a permanent regression test.
  • Leading Quality in a TeamQuality as an engineering-wide property rather than a department. Where a QA specialist adds most, coaching over gatekeeping, and making the case with evidence.
  • Mutation TestingWho tests the tests? Deliberately breaking the code to see whether anything fails, reading a surviving mutant, and the cost that keeps this off every pipeline.
  • Observability as a Testing ToolThe system tells you what your tests could not. Assertions on telemetry, service level objectives as continuous tests, and closing the loop from an incident back to a test case.
  • Performance Testing and Load ModelsA load test is only as good as its model of a user. Arrival rates, think time, percentiles over averages, open versus closed models, and finding the knee rather than a number.
  • Property-Based TestingStop writing examples and state the invariant instead. Generators, shrinking, choosing properties that hold, and the class of bug that example-based tests structurally cannot find.
  • Quality Gates and Release DecisionsTurning test results into a decision: which gates block, which only inform, what happens on a red main, and why an unreliable gate is worse than no gate.
  • Risk-Based TestingTesting effort is a budget. Modelling likelihood against impact, spending on the parts that would actually hurt, and defending the choice when someone asks why an area is thin.
  • Scaling a Suite: Parallelism and ShardingAn hour-long suite gets skipped. Parallel workers, sharding, test selection by impact, and the isolation guarantees you need before any of it is safe.
  • Security Testing for EngineersThe testable part of security: authorisation matrices, injection at every boundary, dependency and secret scanning, and the difference between a scan and a pentest.
  • Testing for Resilience and FailureInjecting the failures production will deliver anyway: latency, partitions, dependency outages and clock skew. Running an experiment with a hypothesis and a blast radius.
  • Testing in Production SafelySome things are only true in production. Feature flags, canaries, shadow traffic, synthetic journeys and a rollback you have actually rehearsed.
  • Testing Non-Deterministic SystemsWhen the same input gives a different answer, equality assertions stop working. Scoring instead of matching, thresholds over sample sets, and detecting drift.

Advanced TypeScript

  • Assertion Functions and satisfiesasserts signatures that narrow for the rest of a scope, satisfies for checking without widening, and const type parameters that preserve literals.
  • Authoring a Typed LibraryDesigning a public type surface, exports maps, shipping declarations for multiple module formats, and treating a type change as a breaking change when it is one.
  • Branded and Nominal TypesMaking two structurally identical types incompatible on purpose — validated input, identifiers, units — and the ergonomics of constructing and unwrapping them.
  • Conditional TypesTypes that branch on other types: the extends check, distribution over unions and how to stop it, and the recursion that makes them genuinely powerful.
  • Declaration Files and Ambient TypesWriting .d.ts by hand, declaring modules and globals, augmenting types you do not own, and keeping ambient declarations from leaking everywhere.
  • Decorators and MetadataThe standardised decorator model, what each decorator kind can do, metadata, and the narrow cases where a decorator beats a plain function call.
  • Function Overloads and Call SignaturesDescribing a function with several legitimate shapes, ordering overloads so the right one wins, and when a union or generic beats overloading entirely.
  • Generics That ScaleTyping higher-order functions, preserving parameter types through wrappers, fluent builders that stay inferable, and generics that read well at the call site rather than the definition.
  • Inference Deep DiveHow the compiler decides a type: infer, contextual typing, inference sites and priority, widening and literal types, and diagnosing why inference produced something too wide.
  • Interop with Untyped CodeMigrating incrementally, containing any at a boundary, typing a legacy module from the outside, and measuring progress so a migration actually finishes.
  • Mapped Types and Key RemappingTransforming every property of a type at once: modifiers, adding and removing optionality, and remapping keys with as to build derived shapes.
  • Template Literal TypesTypes built from string patterns: parsing and constructing strings at the type level, and the APIs this makes safe that were previously just documented.
  • The Compiler API and Custom ToolingReading your codebase as an AST: writing a codemod, a custom lint rule or a generator, and the maintenance cost of tooling that knows about your syntax.
  • Type Checking PerformanceWhy an editor becomes slow: measuring with compiler diagnostics, finding the type that costs seconds, and the rewrites that give the time back.
  • Type-Level Programming and Its LimitsRecursion depth, instantiation limits and compile-time cost. What can be computed in types, what should be, and the error message a colleague will have to read.
  • Variance, Assignability, and Structural TypingWhat makes one type assignable to another, co- and contravariance in function types, method bivariance and the unsoundness it permits.

AI Engineering Foundations

  • Few-Shot Examples That TeachWhen showing beats telling, how to choose examples that generalise instead of ones the model copies verbatim, and how a badly-chosen example set narrows the model instead of guiding it.
  • Giving the Model Your DataThe decision map every AI feature runs into: put it in the prompt, retrieve it at query time, give the model a tool to fetch it, or train it in. What each option costs and which problems it actually solves.
  • Measuring Instead of VibingYour first evaluation: a fixed set of real inputs, an expected outcome for each, and a number you can compare. How to build one in an afternoon and why prompt tuning without it is guessing.
  • Sampling, Temperature, and Non-DeterminismWhy a model that is deterministic underneath gives you different answers anyway: temperature, top-p, seeds, and how to decide when variation is a feature and when it is a bug you have to design around.
  • Structured Output Instead of ProseWhy parsing a model's paragraphs is a bug factory, and how asking for a schema instead turns an AI call into an ordinary function you can type, validate and test.
  • System Prompts and Rules FilesThe durable instruction layer that sits above every request: what belongs in it, what does not, and why project rules files have become a standard part of working with AI tools regardless of vendor.
  • The Shape of an AI FeatureAssembling everything so far into one small end-to-end feature — input handling, prompt, schema, validation, fallback and evaluation — and seeing which parts are AI and which are ordinary software.
  • Tokens, Context, and Why They Cost YouHow text becomes tokens, what a context window really limits, and why input and output are priced and paced differently. Counting tokens before they surprise you, and what happens when you run out of room.
  • What a Language Model Actually DoesNext-token prediction, and how that one mechanism explains almost every behaviour you will meet: fluency without understanding, confidence when wrong, and why the same question can get two different answers.
  • What to Never Hand a ModelSecrets, personal data, and irreversible actions: the categories that need a boundary rather than a careful prompt, plus what retention and training policies mean for data you send to a provider.
  • Why Models HallucinateThe mechanism behind confident invention, why asking a model to be accurate does not make it accurate, and the three things that genuinely reduce it: grounding, permission to refuse, and verifiable citations.
  • Writing a Prompt That Holds UpThe four parts of a prompt that survives contact with real inputs — instruction, context, examples, output contract — and the vague, overloaded and politely-worded prompts that quietly fail.

Building Reliable AI Systems

  • Cost and Latency EngineeringPrompt caching, model routing, batching, streaming for perceived speed, and trimming context that earns nothing. Where the money actually goes, measured rather than assumed.
  • Designing the Context WindowContext is a budget, not a bucket. What to include, in what order, and why adding more relevant material can make answers worse rather than better.
  • Designing Tools a Model Can Use WellA tool description is a prompt. Naming, granularity, argument shape, error messages that teach the model to recover, and why fewer sharper tools beat a large flexible one.
  • Evaluating an AI FeatureGolden sets, rubrics, and regression suites that run in CI. Choosing metrics that move when quality moves, and keeping an evaluation honest as the feature it measures changes.
  • Failure Modes, Retries, and FallbacksTimeouts, rate limits, content filters, truncated output and provider outages — which are worth retrying, which need a different model, and which must surface to the user immediately.
  • Grounding and CitationMaking an answer traceable to its source, forcing a refusal when the sources do not support one, and checking citations mechanically instead of trusting that they exist.
  • Memory and State Across TurnsWhat to carry between turns and what to drop: rolling summaries, durable facts, retrieval over past conversation, and the failure where a stale memory outranks the truth in front of it.
  • Observability for Non-Deterministic SystemsTracing a request through prompts, tools and retries; logging enough to reproduce a bad answer without logging things you should not keep; and watching cost and latency as first-class signals.
  • Prompt Injection and the Trust BoundaryEvery document, web page and tool result is untrusted input that reaches the same context as your instructions. Where the boundary goes, least privilege for tools, and confirming side effects with a human.
  • Retrieval That Actually RetrievesWhy naive vector search disappoints: chunking that destroys meaning, embeddings that miss exact terms, and no reranking. Hybrid retrieval, chunk design, and measuring recall before you blame the model.
  • Shipping an AI Feature SafelyRolling out something you cannot fully predict: flags, canaries, a kill switch, a feedback path from users back into your evaluation set, and what to do the first time it embarrasses you.
  • Skills and Reusable CapabilityPackaging instructions, examples and assets into named units the model loads only when relevant. Progressive disclosure, when a skill beats a bigger system prompt, and how to keep a library of them from rotting.
  • Structured Output You Can TrustSchema-constrained generation, validating at the boundary, repair loops that converge instead of looping forever, and handling partial objects while a response is still streaming.
  • The Agent LoopThink, act, observe, repeat — and the four termination conditions that stop it running away. Step budgets, progress detection, and why an agent that cannot stop is worse than one that cannot start.
  • Tools the Model Can CallHow tool calling actually works — schema, invocation, result, continuation — and what to do about the model calling the wrong tool, the right tool with wrong arguments, or no tool at all.

Docker Foundations

  • Configuration and Environment VariablesOne image, many environments. Passing configuration in at run time with environment variables and env files, and why a secret baked into an image is a secret you have leaked.
  • Debugging a Container That Will Not StartA method for the five failures you will actually hit: exited immediately, port already allocated, image not found, permission denied, and the container that runs but answers nothing.
  • Images, Containers and the DifferenceAn image is a recipe and a container is the meal. Why that distinction explains almost every confusing thing Docker does, plus the commands to inspect both.
  • Installing Docker and Running Your First ContainerGet Docker onto macOS, Windows or Linux, prove it works, and run something real in one command — then look at what actually happened underneath.
  • Keeping Data With VolumesContainers forget everything when they stop. Bind mounts, named volumes and tmpfs — which one to reach for, and the mistake that silently loses a database.
  • Layers, Caching and Build ContextWhy your second build is instant and your third is not. How layers are cached, why instruction order decides your build time, and what .dockerignore is really for.
  • Networking and Publishing PortsWhy localhost inside a container is not your localhost. Publishing ports, user-defined networks, and how one container finds another by name.
  • Publishing an Image to a RegistryTagging, logging in and pushing to Docker Hub or GitHub Container Registry, plus what a tag really is and why :latest is the one you should not depend on.
  • Running a Multi-Container App With ComposeA web app, a database and a cache started with one command. Writing compose.yaml, service dependencies, and the difference between up, down and down --volumes.
  • Smaller, Safer ImagesMulti-stage builds, choosing a base image, dropping root and pinning versions — the four changes that turn a 1.2 GB image with a shell in it into something you would ship.
  • Why Containers ExistThe problem containers solve, told through the machine that worked and the one that did not: what a container actually is, how it differs from a virtual machine, and why the answer is a shipping metaphor.
  • Writing Your First DockerfileBuild your own image from a text file: FROM, WORKDIR, COPY, RUN and CMD, each introduced by the problem it solves, ending with an application you built and ran yourself.
  • Your First Containerised AppThe capstone: take a small application from bare source to a built, configured, published image running behind Compose with persistent data — every step from the earlier lessons in one pass.

Git Fundamentals

  • Branching and Merging BasicsBranches as movable labels, switching without losing work, fast-forward versus three-way merges, resolving your first conflict, and cleaning up merged branches.
  • Choosing What Git TracksKeep your repository to source and nothing else. .gitignore pattern syntax, why ignoring a tracked file does nothing, git rm --cached, check-ignore, and global ignores.
  • Configuring Git the Way You Want ItThe three config levels, your editor, line endings, and the handful of settings that remove daily friction — each introduced by the annoyance it fixes.
  • Installing GitGet Git onto your machine and teach it who you are. Includes a short orientation to the terminal for anyone who has never opened one, and why Git needs your name at all.
  • Reading What ChangedAnswer what is different and who changed this line. git diff and --staged, reading a unified diff hunk by hunk, commit references, git show, log filtering, and blame.
  • Undoing Things SafelyA decision guide for every common mess: restore, clean, amend, reset soft/mixed/hard, revert, and reflog rescue — with a clear line between what is recoverable and what is not.
  • Why Version Control ExistsWhat Git actually stores and why its workflow is shaped the way it is: snapshots, commit hashes, history as a graph, and why every clone is a full copy.
  • Working with Remotes and GitHubBack your work up and share it. Clone versus remote add, SSH keys and tokens, upstream tracking, what origin/main really is, fetch versus pull, and the rejected push.
  • Your First Repository and CommitBuild a real repository from scratch. The .git directory, the three areas, reading git status, staging with add and add -p, and writing commit messages worth keeping.

Git in Practice

  • Automating Git with HooksMake the repository catch its own mistakes. Every hook worth knowing, two complete scripts you can paste, core.hooksPath so they travel with a clone, hook managers, and why hooks are not enforcement.
  • Branching Models for TeamsGitHub Flow, trunk-based development and Git Flow compared honestly, plus release and hotfix branches, the real cost of long-lived branches, and how to keep one current.
  • Cherry-picking and Moving CommitsCopy a commit onto another branch and live with the duplicate: ranges, -x for backports, conflict handling, patch-id detection, and moving work with format-patch when there is no shared remote.
  • .Gitattributes and Config That Pays for ItselfThe committed half of Git automation: line endings, diff and merge drivers, linguist attributes, export-ignore, plus conditional includes and the settings that remove daily friction.
  • Interactive Rebase and Clean CommitsTurn a messy branch into commits a reviewer will thank you for. Every todo verb, splitting a commit, the --fixup and --autosquash workflow, and rebase --exec.
  • Merging and Resolving ConflictsHandle a genuinely hairy merge with a process rather than luck: the merge base, zdiff3 conflict style, modify/delete and rename conflicts, and verifying a merge before you trust it.
  • Pull Requests and Code ReviewThe pull request lifecycle end to end, the three merge buttons and what each does to history, reviewing locally, git range-diff, force-pushing under review, CODEOWNERS and forks.
  • Recovering Lost Work with the ReflogA rescue manual organised by symptom: bad reset, deleted branch, botched rebase, lost amend, dropped stash — plus git fsck, and the one category of loss that is permanent.
  • Rewriting History with RebaseWhat rebase actually does to your commits, merge versus rebase as a real trade-off, the ours/theirs inversion, rebase --onto, and force-pushing with --force-with-lease.
  • Stashing Work in ProgressPut work down safely and pick it up again: push with a message, apply versus pop, the untracked-file trap, partial stashes, what a stash really is, and recovering a dropped one.
  • Tags, Releases, and VersioningCut a release that is reproducible a year later. Annotated versus lightweight tags, pushing and never moving tags, git describe, semantic versioning, and changelogs from history.

Kubernetes Foundations

  • A Cluster on Your LaptopInstall kind or minikube, get kubectl talking to it, and understand the kubeconfig file well enough never to deploy into the wrong cluster.
  • ConfigMaps and SecretsGetting configuration into a pod as environment variables or mounted files, and the honest truth about how much protection a Secret does and does not give you.
  • Debugging a Pod That Will Not RunA method for Pending, ImagePullBackOff, CrashLoopBackOff and the pod that is Running but wrong — describe, events, logs, previous logs, exec, and what each one tells you.
  • Deployments That Keep Pods RunningThe controller you actually use. Replicas, the ReplicaSet underneath, scaling up and down, and what happens when you delete a pod a Deployment owns.
  • Ingress and Getting Traffic InOne entry point, many services. Ingress rules, hostnames and paths, TLS termination, and why an Ingress does nothing without a controller behind it.
  • Labels, Selectors and NamespacesHow Kubernetes groups things without a hierarchy: labels as the glue every controller uses, selectors as the query, and namespaces as the boundary around a whole environment.
  • Manifests and kubectl applyYAML as the interface: apiVersion, kind, metadata and spec, the difference between apply and create, and why declaring the end state beats issuing commands.
  • Persistent Storage for Your DataPods are disposable and disks are not. PersistentVolumes, claims, StorageClasses and access modes — enough to run something stateful without losing it.
  • Pods, the Smallest Unit You DeployKubernetes never runs a container on its own. What a pod adds, why sidecars share one, and why you will almost never create one by hand.
  • Probes, Restarts and Self-HealingLiveness, readiness and startup probes: how the cluster decides your app is alive, ready for traffic, or beyond saving — and what a badly written probe costs.
  • Requests, Limits and SchedulingWhy a pod sits Pending forever, and why another one keeps getting killed. CPU and memory requests versus limits, OOMKilled, and how the scheduler places work.
  • Rolling Updates and RollbacksShipping a new version without dropping a request: rollout strategy, maxSurge and maxUnavailable, watching a rollout, and undoing one that went wrong.
  • Services and Reaching Your PodsPod IPs change constantly, so nothing addresses them directly. ClusterIP, NodePort and LoadBalancer, cluster DNS, and how a Service finds its pods.
  • What a Cluster Is Made OfControl plane, nodes, kubelet, scheduler and etcd, explained as one loop: you write down what you want, and something keeps reality matching it.
  • Why Kubernetes ExistsYou can run containers with Compose, so why is there a cluster? The failures Kubernetes was built to absorb — a dead machine, a traffic spike, a bad deploy — and the declarative idea underneath all of it.
  • Your First App on KubernetesThe capstone: take the container you built earlier and give it a Deployment, a Service, configuration, storage, probes and an Ingress — then update it and roll it back.

Production AI Engineering

  • An Eval Harness You Can TrustBuilding an evaluation you would bet a release on: sample size, variance across runs, statistical significance, and why a two-point score improvement is usually noise.
  • Caching Across a Model StackPrompt caching and its layout rules, semantic caching and its correctness risk, and invalidation in a system where the same input may legitimately produce a different answer tomorrow.
  • Context Engineering at ScaleLong contexts degrade in ways short ones do not. Compaction, hierarchical summarisation, isolating work in sub-agents with their own context, and measuring attention loss instead of assuming it away.
  • Drift, Regression, and Model UpgradesWhy a better model breaks your prompts, how to pin and how to move, shadow traffic, and an upgrade playbook that turns a scary migration into a measured one.
  • Fine-Tuning, Distillation, and When Not ToA decision framework: what fine-tuning fixes, what it never fixes, the data and evaluation it demands, and the maintenance cost that arrives the day the base model is deprecated.
  • Guardrails and Policy EnforcementInput and output filters, allowlists, and classifiers — where each belongs in the stack, what they genuinely stop, and why a guardrail that runs on the same model it guards is not a control.
  • Human-in-the-Loop DesignApproval gates, confidence thresholds and escalation paths that fit real work. Designing against reviewer fatigue, where rubber-stamping makes the human a liability rather than a control.
  • Incidents in Non-Deterministic SystemsResponding when there is no stack trace: reproducing from traces, replaying a request, rolling back a prompt, and writing a postmortem whose root cause is a probability rather than a line of code.
  • LLM-as-Judge and Its Failure ModesPosition bias, self-preference, verbosity bias and miscalibration. How to build a judge that correlates with human labels, and how to know when it has stopped.
  • Model Context Protocol and Tool EcosystemsAn open standard for connecting models to tools and data: servers, clients, transports, and what changes about your threat model once a third party can define the tools your agent sees.
  • Multi-Agent OrchestrationWhen splitting work across agents genuinely helps and when it is expensive theatre. Fan-out and verify, adversarial review, coordination failure, and the token cost nobody budgets for.
  • Routing and Model PortfoliosCascades, confidence signals and cheap-first strategies; abstracting over providers without abstracting away the differences that matter; and measuring whether routing actually saved anything.
  • The AI Threat ModelIndirect injection chains, exfiltration through tool arguments, the confused deputy, and a supply chain that now includes prompts and skills. Defence in depth for systems that will be attacked through their inputs.
  • The Economics of an AI ProductUnit economics per request, margin as a design constraint, abuse and capacity planning, and how cost pressure quietly reshapes architecture whether or not you plan for it.

Python Foundations

  • ComprehensionsBuilding a list, dict or set from another in one readable line — and recognising the point where a comprehension has become worse than the loop it replaced.
  • Dictionaries and SetsLooking things up by name instead of position, handling a key that is not there, and using a set when membership and uniqueness are the whole point.
  • Functions, Arguments, and Return ValuesNaming a piece of work so you can reuse it: parameters, defaults, returning values, and the mutable default argument that catches every Python programmer exactly once.
  • Installing Python Without Breaking Your MachineWhy your computer may already have a Python you should not use, how versions coexist, and getting to a working setup you can trust on macOS, Windows or Linux.
  • Lists and TuplesOrdered collections you can change and ones you cannot: indexing, slicing, growing a list, and the aliasing surprise where two names turn out to share one list.
  • Loops That Do Not Run AwayRepeating work over a collection, repeating until something changes, and the loops that never finish. enumerate and zip, and why you rarely need an index in Python.
  • Making Decisions with Conditionsif, elif and else; comparison versus equality; what Python considers true when the thing is not a boolean; and combining conditions without creating something nobody can read.
  • Numbers and Arithmetic That Surprises YouIntegers that grow without limit, decimals that cannot represent 0.1 exactly, floor division and modulo, and when money needs a different type altogether.
  • Objects and ClassesThe problem classes solve — data and the behaviour that belongs to it in one place — how to write one, and the many cases where a function and a dictionary are the better answer.
  • Organising Code into ModulesSplitting one long file into several that import each other, what the if __name__ line is really doing, and a project layout that will not fight you later.
  • Reading and Writing FilesOpening files so they always close, text versus bytes, encodings and the errors they cause, and building paths that work on any operating system.
  • Strings and TextBuilding and shaping text: f-strings, the string methods worth memorising, why a string can never be changed in place, and what happens when text is not plain English.
  • The Standard Library You Will Actually UseA tour of what ships with Python and saves you writing it: pathlib, datetime, json, collections, itertools, random and argparse, each shown solving a real task.
  • Values, Names, and TypesWhat a variable really is in Python — a name attached to a value, not a box holding one — plus the basic types, why the distinction between them matters, and what None is for.
  • When Things Go Wrong: ExceptionsReading a traceback, catching only what you can handle, and why except Exception hides the bug you most needed to see. try, except, else and finally, and raising your own.
  • Why Python and What Happens When You Run ItWhat a programming language is for, what actually happens between saving a file and seeing output, and the difference between typing at the interpreter and writing a program that lasts.
  • Your First Real Python ProgramBuilding a small command-line tool end to end: arguments, files, error handling, structure and a first test — putting every earlier lesson into one thing that works.

Python in Practice

  • Code Quality ToolingFormatters and linters that end style arguments, pre-commit hooks that catch problems before review, and wiring the same checks into CI so they cannot be skipped.
  • Configuration and SecretsLayering defaults, files and environment variables; validating configuration at startup so it fails immediately; and keeping credentials out of your repository for good.
  • Context ManagersGuaranteeing cleanup even when something raises: the with statement, contextlib, writing your own, and the resource leaks that appear the moment you do not.
  • Dataclasses and Modelling DataReplacing dictionaries-as-records with types that describe themselves. dataclass, frozen instances, post-init validation, and choosing between NamedTuple, TypedDict and a validation library.
  • Dates, Times, and Time ZonesNaive versus aware datetimes, storing UTC and displaying local, zoneinfo, and the arithmetic that goes wrong twice a year when clocks change.
  • DecoratorsWrapping a function to add behaviour around it: closures, functools.wraps and the debugging misery of forgetting it, decorators that take arguments, and when a decorator is the wrong tool.
  • Errors as DesignException hierarchies that let callers catch the right thing, chaining so the original cause survives, and deciding when a failure should raise rather than return.
  • Files, Paths, and the Filesystempathlib beyond the basics: globbing, temporary files, atomic writes that survive a crash mid-write, permissions, and why string paths keep breaking on someone else's machine.
  • HTTP Clients and Talking to APIsSessions and connection reuse, timeouts you must always set, retries with backoff on the right status codes, pagination, and reading an API error instead of swallowing it.
  • Iterators, Generators, and LazinessThe iterator protocol, yield, and pipelines that process a file larger than memory. Where laziness wins, and the bugs that appear when a generator is consumed twice.
  • Logging Instead of PrintLevels, loggers and handlers; structured logs you can search; and what must never reach a log line. Configuring logging once, at the edge, instead of everywhere.
  • Packaging Your Projectpyproject.toml, the src layout, editable installs and console entry points — turning a folder of scripts into something that can be installed, imported and shipped.
  • Profiling Before OptimisingMeasuring where time actually goes: timeit for micro-questions, cProfile for real programs, reading the output, and the optimisation that made everything slower.
  • Regular Expressions in ModerationEnough regex to be useful — groups, anchors, greediness, compiled patterns — plus the cases where a parser, a split, or three lines of plain code is the correct answer.
  • Subprocesses and the ShellRunning other programs safely: argument lists versus shell strings, capturing and streaming output, exit codes, timeouts, and the injection risk in shell=True.
  • Test Doubles and When to MockPatching, fakes and seams. Mocking at the boundary rather than in the middle, and the over-mocked test that passes happily while the code it covers is broken.
  • Testing with PytestTests that fail usefully: plain assertions, fixtures, parametrisation, and choosing what to test so the suite catches regressions instead of restating the implementation.
  • Type Hints That Earn Their KeepAnnotations a checker can actually use, gradual typing in an untyped codebase, Optional and unions done properly, and the hints that add noise without adding safety.
  • Virtual Environments and Dependency ManagementWhy installing packages globally eventually breaks something, what an environment actually is, and how lockfiles turn 'works on my machine' into a reproducible install.
  • Working with JSON and External DataParsing data you did not create: validating shape before trusting it, custom encoders, numbers and dates that do not survive a round trip, and failing loudly at the boundary.

Testing Foundations

  • Beyond Functional TestingThe requirements nobody writes down: usability, accessibility, compatibility, performance and security. What each one is, and the cheapest first check for each.
  • Equivalence Classes and Boundary ValuesYou cannot test every input, so stop trying. Splitting an input space into classes that behave alike, then testing the edges — where bugs genuinely live.
  • Exploratory TestingTesting without a script, done properly: charters, time-boxing, note-taking and heuristics. The technique that finds the bugs your written cases were never going to.
  • Filing a Bug Report That Gets FixedA minimal reproduction, the expected and actual behaviour, the environment, and one bug per report — the difference between a ticket that gets fixed and one that gets closed.
  • How Software BreaksThe failures that actually happen: bad input, missing state, timing, integration seams and wrong assumptions. Knowing the shapes is how you learn to guess where a bug is hiding.
  • Levels of TestingUnit, integration, system and end-to-end — what each level can see, what it cannot, and why the pyramid is a statement about cost and speed rather than a rule.
  • Regression Testing and Why Suites GrowFixed things break again. Where a regression suite comes from, why every bug should leave a test behind, and how a suite turns into something nobody wants to run.
  • Severity, Priority and What Gets Fixed FirstSeverity is how bad it is; priority is when we deal with it. Why the two come apart, who decides each, and how to argue for a fix with evidence instead of feelings.
  • Smoke, Sanity and Acceptance TestingThe same software tested for different purposes: is the build worth testing, did this fix work, and would the person who asked for the feature accept it?
  • Static Testing and ReviewsThe cheapest defects to fix are the ones found before the code runs. Requirement reviews, code review as testing, and what a linter or type checker is really doing for you.
  • Test Data and EnvironmentsMost confusing test results are really data or environment problems. Building the state a test needs, keeping environments comparable, and never testing with real customer data.
  • Turning Requirements Into Test CasesRead a feature description, find what it does not say, and turn it into cases someone else can run: preconditions, steps, expected result, and one behaviour per case.
  • What Testing Is Actually ForNot to prove software works — that is impossible — but to buy information about risk before your users find it. What a test is, what QA is, and why testing early costs less than testing late.
  • When to Automate and When Not ToAutomation is code you now maintain. What it is genuinely good at, what only a human can judge, and how to tell a test worth automating from one that will just break.
  • Writing Your First Test PlanThe capstone: for one real feature, write down what you will test, what you will not, in what environment, with what data, and how you will know when you are finished.
  • Your First Automated TestWrite, run and read a real automated test: arrange, act, assert; what a good failure message looks like; and why a test that never fails is not a test.

Testing in Practice

  • Accessibility Checks in the PipelineWhat an automated audit can catch, the much larger part it cannot, and how to wire the machine-checkable half into CI without pretending the job is done.
  • Browser Tests With PlaywrightEnd-to-end tests that are not a liability: auto-waiting instead of sleeps, one user journey per test, tracing a failure, and running the same spec across browsers.
  • Bug Triage and Quality MetricsRunning triage so the queue stays meaningful, and choosing measures that survive contact with incentives — escaped defects and time-to-detect over test counts and pass rates.
  • Database State and IsolationTests that pass alone and fail together are almost always sharing state. Transactions, truncation, per-test schemas and why ordering dependence is a bug in the suite.
  • Faking External ServicesThird-party APIs are slow, rate-limited and occasionally down. Stubs, fakes, recorded responses and local doubles — and how to notice when your fake has drifted from reality.
  • Integration Tests and Their SeamsWhere to cut a system so an integration test is both realistic and fast: the seams worth testing across, and the ones that are really end-to-end tests in disguise.
  • Killing Flaky TestsA flaky test is a bug report about your suite. The four real causes — timing, shared state, ordering, real non-determinism — how to reproduce each, and why retries are not a fix.
  • Locators and Page ObjectsWhy CSS-path selectors break every sprint. Locating elements the way a user finds them, test ids as a deliberate contract, and page objects that help rather than hide.
  • Running the Suite in CIGetting from works-on-my-machine to a signal the team trusts: what runs on a pull request versus nightly, caching, artefacts on failure, and keeping the pipeline honest.
  • Structuring a Test SuiteHow a suite is laid out decides whether people run it. Naming, grouping, shared setup, the fast/slow split, and keeping the failure message enough to diagnose from.
  • Test Data Fixtures and FactoriesShared fixtures rot and duplicated setup hides intent. Factories with sensible defaults, building only what the test is about, and making the interesting value obvious.
  • Testing an HTTP APIStatus codes, headers, schemas and error bodies — testing the contract rather than the handler, including the authorisation cases everyone forgets.
  • Unit Tests That Earn Their KeepThe difference between testing behaviour and testing implementation, why the second kind fails on every refactor, and how to pick the unit worth isolating.
  • Visual and Snapshot TestingCatching the change no assertion describes. Snapshot tests and their rot, visual diffs and their noise, and how to keep either from becoming a rubber stamp.
  • What Coverage Does Not Tell YouLine, branch and path coverage, what each measures, and why a 90% number can sit on top of tests that assert nothing. Using coverage as a question, not a target.

TypeScript Foundations

  • Arrays and TuplesOrdered collections of a single type, fixed-length tuples where position carries meaning, and the index access that types promise but do not check.
  • Booleans, Conditions, and Truthinessif and else, why === is the comparison you use, and the falsy values that make an innocent condition reject a legitimate zero or empty string.
  • Classes and ObjectsFields, constructors, methods and access modifiers; how a class is both a value and a type; and the many problems a plain function and an object type solve better.
  • Configuring the CompilerThe tsconfig options that change how much the compiler protects you, what target and module actually control, and why strict should be on from the first day.
  • Enums and Literal TypesFixed sets of allowed values, why a union of string literals is usually the better tool, and what an enum actually compiles into.
  • Errors and Exceptionsthrow, try and catch; why a caught value is unknown rather than an Error; defining your own error types; and the empty catch block that turns a bug into a mystery.
  • Functions, Parameters, and Return TypesDeclaring functions, optional and default parameters, what void really means, and functions as values you can pass to other functions.
  • Interfaces Versus Type AliasesTwo ways to name a shape, what each can do that the other cannot, and a rule for choosing that will not start an argument in code review.
  • Loops and IterationWalking a collection with for...of, repeating until a condition changes, break and continue, and the loop over object keys that hands you strings you did not expect.
  • Modules, Import, and ExportSplitting a program across files, named and default exports, what a relative import path resolves to, and keeping the dependency arrows pointing one way.
  • Null, undefined, and Strict Null ChecksTwo different kinds of nothing, the errors they cause at runtime, and how strict null checking turns that whole category of crash into a compile error.
  • Numbers and Floating PointOne number type for everything, the arithmetic that surprises you, NaN and how it spreads, and what to reach for when you are counting money.
  • Objects and Type AliasesDescribing the shape of your data, naming that shape so it can be reused, optional and readonly properties, and why an object type is a contract rather than a class.
  • Promises and Async AwaitWhy some work does not finish immediately, what a promise represents, async and await, and the forgotten await that makes a function return before its work is done.
  • Setting Up and Running Your First FileGetting from nothing to a running, type-checked file: the runtime, the compiler, a real project folder, and what each generated file is for.
  • Strings and Template LiteralsBuilding text, template literals over concatenation, the string methods worth knowing, and why every string operation gives you a new string.
  • Union Types and NarrowingThe central idea of TypeScript: a value that could be one of several types, and how the compiler follows your checks to work out which one it is on each branch.
  • Values, Variables, and Basic TypesNaming values with let and const, the basic types, and why you usually let the compiler infer a type instead of writing it out.
  • Why TypeScript Exists and What It Runs OnThe class of bug types catch before your program ever runs, what the compiler does and pointedly does not do, and where the code you write actually executes.
  • Working with Collectionsmap, filter and reduce and the types that flow through them; Map and Set for lookups and uniqueness; and why a plain object is a poor dictionary.
  • Your First Real TypeScript ProgramBuilding a small tool end to end: modules, types at the edges, async work, error handling and a first test — every earlier lesson assembled into one working thing.

TypeScript in Practice

  • Async Patterns and ConcurrencyRunning work in parallel versus in sequence, all versus allSettled versus race, cancelling with an abort signal, and the awaited loop that made everything ten times slower.
  • Building and BundlingCompiling versus bundling, emitting declaration files, source maps that make production stack traces readable, and choosing an output that suits who consumes it.
  • Dependencies and Their Type DefinitionsWhere types come from when they are not in the package, community type packages, versions drifting apart, and typing a library that ships none.
  • Error Handling StrategiesThrowing versus returning a result, typed error unions, keeping error information across boundaries, and choosing one approach so callers do not have to guess.
  • Generics and Reusable TypesWriting a function or type that works for many types without losing the specific one, constraints that keep it honest, and the generic parameter that should have been a plain argument.
  • Linting and FormattingType-aware lint rules that catch what the compiler allows, separating formatting from correctness, and configuring both so they never disagree.
  • Modelling Domains with TypesMaking illegal states unrepresentable: replacing boolean flags with unions, encoding invariants in shapes, and letting the compiler enforce rules you were writing comments about.
  • Module Resolution, ESM, and CJSWhy an import that looks correct fails at runtime: the two module systems, resolution modes, file extensions, and reading the error instead of guessing at config.
  • Narrowing in DepthType guards, discriminated unions, and exhaustiveness checks that turn a new case into a compile error instead of a silent fall-through.
  • Project Structure and ReferencesOrganising a codebase that has outgrown one tsconfig: project references, incremental builds, path mapping, and dependency boundaries the compiler enforces.
  • Runtime Versus Compile TimeTypes are erased before your code runs. What that means for validation, reflection and generics, and the checks people expect the type system to perform at runtime.
  • Strict Mode and the Options That MatterWhat each strict flag actually catches, which additional options are worth the friction, and how to turn strictness on in a codebase that was not written for it.
  • Testing TypeScriptRunning tests against typed code, typing test helpers and fixtures without fighting them, and asserting on types themselves so a refactor cannot quietly widen an API.
  • TypeScript in CIType checking as a required gate, keeping it fast as the codebase grows, caching and incremental builds, and failing on the errors that matter.
  • unknown, any, and neverThe three types people misuse most: what each one means, why any disables the compiler far beyond the line it appears on, and what never is telling you when it shows up.
  • Utility TypesThe built-in transformations — Partial, Pick, Omit, Record, Required, Awaited and friends — what each is really for, and the point where a chain of them becomes unreadable.
  • Validating Data at the BoundaryAnything crossing into your program is unknown until proven otherwise. Parsing over casting, schema validation, and why a type assertion on API data is a lie with a compile-time blessing.