Your concept feed For you Start small Foundations Recursion Arrays Linked lists Trees Heaps Ranges Graphs Backtracking Tries Strings Think in DP 1D DP 2D DP 3D DP Advanced DP Greedy Math & bits Connect LLD HLD Learn Saved 0 Review 0 48 ideas
Follow the connections in this topic
A small step before this topic
Let’s picture it Let’s start with three stops. Home. Then the park. Then the café. Just a few things in a row.
One little change Point to the middle one. The park is second. In Python, its position is 1, because counting starts at 0.
Now it has a name That’s a list. A list keeps things in order. An index is just a position in that list.
No pressure. Just try it. Which place is at position 0? Home Park
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Now visit each stop. You don’t need three different instructions. “Visit the next place” works each time.
One little change One, then the next. Finish home. Move to the park. Then do the same at the café.
Now it has a name That repeat is a loop. One small action, repeated for each item. Three stops mean three visits.
No pressure. Just try it. Add one more stop. How many visits now? 3 4
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it What if it rains? Let’s choose the café on rainy days, and the park on sunny days.
One little change Today is sunny. The rule stays the same. The weather changed, so we choose the other place.
Now it has a name That’s an if / else. Raining?
Yes: café
No: park
A condition is a yes-or-no question. Its answer chooses which step happens next.
No pressure. Just try it. It’s raining. Where does our rule send us? The park The café
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Name a tiny job. Our job is “add one.” Give it 3, and it gives back 4.
One little change Try a new input. Give the same job 8. It gives back 9. We can reuse the instructions.
Now it has a name That job is a function. Input goes in. An answer comes back. In Python, return sends the answer back.
No pressure. Just try it. What does add-one return for 5? 6 5
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Picture a pile of plates. Blue goes down first. Pink goes on top.
One little change Take the top one. Pink comes off first, even though blue arrived first.
Now it has a name That’s a stack. Last in, first out. Paused function calls work this way too: finish the newest call, then return.
No pressure. Just try it. Add green on top. Which plate comes off next? Blue Green
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Have we visited the park? Keep a little checklist of places we’ve seen.
One little change Write park again. We still only need one check beside park. We’re remembering whether, not how many times.
Now it has a name That’s a set. A set keeps distinct items. “Is park in here?” becomes a quick membership check.
No pressure. Just try it. Add park twice. How many copies in a set? 1 2
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Let’s remember a little more. The park is five minutes away. Write that beside its name.
One little change Look it up later. Ask for “park.” The notebook gives you 5. No need to measure the walk again.
Now it has a name That’s a dictionary. A key finds a value. Here, the place name is the key and the time is the value.
No pressure. Just try it. We now write park: 6. What does park return? 5 and 6 6
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Draw our little walk. A dot for each place. A line where we can walk directly.
One little change Two short walks can join. Home to park, then park to café. We can reach the café without a direct road.
Now it has a name Dots and links have names. A dot is a node. A link is an edge. Together, they make a graph.
No pressure. Just try it. Must two places share a direct road to be reachable? No Yes
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Same door. One small difference. You have a key. Your friend doesn’t. The door is the same, but your next move isn’t.
One little change Remember the key. If we only write down “at the door,” we lose something important.
Now it has a name That little note is a state. A state remembers what we need to continue. Here: where we are, and whether we have the key.
No pressure. Just try it. Is “at the door” enough to decide if we can enter? Yes Not by itself
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it How many little jobs? Visit three places. Say hello once at each. That’s three hellos.
One little change Now try every pair. Three people each greet all three people, including themselves for this toy count. That’s nine greetings.
Now it has a name Count how the work grows. One pass grows with n. Trying every pair grows with n × n. Code length doesn’t tell us that.
No pressure. Just try it. With 4 items, how many ordered pairs, including self-pairs? 4 16
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Find 8 in a sorted row. Start with 2, 4, 6, 8, 10. Look at the middle: 6.
One little change Keep the side that can work. 8 is bigger than 6. Everything on the left is too small, so we can leave it behind.
Now it has a name Keep one promise. If 8 is present, it stays in the part we keep. That repeating promise is called an invariant.
No pressure. Just try it. Would this left-or-right shortcut work on an unsorted row? Not reliably Yes
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Open a box. There’s a smaller box inside. We already know how to open a box.
One little change Do the same small job again. Open the smaller box. Keep going until there isn’t another box inside.
Now it has a name That’s the idea of recursion. A function asks itself to handle a smaller case. The empty box is our stopping point: the base case.
No pressure. Just try it. What if every box contains another box forever? We stop anyway We need a stopping case
Next little step 1 / 4 A reminder Python My thought A small step before this topic
Let’s picture it Count a tiny family of dots. One parent has two children. Each child says, “There’s one of me.”
One little change Let the answers travel up. The parent adds the two answers, then counts itself: 1 + 1 + 1.
Now it has a name That works for bigger trees too. my answer
left answer
right answer
Ask each child about its little tree. Combine the answers. You don’t need to hold the whole tree in your head.
No pressure. Just try it. Do we also count the parent itself? Yes No
Next little step 1 / 4 A reminder Python My thought A small step before this topic
A familiar idea Start with one small responsibility. A room has two seats left. Booking one should leave one. Booking three should fail without changing anything.
One new wrinkle Keep the rule beside the data. seats
book(count)
never negative
If anyone can subtract seats anywhere, one caller may forget the check. Give booking to the object that owns availability.
Try a tiny example A class describes that little owner. class: room plan
object: this room
An object is one actual room created from the class. A method is an operation on that room; self refers to this particular room.
Notice what matters Different rooms keep separate state. Booking in room A should not reduce room B’s seats. Each object carries its own availability.
No pressure. Just try it. What should a failed booking do to the seat count? Leave it unchanged Subtract first and hope
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea An order and its receipt have different jobs. order: total
renderer: text
The order knows its items and total. The receipt renderer knows how to turn that information into text.
One new wrinkle Let one ask the other for help. A checkout object holds an order and a renderer. It delegates each small job rather than doing everything itself.
Try a tiny example That relationship is composition. has a helper
not is a helper
Checkout has a renderer. It is not a special kind of renderer. Changing the receipt layout need not change price calculations.
Notice what matters Separate changes, not every line. pricing changes
layout changes
Split responsibilities when they have genuinely different reasons to change. A tiny stable function does not need three extra classes.
No pressure. Just try it. Is “checkout is a kind of receipt renderer” the useful relationship? No, checkout uses one Yes
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea A reminder only needs a sender. It says “send this message.” It does not need to know whether the sender uses email, a screen, or a test notebook.
One new wrinkle Write down the small promise. send a string
return normally or raise
An interface describes the operations a caller relies on. Python’s Protocol can express that expected shape for a type checker.
Try a tiny example Pass the helper in. caller chooses sender
reminder uses sender
Give the reminder its sender when creating it. That is dependency injection: supplying a collaborator instead of building it secretly inside.
Notice what matters Tests can use a recording sender. real delivery
record in test
The test sender records messages without contacting anyone. It keeps the same promise, so the reminder workflow stays unchanged.
Make it reusable A matching name is not the whole contract. method shape
behavioral promise
Type hints do not enforce runtime behavior. A replacement must also respect agreed inputs, side effects, and failure behavior.
No pressure. Just try it. Should a unit test need to send a real email to test reminder wording? No, inject a recording sender Yes
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it The helper speaks a different language. send(message)
deliver(text, priority)
Our app calls send(message), but an old client exposes deliver(text, priority). Neither side needs a rewrite.
One little change Translate at the boundary. An adapter accepts the app’s small interface and calls the legacy method with the required arguments.
Now it has a name Adapt the meaning as well as the names. same promise
translated call
Choose a documented priority and preserve failures. Renaming a method is not enough if success means something different.
No pressure. Just try it. Does an adapter need to replace the legacy implementation? No, it delegates to it Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A caller wants one useful operation. Preparing a lesson session may require loading a lesson, finding a saved note, and assembling a display.
One little change Offer an entry point for that workflow. A facade exposes open_lesson(id) and delegates to the relevant collaborators. The caller need not sequence them itself.
Now it has a name Do not let convenience swallow every responsibility. coordinate here
implement details there
The facade coordinates. Loading, storage, and formatting still belong to focused helpers with their own contracts.
No pressure. Just try it. Should the facade become the implementation of every subsystem? No, it should delegate Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Five names. One aim: contain change. Suppose report content changes separately from where it is saved. Keep those responsibilities separate. That is single responsibility.
One new wrinkle Add a new option without rewriting callers. A new storage implementation can keep the same save promise. That is the useful part of open–closed design.
Try a tiny example A replacement must keep its promise. promises save
must support save
A read-only store cannot pretend to be a writable store and fail every save. This is the substitution rule.
Notice what matters Ask only for abilities you use. A report saver needs save, not delete and search too. A small interface avoids forcing unrelated capabilities.
Make it reusable Depend on the promise, not the concrete helper. service
save contract
chosen store
Pass a store into the report service. The service describes what it needs; storage details stay outside. This is dependency inversion.
Name the idea SOLID is a review lens, not a class quota. clear responsibility
honest contract
small dependency
Use these checks when a real change or broken contract exposes a problem. More abstractions are not automatically a better design.
No pressure. Just try it. Does adding an interface for every tiny function guarantee good design? No, it can add needless complexity Yes
Next little step 1 / 7 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Delivery pricing has two possible rules. One shop charges a flat 50 units. Another charges 10 per item. Checkout still needs one fee.
One new wrinkle Keep the changing rule in one place. Pass a fee function to checkout. For three items, one function returns 50 and the other returns 30.
Try a tiny example That replaceable rule is a strategy. same workflow
different policy
The owner keeps its workflow. The strategy supplies the part that varies. In Python, a function is often enough.
Notice what matters The policy still needs a contract. input count
output fee
same units
Agree on input meaning, currency units, valid counts, and failures. Swapping functions is safe only if those promises match.
No pressure. Just try it. What changes when a new delivery rule is added? The supplied pricing policy Every checkout caller
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Keep the operation. Add one behavior. sender
successful-send count
A sender already works. We want to count successful sends without editing the sender or every caller.
One little change Wrap a sender with another sender. caller
counting wrapper
sender
The wrapper calls its inner sender, then increments its count. Callers still use send(message).
Now it has a name Order changes the meaning. attempts before
successes after
Counting after delegation records successes. Counting before it records attempts. Decide which metric you promised.
No pressure. Just try it. If the inner sender fails, should a success counter increase? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Someone still has to choose the strategy. configuration
working policy
Configuration says flat or per-item. We need to turn that small setting into a usable pricing object.
One new wrinkle Put construction choices in one place. flat setting
FlatFee object
A factory reads the setting and builds the appropriate object. Callers receive the common fee interface.
Try a tiny example Factory and strategy answer different questions. Factory: which object do we create? Strategy: which rule does the workflow use? They can work together.
Notice what matters Reject a setting we do not understand. unknown setting
clear error
Silently selecting a default could charge the wrong fee. Invalid configuration should fail clearly before checkout proceeds.
No pressure. Just try it. Is returning any object enough for a factory? No, it must satisfy the caller’s contract Yes
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A request has several optional choices. Method, path, headers, and timeout are easier to inspect as named choices than a long positional constructor.
One little change Assemble first. Validate before use. choose options
validate
build
A builder gathers choices. build checks that required fields exist and returns a separate usable value.
Now it has a name The built value must not keep changing. builder changes
old request stays
Copy mutable settings into the result. Reusing the builder should not edit an earlier request by accident.
No pressure. Just try it. Should changing the builder later mutate an already built request? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Copy a configured starting point. A report template has a title and a list of columns. A new report should inherit those choices but be editable independently.
One little change An outer copy can still share inner data. A shallow dictionary copy keeps its nested column list shared. Editing that list then changes both reports.
Now it has a name Choose what becomes independently owned. copied data
recreated resources
Deep copying works for this data-only example. Connections, locks, and external resources need an explicit reconstruction policy.
No pressure. Just try it. Does an outer dictionary copy always copy nested lists? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Some products need to belong to one family. A text interface wants text buttons and checkboxes. A symbol-based interface wants matching symbolic versions.
One little change Choose the family once. The chosen factory supplies both products. Callers do not independently mix concrete products from incompatible families.
Now it has a name Compatibility earns the extra abstraction. related products
shared family promise
Abstract Factory supplies related products together. If there is no family constraint, separate constructors may be enough.
No pressure. Just try it. What does Abstract Factory add beyond creating one object? A compatible product family Automatic singleton lifetime
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Some workflows need a fixed order. Read values, validate them, transform them, then return a result. Different importers may vary only the transform step.
One little change Keep the skeleton in one method. fixed workflow
replace one step
The base run method fixes the sequence. A subclass supplies the named variation point.
Now it has a name The base promise still applies. same contract
different transform
A subclass must honor validation and output expectations. Inheritance does not excuse breaking the caller’s contract.
No pressure. Just try it. How does Template Method differ from a supplied Strategy object? It varies steps through inheritance It always uses a faster algorithm
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A creator owns a stable workflow. An exporter creates a formatter, formats records, and returns text. Its subclass chooses which formatter gets created.
One little change Make construction the overridable step. creator workflow
creation hook
The base workflow calls make_formatter. A subclass supplies the product without rewriting the surrounding sequence.
Now it has a name Similar names hide different boundaries. simple factory
factory method
abstract factory
Simple factory selects by configuration. Factory Method uses a subclass hook. Abstract Factory provides a compatible set of products.
No pressure. Just try it. What is the variation point in this creator? Which formatter it constructs The meaning of every caller’s data
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it You do not need every item at once. A page has two notes. Ask for the next page only when those notes have been consumed.
One little change Expose one item at a time. A Python generator keeps its paused position between yields. The caller can use a normal for loop without knowing the paging details.
Now it has a name Define what happens as data changes. iteration order
snapshot? separate promise
A cursor can move through a stable order, but pagination alone does not promise a snapshot while concurrent writes occur.
No pressure. Just try it. Does returning an iterator automatically make a remote dataset a consistent snapshot? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea One event can have several listeners. card saved
counter
notebook
Saving a learning card might update a counter and record a notebook event. The saver need not own both reactions.
One new wrinkle Let interested helpers subscribe. publisher
listener A
listener B
The publisher keeps listeners. When an event happens, it tells each one through the same callback shape.
Try a tiny example Decide what failure means. If one listener fails, should the others run? Our small example keeps notifying and returns the failures to the caller.
Notice what matters Observer is a local notification pattern. same process
explicit failure rules
This version is synchronous and in memory. It does not promise delivery after a process crash or make slow listeners disappear.
No pressure. Just try it. Does a local observer automatically provide durable event delivery? No Yes
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it An action can become a small object. “Append hello” can remember both the target document and the requested text instead of running immediately.
One little change Execute it when the caller chooses. A queue or button can hold this command. It does not need to understand how the document changes.
Now it has a name Undo needs its own promise. Remember the previous text. Undo is safe only if no later unrelated edit has changed the document since this command ran.
No pressure. Just try it. Can every external action be undone merely because it is a command? No, undo needs real inverse behavior Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Keep a restorable earlier draft. Save a document snapshot before editing. A history manager can hold it without implementing how restoration works.
One little change Let the state owner restore it. The document creates and accepts its own snapshots. A snapshot from a different document should not silently overwrite this one.
Now it has a name Local restoration has a boundary. local state restored
external effects remain
A restored document does not undo an email already sent. Snapshot history also consumes storage that needs a lifetime policy.
No pressure. Just try it. Does restoring local state reverse every external side effect? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Peers do not need to know every other peer. A chat participant sends through a room. The room decides which other participants receive the message.
One little change Put collaboration rules in one place. membership
routing
coordinator
The room owns membership and routing. Participants only submit or receive messages through a small boundary.
Now it has a name Keep that coordinator focused. coordination
not every responsibility
A mediator reduces tangled peer references. It should not absorb every unrelated feature just because messages pass through it.
No pressure. Just try it. Must each participant hold references to every other participant? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A request passes through several decisions. First check whether its shape is valid. Then check permission. Finally call the business operation.
One little change A handler may stop the chain. Invalid input should not reach the business operation. A failed permission check should not merely add a warning and continue.
Now it has a name Order is part of the contract. ordered handlers
explicit continuation
Each handler decides whether to reject or forward. Keep that decision visible instead of scattering checks across callers.
No pressure. Just try it. Should a denied request continue to the final operation? No Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea The same action can mean different things. locked
paid → unlocked
push → locked
Push a locked turnstile: stay locked. Insert payment: unlock. Push now: let one person through, then lock again.
One new wrinkle Name the states before adding flags. Locked and unlocked describe which actions are currently legal. A transition says how an action changes the state.
Try a tiny example Keep transitions in one checked doorway. checked action
consistent next state
If callers change unrelated paid and open flags directly, impossible combinations can appear. One operation should own each transition.
Notice what matters Start with a small state machine. simple enum now
State objects if needed
An enum and clear conditions are enough here. Separate State objects become useful when each state gains substantial behavior.
No pressure. Just try it. Must every two-state object use a separate class for each state? No, clear transitions may be enough Yes
Next little step 1 / 5 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A group can contain items or smaller groups. A file has a size. A folder’s size is the sum of its children, which may themselves be folders.
One little change Give both the same small operation. Call size on a leaf or a group. The group delegates to its children and combines their answers.
Now it has a name This is tree recursion expressed as object design. leaf: direct answer
group: combine
Composite makes leaves and groups usable through one operation. The input must obey the promised tree structure.
No pressure. Just try it. What happens if a folder contains itself in this simple recursive design? The tree assumption breaks It automatically deduplicates
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Two dimensions can vary independently. remote features
device implementations
Basic and advanced remotes can control speakers or screens. Subclassing every pair makes combinations multiply.
One little change Connect them through a small interface. remote
device contract
implementation
A remote holds a device that supports power and volume. New remotes and new devices can then vary independently.
Now it has a name A bridge anticipates variation. bridge: separate axes
adapter: translate mismatch
An adapter translates an incompatible existing interface. A bridge separates two changing dimensions in the design itself.
No pressure. Just try it. Do five remotes and four devices require twenty combined subclasses? No, compose the dimensions Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Element types stay stable while operations grow. A tree contains numbers and additions. Evaluation and formatting are two different operations over those same elements.
One little change Let the operation visit each element kind. An element accepts a visitor and calls the matching method. The visitor owns the operation’s behavior across the tree.
Now it has a name The tradeoff has a direction. new operation: local
new type: many updates
Adding an operation is convenient. Adding a new element type requires updating visitors that promise to handle every type.
No pressure. Just try it. Which change does Visitor make easier? New operations over stable types New types without updating operations
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it A tiny rule language can stay tiny. A rule is a named flag or two rules joined with AND. That is enough to express member AND active.
One little change Make the grammar a tree. Flag reads one context value. And evaluates its children and combines their truth values.
Now it has a name Evaluate known operations, not arbitrary code. allowed grammar
bounded evaluation
A larger language needs parsing, validation, and work limits. User text should not become unrestricted Python execution.
No pressure. Just try it. Should user rule text go directly into Python eval? No, interpret a constrained grammar Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Many labels share one style. Text and position differ, but font family and size repeat. Share the repeated style instead of copying it into every label.
One little change Keep per-use state outside the shared value. shared: style
separate: position
A style is immutable. Each label keeps its own text and position, so moving one label does not move the others.
Now it has a name Reuse helps only when values repeat. same key: reuse
new key: new value
A factory reuses a style for each key. If every style is unique, the factory can still grow without bound.
No pressure. Just try it. Where should a label’s position live? Outside the shared style Inside the shared style
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it The domain wants a saved note, not a SQL string. Let a notebook service ask a repository for notes. The repository owns how those notes are stored and queried.
One little change A write may change several related things. several changes
one commit
A unit of work groups those changes into one commit or rollback boundary. Repository methods alone do not guarantee atomicity.
Now it has a name Tests can supply local storage. memory test
database adapter
A memory repository checks domain behavior without a live database. It is useful only if its relevant semantics match the real adapter.
No pressure. Just try it. Does having a repository automatically make multiple writes transactional? No, define the unit of work Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Keep only two useful answers nearby. Put A, then B into a capacity-two cache. A is the least recently used entry.
One new wrinkle Reading A changes the order. B oldest
A newest
C arrives
A was just used, so B becomes the oldest. Adding C must evict B, not A.
Try a tiny example One structure is not enough. dictionary: find
linked list: reorder
A dictionary finds an entry quickly. A doubly linked list can detach that entry and move it to the recent end quickly.
Notice what matters Let the cache own both structures. Every stored key must have exactly one list node. All get and put operations preserve that shared invariant.
Make it reusable Use sentinels to simplify the ends. Dummy head and tail nodes make removal and insertion follow the same pointer rules, even for the first or last real entry.
No pressure. Just try it. After put(A), put(B), get(A), put(C), which key leaves a capacity-two cache? B A
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Sometimes we should avoid calling the real helper. A slow lookup returns the same value repeatedly. A cache proxy can answer a hit without reaching the underlying source.
One little change Keep the same lookup interface. On a miss, ask the real source and remember the result. The caller still uses get(key).
Now it has a name Control comes with a freshness rule. immutable value ✓
changing value: new rules
Our example caches immutable values only. Mutable data would need expiry, invalidation, or a version-aware key.
No pressure. Just try it. Can this forever-cache safely wrap arbitrary changing data? No, it needs a freshness policy Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Ask what this parking lot must do. For this first design: park a vehicle, issue a ticket, then release the spot. No reservations or payment yet.
One new wrinkle Write two rules we must not break. spot: one vehicle
vehicle: one ticket
One vehicle per spot. One active ticket per vehicle. These rules matter more than how many classes we draw.
Try a tiny example Give the pieces small responsibilities. spot
ticket
lot coordinator
A spot knows whether a vehicle fits. A ticket identifies a stay. The lot coordinates claiming and releasing.
Notice what matters Choose a fitting free spot, then commit. check fit
choose free spot
commit together
Our policy picks the smallest fitting spot. If none exists, return unavailable without creating a ticket.
Make it reusable Closing the ticket reverses the allocation. ticket identity
matching stay
release
A valid ticket frees exactly its spot. Repeating an old exit must not free a different vehicle’s later stay.
No pressure. Just try it. Two gates see the same free spot. Is checking before assigning enough? No, check-and-claim must be atomic Yes
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea A purchase changes two kinds of state. credit: 50
price: 30
change: 20
A snack costs 30 units. You insert 50. Successful vending removes one snack and returns 20 change.
One new wrinkle A failed attempt must not lose money. check stock
check credit
then commit
If the snack is sold out or credit is too low, keep the credit and stock unchanged.
Try a tiny example Make cancellation a real operation. credit: 50
cancel
refund: 50
Before a successful purchase, cancel returns all inserted credit and resets it to zero.
Notice what matters Put validation before both mutations. all checks pass
stock −1
credit → 0
Only after every check passes do we decrease stock and consume credit. That protects the purchase boundary in this single-threaded simulator.
Make it reusable Real hardware adds another uncertain step. paid
dispensing?
confirmed or failed
Dispensing can jam after payment. A real machine needs pending and failed states plus recovery. Our simulation assumes dispensing always succeeds.
No pressure. Just try it. The chosen snack is unavailable. What happens to inserted credit? Keep it available for retry or refund Discard it
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Design one small elevator simulation first. floor 0
request 2
request 5
Start at floor 0 with requests for floors 2 and 5. We will serve a fixed batch with a simple nearest-stop policy.
One new wrinkle Picking a stop is a policy. choose next stop
move to it
Nearest-stop chooses 2 before 5. A directional sweep or FIFO queue could make a different choice without changing movement rules.
Try a tiny example Doors and movement constrain each other. Our controller closes doors before moving, changes one floor per tick, and opens only after reaching a requested floor.
Notice what matters Remember pending requests without duplicates. pending: {2,5}
serve 2
pending: {5}
A set is enough for this fixed batch. Serving a floor removes it once, even if its button was pressed twice.
Make it reusable Keep the assumptions visible. simulation
not hardware control
Real elevators need safety interlocks and richer dispatch. Nearest-stop can starve far requests under continuous arrivals; our fixed-batch example makes no fairness claim.
No pressure. Just try it. Is nearest-stop guaranteed fair when nearby requests keep arriving forever? No Yes
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea Split 100 small currency units among three friends. Equal division leaves a remainder. Use shares 34, 33, 33 under an explicit, deterministic remainder rule.
One new wrinkle Suppose Ana paid the full 100. Ana’s net credit is 100 − 34 = 66. Bo and Cy each owe 33. The balances still add to zero.
Try a tiny example Keep money in integer units. integer units
one currency
Store cents or paise, not binary floating-point approximations. Record which currency the ledger represents.
Notice what matters Validate the whole split first. shares sum correctly?
commit balances + record
Shares must be nonnegative and total the expense exactly. Only then update balances and retain the expense record.
Make it reusable Net balance and original debt are different views. net balances
audit records
Balances help settle totals. The expense log explains how they arose. Netting does not preserve each original person-to-person obligation.
No pressure. Just try it. What should all net balances sum to after every valid expense? Zero The full expense amount
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
A familiar idea The happy path is only one sequence. thread A: free?
thread B: free?
One spot is free. Two threads both check it before either claims it. Both could think they succeeded.
One new wrinkle Protect check and claim together. A lock makes those steps one critical section inside this process. The second caller then sees the first caller’s committed result.
Try a tiny example Now the same request arrives again. request r7
retry r7
same result
A timeout caused a retry. Give requests stable IDs and remember completed results, so the same claim is not executed twice.
Notice what matters Detect conflicting reuse too. same ID
different payload
reject
If r7 later requests a different spot, reject it. An idempotency key identifies one operation, not permission to change its payload.
Make it reusable Test promises across operation sequences. invariants
retries
failure boundaries
Check duplicate retries, competing claims, and invalid requests. A local lock is not enough for multiple servers or recovery after a crash.
No pressure. Just try it. Does a Python lock stop a second server process from claiming the same database row? No, use a shared transactional boundary Yes
Next little step 1 / 6 Mental model Why it fits A reminder Python My thought A small step before this topic
Let’s picture it Some helpers should live for the whole application. one app lifetime
many callers
A configuration value or connection pool may be shared. That is a lifetime decision, not proof every caller should fetch a global object.
One little change Let the application own that lifetime. application
service A
service B
Create the shared helper at startup and pass it to services. Tests can create a separate application with a different helper.
Now it has a name Know what “one” means. one process
not one distributed system
A language-level singleton is usually one per process, not one across every server. Hidden globals also make tests and replacement harder.
No pressure. Just try it. Does one singleton in each of three server processes create one shared distributed instance? No, there are three process-local instances Yes
Next little step 1 / 4 Mental model Why it fits A reminder Python My thought Keep a connection for later. Tap the bookmark on any post to find it here.
Explore the course