Google, AWS, and PostgreSQL reading paired with small exercises that leave you with something better than another bookmark.

You can recognize every box in a system design diagram and still get uncomfortable when someone asks why it belongs there.

A cache makes sense until somebody asks how stale the result can be. Retries sound sensible until the first request succeeds and its response disappears. An index looks helpful until you have to explain whether the database actually uses it.

Honestly, this is where I want preparation to become a little less decorative.

I like a resource more when it helps me produce a decision I can defend. Reading a chapter is a perfectly nice afternoon, but writing down what counts as a good outcome, drawing a retry timeline, or inspecting a query plan gives the reading somewhere to land.

These three resources are publicly readable without buying a course. They cover different pieces of the conversation, and each comes with a small practice task of my own. You do not need an AWS account or paid cloud infrastructure for the exercises below.

Three notebook cards introduce free system-design reading from Google, AWS, and PostgreSQL, focused on reliability, safe retries, and query plans.

Start with Google’s SRE Workbook when reliable feels too vague

Open Implementing SLOs in Google’s SRE Workbook, particularly the discussion of what to measure and the distinction between an indicator and an objective. It is useful for turning a broad reliability aspiration into a measurable service promise.

You do not need to read the whole book before making this practical. Pick one user journey and decide which outcomes belong in the calculation.

For an original exercise, imagine a small document app. A signed-in user opens a document they are allowed to read. Our illustrative proposal is that 99.5% of eligible load attempts return the correct document within 500 milliseconds over a rolling 28-day window.

The percentage and timing are practice assumptions, not targets Google recommends for every product. Write down why the user would care about them and what evidence you would need before adopting them.

A service-promise card defines the document-loading journey, a good outcome, eligible attempts, and an illustrative target.

Now make the denominator less slippery. An eligible attempt in this exercise is a valid request from an authorized user for an existing document. Server errors and timeouts on those attempts remain in the denominator. Removing them would make the service look healthier by hiding the very failures we care about.

For the exercise, measure elapsed time from the user action until the document is usable in the client. Record a timeout as a bad outcome at the agreed timeout threshold. This is different from timing only the database query or only a successful server response.

Try a tiny counting check. If 20,000 eligible attempts occur, a 99.5% target leaves room for 100 bad outcomes. That is a request-count calculation; it does not translate directly into a fixed number of outage minutes.

Your output is a short service promise card containing the journey, eligibility rule, good-outcome rule, measurement point, and window. Then explain one case your proposed telemetry could miss. That last part keeps a tidy definition from becoming false confidence.

Use the AWS Builders’ Library when retry sounds like the whole answer

Next, read Making retries safe with idempotent APIs. Focus on caller-provided request identifiers, late requests, and the distinction between reusing an identifier and expressing a new intent.

This is a good companion to the first exercise because a reliable-looking response is not enough if repeating the operation creates an extra resource.

Keep the same document app. Imagine the user creates a document, the server commits it, and the response is lost. The client cannot tell whether creation happened, so it retries.

For our practice contract, the client sends a key called K7. The server records that K7 belongs to document D42 for this account and this request intent. A repeated request with the same key and intent resolves to that same operation. A genuinely new document needs a new key, even if its title happens to match.

Three requests using key K7 resolve to document D42, while a changed intent with the same key is rejected under the proposed contract.

Draw three attempts on paper, including the lost response. Under each attempt, write the document count and the identity returned to the caller. We want one document, not three successful-looking acknowledgements for three accidental creations.

Then make the exercise less polite. Send the same key with different contents and decide the conflict response. Let two identical requests arrive concurrently and explain how the server prevents both from independently creating a document. Finally, let a retry arrive after the stored key has expired and state what the contract can still guarantee.

Keep these as explicit design questions rather than quietly assuming a dictionary solves them. In a real implementation, coordinating the key record with the resource creation and handling in-progress operations require deliberate storage semantics.

Your output is a retry timeline with expected outcomes and unresolved decisions. You can do this entire exercise with a notebook. The reading contains cloud examples, but reproducing their infrastructure is not necessary for this practice task.

Open PostgreSQL’s EXPLAIN guide when add an index becomes a reflex

Use the PostgreSQL documentation on Using EXPLAIN. Start with the basics and the EXPLAIN ANALYZE section. The important distinction is between a planner’s estimates and measurements gathered by actually executing a query.

This exercise assumes you already have a local PostgreSQL database and understand basic SELECT queries. Reading the guide is free; the hands-on part needs a local installation or another environment you control.

Return to the document app. Its recent-documents view filters by owner, orders by update time, and shows the first twenty results. Sketch the query and predict where the work will happen before inspecting a plan.

For your own fixture, choose an owner distribution and enough rows to make the experiment meaningful. Keep the fixture disposable. A table with ten rows may quite reasonably make an index look unnecessary, so record the dataset size rather than treating any one plan as universal.

A local query experiment compares scan type, row counts, buffers, and time before and after one deliberate change, with no invented benchmark results.

Here is a manageable experiment you can repeat.

  • Save the query, dataset description, PostgreSQL version, and initial plan.
  • Propose one index that matches the filter and ordering, and explain the work you expect it to reduce.
  • Refresh relevant statistics after loading the fixture, then compare plans and results under the same conditions.
  • Check both correctness and the measured work, including whether the improvement remains useful for a different owner with many more documents.

Use EXPLAIN ANALYZE only on a safe local query you intend to execute, because it runs the statement. Planner costs are not milliseconds, and one faster timing is not enough to establish a reliable improvement. Cache state and the data distribution can affect your observation.

Your output is a before-and-after comparison with actual measurements. If the plan does not change, that is still useful evidence to investigate. The goal is not to persuade PostgreSQL to validate your first guess.

Bring the three pieces back into one explanation

These resources become more useful together because they make you discuss the same app from different directions.

The service-promise card describes the experience you care about. The retry timeline describes what must remain true when communication fails. The query comparison gives you evidence about one piece of the performance story.

None of them replaces a full system design. Together, though, they make it harder to hide behind a diagram full of familiar components.

A final notebook checklist asks readers to keep a service promise, a retry timeline, and a query comparison, then explain one changeable assumption.

Close the source tabs and explain the app aloud for five minutes. Start with the user action, describe the promise, walk through the lost response, and explain what the query experiment did or did not demonstrate. If a statement depends on an assumption, say the assumption.

For another round, choose a problem from this interview practice collection and bring just one of these exercises into it. A small, relevant application is more useful than trying to squeeze every chapter into every answer.

I prefer finishing with three imperfect artifacts I can discuss over thirty pristine bookmarks I have not used. An unanswered question written beside a real example gives the next practice session a useful starting point.

Save the resources, absolutely, but give yourself something to explain before collecting the next three.

~ Emily