---
title: 'Low-Level Design Interview: Design Amazon Locker with an Ex-Meta Staff Engineer'
source: 'https://youtube.com/watch?v=s6nGkoGJhXk'
video_id: 's6nGkoGJhXk'
date: 2026-08-04
duration_sec: 3055
---

# Low-Level Design Interview: Design Amazon Locker with an Ex-Meta Staff Engineer

> Source: [Low-Level Design Interview: Design Amazon Locker with an Ex-Meta Staff Engineer](https://youtube.com/watch?v=s6nGkoGJhXk)

## Summary

This video provides a comprehensive walkthrough of a low-level design interview question focused on designing an Amazon Locker system. The presenter, an ex-Meta staff engineer, demonstrates a structured framework for approaching such problems, covering requirements gathering, entity identification, class design, implementation, and extensibility considerations. The video is aimed at software engineers preparing for system design interviews, offering practical advice and code examples.

### Key Points

- **Introduction to Amazon Locker Design Problem** [00:01] — The video introduces the Amazon Locker low-level design interview question, noting it's commonly asked at Amazon and is on the easier side. The presenter is an ex-Meta staff engineer and co-founder of Hello Interview.
- **Framework for Low-Level Design Interviews** [01:21] — The presenter outlines a 5-step framework: 1) Cover requirements, 2) Define entities, 3) Class design, 4) Implementation, 5) Extensibility. This framework ensures all important aspects are covered without running out of time.
- **Problem Statement: Design a Locker System** [03:18] — The problem: Design a locker system like Amazon Locker where delivery drivers deposit packages and customers pick them up using a code. The presenter explains the real-world context of Amazon Locker.
- **Importance of Clarifying Questions** [04:25] — The presenter emphasizes the need to ask clarifying questions to define requirements. Categories: primary capabilities, error handling, and scope boundaries. Example questions: different compartment sizes, how customers get codes, package expiration.
- **Finalized Requirements** [06:33] — Five key requirements: 1) Driver deposits package by size, 2) System assigns compartment and returns access code, 3) User retrieves package with access token, 4) Access tokens expire after 7 days, 5) Staff clears expired compartments. Out of scope: logistics, SMS/email notifications.
- **Identifying Entities** [08:05] — Entities identified: Package, Compartment, Locker, AccessToken. Driver and User are external and not modeled. Package is just an input parameter (size matters). Compartment, Locker, and AccessToken are core classes.
- **Class Design: Locker** [12:28] — Locker class: state includes compartments (list) and accessTokens (map from code to AccessToken). Behaviors: depositPackage(size) returns code, pickup(code) returns void or error, openExpiredCompartments() returns void.
- **Class Design: AccessToken** [17:14] — AccessToken class: state includes code (string), expiration timestamp, compartment. Behaviors: isExpired(), getCompartment(), getCode(). Simple getters and a check.
- **Class Design: Compartment** [18:51] — Compartment class: state includes size (enum: small, medium, large) and isOccupied (boolean). Behaviors: isOccupied(), markOccupied(), markFree(), open(), getSize(). Encapsulates physical state.
- **Implementation: Deposit Package** [21:28] — Core logic: find available compartment, open it, mark occupied, generate access token, store token, return code. Edge cases: no compartment of right size -> throw error. Uses helper methods for readability.
- **Implementation: Pickup Package** [30:30] — Core logic: look up access token by code, get compartment, open it, mark free, remove code from map. Edge cases: empty code, code not in map, expired token -> throw errors.
- **Implementation: Open Expired Compartments** [35:46] — Core logic: iterate over access tokens, find expired ones, open compartments, mark free. Decision: do not remove from map to give 'expired' error instead of 'invalid'. Corner cases: empty map or all expired are fine.
- **Extensibility: Fallback to Larger Compartments** [41:00] — Modify getAvailableCompartment to iterate over sizes starting from requested size, allowing smaller packages to use larger compartments if exact size is full.
- **Extensibility: Handling Broken Compartments** [44:11] — Introduce an enum CompartmentStatus (available, occupied, outOfService) to replace boolean isOccupied. This adheres to information expert principle.
- **Extensibility: Two-Phase Commit for Deposit** [45:48] — Split depositPackage into reserveCompartment and confirmDeposit to ensure package is actually deposited before generating access token. Add 'reserved' status to compartment.

### Conclusion

The video effectively demonstrates a structured approach to low-level design interviews, emphasizing the importance of clarifying requirements, clean class design, and thoughtful implementation. The extensibility discussion highlights common follow-up questions and how to handle them, making it a valuable resource for interview preparation.

## Transcript

another really common low-level design interview question. This time it's going to be Amazon locker. Another one that's on the on the easier side, but is really commonly asked at Amazon in particular. And so you'll see how I would answer
this question, as well as how I, as an interviewer, think through evaluating Now, for those of you who are new here Metastaff engineer and the current co-founder of Hello Interview. Hello
software engineers just like you prepare for their upcoming interviews. And so we system design, ML system design, low-level design, as we're talking about today, code, behavioral, salary negotiation. You go down the list. Tons
of content, videos, the overwhelming majority of which is free. So come over to the site and check it out. Uh for this particular problem, if videos are read our written breakdown. We walk through everything that we're talking
about here today as well as proper uh implementations uh in each of the core languages. So you can come check that out. Um of course if like and subscribe. I always forget to say that, but I should say that right
out of the gate. Uh all right, let's get after it. to follow both in this YouTube video as well as the framework that I suggest you
design interviews. And the goal of this framework or any framework really is to ensuring that you touch on all of the most important things and don't end up running out of time in what is a short interview typically. So, the first step
cover the requirements. You're going to spend some time here engaging in a back to understand exactly what it is that you're building and have an agreed upon set of requirements that's going to take you forward. From there, you want to
relationships. This is basically asking like what are the nouns of my system? What are the things that I'm going to want to model as classes or enums moving forward? And then with those in hand, you can move on to your class design in
order to take those entities, go through them one by one using your requirements to derive both the state and the behavior for each one of your entities or each one of your classes. And then in this case, state is just the things that
you need to remember in order to enforce the the requirements. And the behavior uh is what the class needs to be able to do. Basically, the functions you're kind of creating the interface for the code. And then you can move on to number four.
Well, with that class design in hand, we need to actually go implement it. And so, this is different by each company and each region. Some companies or the majority of companies just prefer pseudo code here instead of actual code.
They're worried more about your design choices than your syntax. For this on pseudo code and keep it language agnostic. Um, but for the full implementation, Java, Python, TypeScript, other languages, they're all
description. So, if that's what you're after, go check that out there. And then interview, if time permits, you tackle extensibility. And so, these are just follow-up questions about how the design could evolve. Uh, I'll cover what some
of the most popular ones are for this particular question as we get to the particular question as we get to the end. you just walked into your first low-level design interview and you were
greeted with this prompt on the whiteboard. Design a locker system like Amazon Locker where delivery drivers can deposit packages and customers can pick deposit packages and customers can pick them up using a code. Quickly, if you're
think it's in all parts of the world. Here's what it is. It's basically this self-s serve kiosk that you can use to schedule picking up your packages. So, from Amazon, you can say you'd like it
They're kind of positioned all over the city. The driver comes up, a door opens, they put your package in, they close it, and then they send you a code, you come with that code at some later date. You type it in, the the door opens, and you
can take your package. So, if you live in uh, you know, some location that it's not safe to deliver packages, this is oftent times what ends up being used. have gotten this prompt and some of you might be thinking, okay, I heard that I
know exactly what to do. Let me get coding. Um, but but please don't Uh the intentional. Your interviewer wants to see if you have the ability to ask clarifying questions in order to hone in on a final set of requirements. This is
unquote problem analysis. And it's explicitly something that your the end of the interview, they're going to go through a set of criteria. One of break down the problem and define a clear set of requirements from it. So
want to ask some questions. Candidates usually ask me, well, how do I know what what to ask. And my answer to them is that you should focus on three key categories. The first is the primary capabilities of the system. The second
is any error handling of the system. And the third is any scope boundaries. What's in scope? What's out of scope? And so in this particular question here, or in this particular problem, maybe it's an overused question. Here's a set
to paste them in so you don't see me type them all. capabilities, you might ask your interviewer, are there different sized would answer yes. There's there's small, medium, and large, and you should put
compartment. What about how does the customer get their code? Do we need to send them an SMS or an email? We'll say that's out of scope, right? You just function is that ends up calling you will end up getting the code to the
user. For error handling, we could ask, can one customer have multiple packages your interviewer would say, yes, they can, but they'd all have their own individual access token in their own individual compartment. Easy enough. And
ever expire if someone doesn't pick it up? Let's say after 7 days, they expire. And then after that expiration, then staff can come back and grab that package, maybe bring it back to the warehouse or whatever it may be. Uh and
size are full when the driver tries to deposit it? Let's just throw an error in this case. Lastly, we can ask further about scope. What's in scope for the delivery flow or just the pieces where the driver arrives at the locker until
interviewer would respond, it's just that part at the end. It's just when the customer picks it up. Everything else is out of scope and and managed by some higher order service. And so once you've
have been taking notes the whole time. And you'll eventually be able to land on here. I'll paste them in so you don't see me type it. The clear requirements that we have are five things. First, the driver, the carrier deposits a package
by specifying the size. When they do this, the specific compartment is going then it's also going to return that access code so that some other parent service can send that via SMS or email
to the user. After they successfully deposit, that access token is generated. that's a bit redundant there. The user is then going to retrieve their package by entering that access token. Uh, and then that door is going to open and
We mentioned that access tokens expire after 7 days and that there's that staff component there where they come in every per every so often and clear out um the
compartments that have expired access tokens. out of scope, how it got to the the logistics, all of that is out of scope for us, as well as, as we mentioned, the SMS or email notifications. And so, as you're
interviewer, you're probably doing this a little bit more integrated, like asking questions, you're writing requirements, uh, asking questions. I because I figured it could get boring for you guys. But, this is important
requirements, and now this is what you are going to build for the rest of the, uh, the interview and nothing else. Everything not mentioned here is Everything not mentioned here is implicitly out of scope.
step in our delivery framework is our entities. This is just figuring out what going to interact with another. They become our classes in class design. The just looking for the nouns in our requirements and considering each of
them one by one to see if they have any place in our system. So if we look at at our requirements here, entities, there are a couple of things that stand out. The first is that we're depositing package. Whoa, bad typing. We're deposit
we're depositing packages. So we can put package down first. Then we also have these compartments that need to open. So we'll put compartment down. These are locker, the Amazon locker. We don't want to forget that one. And then we talk
about these access tokens. the access tokens expire uh expiring being returned to the user all of these things. So we have this concept of an an access token. Uh maybe honorable mention of course we have the carrier or the driver and then
we also have the user who's going to pick it up. I'll start with those two straightforward. Um these are external to our system. We don't need to model the driver or the user. Of course some user does have an Amazon account but
send them an email with the code. They're going to come with that code. our system do we need to model or maintain the state or behaviors of a user. So, I'm going to cross that one out. Delete it. Exact same thing is true
of the driver. So, I'm going to remove them as well. Now, working our way back This one's a little bit more interesting storing packages. So, we need a pocket package class, right? Most candidates
add a package here. But what you'll find especially as you get later on in the design is that packages also are external to our system. Some other shipping information, the customer details, what's in the package, all of
thing when it pertains to the package. It cares about its size because we need that to know what size of compartment we should assign it to. But that's it. So class. It doesn't need to be its own entity. it's just going to be an input
parameter to whatever our pickup or whatever our deposit excuse me function is. Okay, so that'll become more clear as we get later on in the design, but that that's or at least I know maybe preemptively that that's not going to be
important. Uh compartment on the other hand, this is truly central to our holds the package. Each one has a size, an ID, an ability to open. They track occupied. So compartment will be important. This will be a class in our
system. Locker two is an obvious one. It orchestrates the whole thing. So when the driver comes, they say, "I have a medium package." Something needs to scan through all of the compartments, find which one is the best fit. Uh something
needs to handle generating the codes, tying it all together, handling the the orchestration. That's going to be the locker. This is our entry point. interact with, our external users interact with. And then you have this
interesting one to think about. You could say, well, isn't this just a string? Like, it's a string. Sure. It certainly needs to be stored somewhere, right? This is state in our system. That string is important. Upon uh deposit, we
generate one and we need to save it so we can look it up on pickup. But it's actually more than just a string. It's a it's a bearer token, meaning that it has an expiration time even. So, it represents the right to a specific Oops.
It represents the right to a specific compartment. And that's a concept that's entity. So I'm going to keep it here as an entity. even driver and carrier, I want to I want to call out that you might be
thinking to yourself, how would I know that already? And the answer is you don't have to. Don't stress it. Put down all the nouns here first. It's all good. further into your design with your class design and your implementation, you're
And you can always come here and just update the entities. that's a totally natural, acceptable, you know, even promoted and great thing to do in the but this is a good time for you to just get the lay of the land so that it gives
get the lay of the land so that it gives you a foundation as we move into class. entities, we need to define their interface. This is the class design. What state does each one hold and what methods does it expose? I really like to
that you do the same thing. So I want to start with the orchestrator in our case this is the locker and then move down to the entities that it depends on. This this allows us to define the highle operations first which is going to
naturally reveal what the lower level classes need to provide. So we can start classes need to provide. So we can start by uh sketching out the class design for by uh sketching out the class design for our locker. Um the way that I recommend
systematically. And so you're going to look at your requirements first trying to extract the state that your locker needs to remember and then handle the behaviors. So when we start with state, we can look up here and we know that a
carrier or driver deposits a package of a specific size. The system assigns an available compartment of matching size. So the system here is the locker. The locker needs to be able to know which compartments are available uh which
compartments exist in the system in general all of this. And so the first thing that we know then it needs to remember is compartments. Compartments. And this could just be a list of compartment objects. These are
all of the compartments that are a part of this locker system. All 50 or 100 of them. Okay, straightforward enough. Coming back to our requirements, we can keep scanning here. And we might see that the user receives the package by
entering an access token. The system validates the code and opens this, etc. And so another thing that our locker here needs to track is all of the available access tokens. What are all of the access tokens that the locker has
the access tokens that the locker has handled out? And so we have access handled out? And so we have access tokens. And this could just be access tokens, a list of access tokens. Here are all the compartments our system
has. Here are all the access tokens we've handed out. Um, if we want to check on pickup, we would then need to iterate over all of the access tokens. find the one that matches the string that the user input and then return that
to them. For what it's worth, this is totally fine as it is right now with 50 or 100. So what if it's oven it's going to go wicked quick and this doesn't matter. What you could do and what I'll end up doing here um just because I like
the way that it's clear about the intent is that you could turn this into a map. And so I can have a map of string which is the code the access code to the actual access token. And now when a user comes for pickup and they give us that
the map. Now importantly I'm not really doing this because of the O1 nature. As I said of N over 50 or 100, it's effectively the same. I'm actually doing super clear that what this does is it maps directly from that string to the
token object. Um so that we can then find what their compartment is. This is interview. Talk to your interviewer about because of leak code. I find that so many candidates are so hyper optimized on these O of one efficiencies
scale or the clarity of their code and so in this case this is where adding think clearer but there are lots of times when we might see examples of this where that's not the case so just keep that in mind if you're ever doing an O1
optimization think first about readability especially if that n is small where small here is like under hundreds of thousands okay um so that's defined our state. Now, we want to do that exact same thing with behavior. And
requirements, we have that the carrier deposits a package by specifying a size. So, the main thing here that we have is some deposit function. Deposit package function. This is going to take in the
size so that we know which size compartment to return to them. And then it's going to return a string which is just that access token that we'll figure figure out how to get to the user. Right? So it's the first big public
function deposit package. What happens next? Well, the user retrieves the package by entering the access token. And so we need some pickup function here. So we need some pickup function which takes in a string which is that
token code, right? And it's going to return either void if it was successful because it just opened that compartment or an error if it was not successful. we need if we scan through our requirements is that staff can open all
expired compartments to manually handle those packages. Again, this is the case packages that didn't get picked up. They want all those doors to open so they can put them in the truck and take them back to the warehouse. So, we can name this
open expired compartments, going to return void because all that it does is just open up those expired compartments, the doors all open so that they can be handled, right? Um, okay,
that's our class design for the locker. Now, we can move on to our access token. So, for the access token, what is the class design for access token? Doing the state, we can come up to our requirements and we know that upon
successful deposit, an access token is generated. Okay, not telling us too much so far. User retrieves the package by entering that access token code. Okay, great. We know that it expires after 7 days and we know that it's of course
mapped to the compartment. And so all of that leads us to first that code. This is the string. This is the access token code that the user gets sent and types in. There's of course some expiration timestamp here when the code expires and
then there's the compartment that this access token accesses. So we have the access token accesses. So we have the compartment there.
straightforward here we have the we want to check if it's expired. it's expired. This is what locker is going to use on pickup in order to first Should I even allow this user to pick this up? Next, we have the get
what locker will need to call in order to get the compartment. A simple getter to get the compartment. A simple getter here. Capital compartment. And then we should expose this get code to because we need to get that string
code to send it to the user when depositing the package. And so that is going to be our full class design for access token. The last one is the easiest of the group. Maybe it's it's the compartment.
It's pretty straightforward. We're going to have compartment. Let me put an extra new line there. And what all does the compartment need to do? Well, the main compartment has a size small, medium, and large. Uh, and then it's going to
need to know whether or not it's actually available. So, whether it's actually available. So, whether it's occupied. So, we'll have the size, which is going to be a size enum of either small
of either small of either small, medium, or large based on the requirements. And then we're going to know is it occupied? And that's going to be a boolean true or false. When we move on to the actual behaviors,
about what happens when we deposit a package, looking at up our requirements, when we deposit a package, we need to be able to check is occupied. Is occupied.
basically just the getter there. But then we also need to be able to mark it occupied and that's just going to return void. If we need to mark it occupied, then on pickup or on staff clearing it, we also
need to be able to mark it free. So mark it free and that's void. Importantly, we compartment opens, right? We open it. We open it here for the staff as well. So there's some function here which must trigger the mechanics of the actual
compartment to open which is just some open function which returns void. Of because this will be some mechanical component as I mentioned. And then some more getters. We probably need to be able to get that size. So get size
we're trying to deposit the actual package. Um so get size will return the Okay, that looks pretty good to me. Important thing to note here is the
compartment is managing its own physical state through this mark mark occupied and this mark freed and it pri it it provides this way to open itself with this open function. This is nice encapsulation. It knows whether or not
it's occupied. Um there is an argument that this could be maintained by the locker. The locker could have some occupied map here. Again, that would make things O of one as opposed to iterating over the compartments. But
given that this is a matter of the physical state of the compartment as opposed to a relationship with regards to the compartment, it makes the most sense to model it here on the compartment class directly.
time for us to move on to the actual implementation. And so the way that this you're going to implement the most interesting functions in pseudo code. most interesting functions or methods, you can propose this, especially in more
senior level interviews. Oftent times it's the candidate proposing it. Uh in typically it's the interviewer who's saying, "Hey, these are the the subset but typically they're the most
they are for this interview in just a moment. Uh as I mentioned, we're going what the majority of low-level design interviews do. But roughly 30 35% of to implement in the language of your choice. And that's why in the written
article linked in the description, we have the implementation uh in each of the major languages. So check that out. But when we come back here, we can come But when we come back here, we can come down to implementation.
And what you want to do when you get to implementation is think about this right? You can serialize this to make it it pretty straightforward. And the way of the core methods that we need to implement, you're going to do two
things. You're going to first just define the core logic. I'll show you to do is you're going to consider the edge cases. And you'll rinse and repeat for each of the core methods. And it'll be it'll end
up being super straightforward to build this from the ground up. And so the most interesting methods for us in this case actually all live in the locker. The access token is just some getters. Is expired is straightforward. We compare
the expiration time to now. These are all just getters and setters. The open mechanical, so it's not something that we would implement. So those are the We're actually just going to implement the locker class, the orchestrator in
class locker to start the implementation. And we're going to start with the posit package size. And to do this, let's take the approach
that I just mentioned starting with defining the core logic. And so if we want the core logic, what are the steps to depositing a package? Well, the very this function needs to be able to find an available compartment. So find the
compartment of the right size. That'll be step one. Once it found the compartment, it needs to open the compartment so the driver can go place it in. The third thing that it'll do is it'll need to mark this compartment.
Compartment is occupied so that we don't end up opening this again in the future. The fourth thing that we'll need to do is think about how does the user know that this is their compartment. And so that'll start with
generating an access token for them. Once we have that generated access token, we'll need to store it. Store the access token. That's what we have that access token map for, right? Access token mapping. So store that
Access token mapping. So store that access token and then return the access code or the access token code so that it can be sent uh to the user by SMS or email or otherwise. Right? So that's our our core logic. Um,
think about what our corner cases are or we can think about our corner cases right out of the gate. I don't know that there is much of a an ordering that them right out of the gate because why not consider edge cases or let me just
write edge cases. What are the edge cases that can go wrong here? Uh, the compartments available of the requested size? So, if we come here and there's no size? So, if we come here and there's no none available, then that's an issue. So
none no compartment of right size. And how are we going to were going to throw an error there. So if we do, then we're going to throw error. So open compartment. Sure, there could be a mechanical issue there. I
but I'm going to assume that's out of scope. That's not our problem. Mark this Generating the access token. We shouldn't have issues doing that. have issues unless for some reason we ran out of memory. Um, but why would we?
of compartments. So that access token map shouldn't get too large. And then one edge case that I'm I'm concerned about. So we can get in here to actually implementing it now in pseudo code.
compartment of the right size. Okay, so we have the compartment equals get we have the compartment equals get available compartment of some size. So I'm going to abstract that away for now to a helper function. We'll implement it
maybe in just a moment. And then I'm going to do compartment.open. I'm going to call that open function on the component or on the compartment, excuse me. So that's step two. Step three is mark the component uh the
compartment. Why do I keep doing that? As occupied. So compartment dot we have this mark occupied. So I'll mark it as occupied. The next one was to generate the access token. So I'm going to have access token
equals generate access token for a given compartment. So straightforward. It's going to generate the access token using you know maybe
some cryp cryptographically secure uh you know random hash and then we'll create an access token and return that access token object. So this is really just using the constructor with that
code and the expiration is seven days from here and we'll implement that in a second. Uh and then I need to update my mapping. So I have that access token mapping and I'm going to have the access token.get code that string. This is just
to give us that nice of one lookup that we talked about earlier. And then I'm going to set that access token. At the end of all of that, I'll return access code. I know some of you were thinking you wrote that twice. Probably not the
you wrote that twice. Probably not the best. So I'll do that. How's that? Better. Now we don't repeat any code. So return code. Um now in terms of that edge case that would be here. So get available compartment. Uh let's say that
this returns null in case that there is no compartment and then I'll let the caller handle it. In this case, we're the caller. So get compartment equals equals null. Then we are going to throw an error. We'll throw an error. In this
case, maybe just no available compartment of that size, right? Something like that. So there's the the basic implementation. You can see one thing that I did here is
that I used helper methods um private helpers that made this more readable, and then I could turn to my interviewer and say, "Hey, do you want me to if you'd like. In our case, let's go ahead and do the get available
compartment because it's interesting enough and pretty straightforward. So get available compartment, it's going to be private.
And what should that look like? That is going to take in the size of course and going to take in the size of course and this is just going to
compartments and then for each see if right size and and then for each see if right size and free
first that matches return it. So that's our core logic here but let's evaluate after we write it. And so what do we have? We have for
C in compartments for C we're going to iterate over every for C we're going to iterate over every every compartment. If C do get size equals equals the size which was our input parameter from right here and
input parameter from right here and not C dot is occupied. So we're calling the compartments is occupied there. Then we're going to return C return the compartment right that first one. And then if nothing return null. So pretty
straightforward there. Um, error cases. What can go wrong here? Get size that shouldn't fail. The thing that could go wrong here would be that we don't find return null. So maybe I'll put that here just for completeness. Edge cases
none available. Return null. Then the other helper function was generate access token. I'm not going to implement that one because it's it's so straightforward. Generate the access token in the way that doesn't
matter. Some random something. um and then simply call the constructor and public function which is going to be pickup. So we'll take the exact same approach. Come back in here. Pick up. Pickup takes in a string where that
string is that access token. So maybe I'll do this just to be super clear. The access code string or maybe just code string so that you know what I'm calling. Uh let's start again with the core logic
our core logic, what's the first thing that we do again uh on pickup? Pause the video here, think about it, and then you thing that we're going to do is we're going to look up that code on the um in
that access token mapping. So look up the code to get access token. Okay, what's the next thing that we should do? Well, we need to check I
guess that's maybe an edge case, so I'll hold that off. Um but we need to get the compartment associated with that access token so that we can open the token so that we can open the compartment. Open the compartment.
compartment then we assume that the user grabs their package and we need to mark grabs their package and we need to mark the compartment as free and then remove the compartment as free and then remove access code from map. Now you'll see
here that we're taking some liberties here. We're assuming that the compartment when it opens auto closes like after say 30 seconds. This is it's worth. They auto close. In reality, there's probably some sensors here to
know that the user actually uh took the package out. Maybe even some cameras, get that sophisticated. We're just going to assume that we need to open the take the package. The compartment will will auto close and we can keep moving
from there. So, that's the simplification that we're going to make with your interviewer about that simplification. In the case of this going to say yes, they don't need you to implement all of those checks, but maybe
it's something that we discuss when we get to the extensibility portion at the end. So, that's our core logic. Then, when we move on to our edge cases, what could happen with the corner cases here? Well, we called out one already, uh, or
I almost said it because it came to mind, and that would be that the access token is expired. That's a big one there, right? I guess the first one will there, right? I guess the first one will be some validation of the code itself
like not empty maybe not necessary but we'll do it for completeness and then if the access token is expired throw if it's empty throw and then what else it's empty throw and then what else could potentially go wrong here um I
guess maybe even before that I'm just going through these right you get the compartment look up the code what if the code is not in mapping basically it's not empty but it's a code that we don't have. We'll throw we don't have that
code. Open the compartment. Mark the compartment as free. Remove the access already in there. So that should be fine. So those are all of our cases. Um fine. So those are all of our cases. Um let's go ahead then and implement this.
like? Starting with the happy path. So the happy path would be that we first get the access token. So access token mapping and we pass in the code which was our input parameter. So look up the code and get the access token. Okay,
from there we get the compartment and we get that with access token get compartment. Now we need to open the compartment. Okay, easy enough. Mark the compartment is free because we assume that the user
the user grabbed their package. And then for that access token mapping, we now for that access token mapping, we now need to remove the current code. And we know that the code is valid because of it already worked here. And so then edge
cases coming in. I guess that first thing that we want to check is that if thing that we want to check is that if code is empty for some reason they passed in an empty string here. Uh then we want to throw
we want to throw error of invalid code. What if the code is not in the mapping? Well, this would be language dependent. So oftentimes you'll you'll get a key error here. For example, in Python, some exception will
because we're in pseudo code. And I'm just going to make the assumption that this maybe would return null. And so I'll say if this returned a null, meaning that it wasn't valid or it wasn't in there, then throw error.
wasn't in there, then throw error. Again, invalid code. And I'd talk to my language dependent. Depending on the language, it might throw an error. I'm going to assume for the case of our pseudo code that it just returns null.
here, let me add some lines to make it more readable would be if access token dot is expired. So if it's expired then we'll throw
error access code expired. Okay. So there's our full implementation of pickup. Last up, we're going to take on the final public method exposed by
locker, open expired compartments. As a reminder, this is the function that's going to be called by staff that comes daily, weekly, whatever it may be, in packages that didn't get picked up by users and are past their expiration. And
one as we did for each of the others, which is to define the core logic and the corner cases. The core logic in this case is that the first thing that thing the function is going to do is scan through all accessed tokens in the
mapping. Find the expired ones. So get all the expired tokens uh for each of those. Get the compartment
of each and then open those compartments. And then this is where they are going to you know this is where they are going to you know this is where they are going to remove the packages external to us. And
remove the packages external to us. And then for us we are going to mark the compartment as available again basically not occupied. And then here's an interesting question is do we remove it from do we remove that access code from
the map? This is a place where I would ask my interviewer. like, well, there's it from the map. What would happen then if a user came after 10 days with that same access code? Well, they would get a they would get a invalid code as opposed
to an access code expired. So, maybe we want to actually leave these here for a two. Um, there's the memory consideration. When will this map grow so large that this actually matters? Um, you could do some math and say probably
compartments or so, even if these packages are exchanging every single day. U, you know, it would take a 100 days before you were at 5,000 things in this map. Um, so I'd have this conversation with my interviewer. I'm
going to say let's not actually remove them. So decision no because I'd rather users get the access code expired than the invalid code one. So let's come in and implement it now. open expired compartments. We'll say for the token or
compartments. We'll say for the token or for the code and the access token in our access token mapping. So here we're just iterating over the keys and values of done in all of the major languages of course. I'll say if the access
course. I'll say if the access token dot is expired just to confirm that's what we called it. access token is expired. So if it's expired then we are going to get the compartment compartment equals access
I'm going to open the compartment compartment.open. I'm going to assume the employee removed them right and that this just
closes after 30 seconds and doors auto close. That's the assumption that we agreed upon a moment earlier. And then I'm going to do compartment mark free.
Okay. And then we are going to not remove from access token mapping so they still get correct error. And you you'd say to your interviewer, well at some point we should obviously clear these out. So
maybe we have some additional loop here. So loop to clear out the access tokens So loop to clear out the access tokens from the map that are I don't know three months plus old something like that you'd agree on with your interviewer but
that's the interesting bit um I realized that we didn't talk about corner cases implement the core logic and then talk about corner cases or do them all up about corner cases or do them all up front. Um but in this case thinking
through them are there any if the map is empty or nothing is expired that's fine we just won't loop through anything here right we'll still routine return return void if everything is expired uh then we would open all the compartments also
fine this method is also an important meaning that if it's called multiple times we're just going to open the same compartments that's no big deal either um so yeah I'm gonna I'm gonna say kind
of none that aren't are that aren't explicitly or implicitly handled. interview, I suggest you do this. I think it helps you, but like this isn't
checking your implementation. Uh I think this will this will work for you, but down word for word uh or write down exactly as I'm doing, though I suggest that it's a pretty good approach to take. Okay, so that should finish up our
like that was pretty straightforward. The approach of writing core logic and edge cases made it super linear and easy to come up with whatever our effect the entire locker class. No reason to implement access tuck in our
mentioned. They're simple getters and setters. the framework, and this is where your interviewer might ask you some follow-up
questions to test how extensible your design is. Note that if you're an there's a chance that your interview is over at this point. There's no time left and life is good. Don't don't stress it. If you're senior or up, then you can
questions here as it pertains to extensibility. So, let's go through what to Amazon Locker. These are the questions that I've heard uh candidates report being asked to them um within interviews. And so the first one that
allow a smaller package to use a larger compartment as a fallback when all the exact same size compartments are full. So you have a small package, all the just put that in a medium or a large compartment? Second, how would you
under maintenance? And then third, how would you ensure packages are actually deposited before you generate those access tokens? So we can take each of those one by one. Let's start with this first one.
Uh, so assuming your interviewer just asked you this, what would you say? It just going to need to change that get available compartments function that we had. So get available compartments such that you have one additional outer
loop. And that outer loop is going to just make sure that you iterate sequentially over the sizes starting from the size that matches first. And so what might this end up looking like? Well, you'd have maybe let's call this
Well, you'd have maybe let's call this now the requested size. And so you'd now the requested size. And so you'd have the sizes in order using those size have the sizes in order using those size enums. And that would be small, medium,
and large. And then you'd get the index of the one that they're asking. So you know where to start in that actual array. And so sizes in order dot index array. And so sizes in order dot index of uh requested size. Okay. And so now I
large, I'm going to start here and there's nowhere else I can go. If I'm at know that I have two I can do. If I'm small, here on. And then we just add that extra bit over the loop. So for I from start index to sizes
in order.length and just some pseudo code here. me basically saying I'm going to iterate over starting from that start index that we found that's all that I'm saying here
and then the size that we care about now is going to be the sizes in order of I right so if in its example again if we're starting with small then this the size of small then we're going to move to medium check the size of medium
hits is going to be the one that ends up being returned. And so in your actual extension, often times you don't end up actually implementing it, um you would just tell them basically describe what I just did, saying you'd add another loop
compartments loop that already exists in order to iterate over the different sizes starting from the size uh that matches the requested size and then implement it so you guys can see exactly what I mean. Next, how would you handle
compartments that are broken or under maintenance? So, we can tackle that one. And this is really testing basically whether or not your compartment was designed adhering to information expert. The compartment owns and knows
everything about itself. It knows whether it's occupied. It knows now in status. And that should make this easy to extend. And so the way that you would describe this to your interviewer is that currently we have basically boolean
state is occupied or not is occupied. But now we've added a third bit of state here. Basically an outofservice state. And whenever that's the case, whenever you're transitioning from a boolean state to a multi-dimensional state
larger than two, then you typically want to introduce an enum. And so what this would end up introducing probably an enum like compartment status. And then your compartment class design would update to something like this. Your
status of either available, occupied or out of service. Maybe you have more specific ones here like broken for some reason or you know I don't know some But for our case we'll say out of service. And then now instead of
checking is occupied here, you're going to check is available where is available is simply checking whether or not the status is available and not occupied or as occupied, you set the compartment status to occupied. When you mark as
available, you set it to available. Mark is out of service, out of service. You get the picture, right? So we've replaced that boolean is occupied with replaced that boolean is occupied with simply enum with with three possible.
Last up and maybe most interestingly, we have how would you ensure packages are actually deposited before generating the access token. And so the issue that we have right now is that we assume that the driver put the package in. If we
come back up here to our deposit package, we open the door, we mark it as occupied, we generate the access token, and we go on our way. But we don't package. Like the worst case scenario here would be that the driver got
Something happened and now we've marked a compartment as occupied that is not occupied and we have an access token mapping to a package that's not actually in a compartment. Right? And so how would you handle this both in real life
and in the interview is that you would need to introduce what's called a two-phed commit pattern. And so let me write that down. Two-phased commit. instead of having deposit package like we have now which does everything all at
once, we'd split it into two. You would have a reserve compartment, reserve have a reserve compartment, reserve compartment and a maybe confirm deposit. interesting because there's multiple ways you could do this. Of course, in
the real system, this confirm deposit is probably going to be based on sensors. Like maybe did the weight of the actual um you know content of the compartment change? Maybe that's what triggers this confirm deposit. Um, in our case, we'll
make it simple and we'll say that the driver just has to click that. And so the driver first reserves the compartment. This would open the door and maybe generate an access token and store it not yet in our access token
mapping, but maybe somewhere else. Uh, I'll show you that in a moment. And then package, then they need to come back and confirm to us that it was actually deposited. At which point we mark the compartment as occupied. Maybe even we
swing the door closed and we do all the rest. And so let me show you what that to copy and paste so you guys don't have to see me writing the code. But the updates are that to locker we're going to have instead of just that deposit
function like we had before, we have reserve compartment and that confirm deposit and then maybe the ability to cancel a reservation in case something went wrong here. You could even have this be based on a timeout. And then for
the compartment itself, we knew that we had already added that compartment status available, occupied, and out of service. Maybe we add an additional one here of reserved. Missed one there. So we had an additional one of reserved
now. And the way that this flow now changes, again, I'm going to paste this is that first you call reserve compartment with the size. This is going going to mark it as reserved. Now, basically updating its status to just
reserved. It's going to open it. and we generate a reservation ID and then keep that in some reservation mapping. This is important because that's what the uh driver is then going to call confirm deposit with is with that reservation
ID. How this happens a little hand wavy for an interview, right? Maybe you show the screen and that's what they need to end up typing in. Again, if you did this based on weights or sensors, then it probably would have an automatic mapping
from that compartment to the reservation ID. Um, but we're going to be kind of we're on this boundary of of physical and software. But in any case, they have that reservation ID in hand. Then maybe they physically come back in after
placing the package, come back to the screen, type in that reservation ID, and what we do then is we get the compartment associated with it. We now mark it as occupied. We only now actually generate that access token, add
it to our mapping, and then of course whatever external code now sends it to the user saying that they're ready. And then we've removed the reservation bit here. So the key bit, again, you probably wouldn't implement this in an
you would explain to your interviewer that you need some form of a two-phase commit. This two-phase commit of actually opening the compartment, and then two, validating that something was placed in the compartment. And only upon
validation do we kick off these downstream flows such as marking the compartment as occupied, generating the access code, and subsequently sending it access code, and subsequently sending it to the user.
for the Amazon locker. So we went from a vague prompt to a concrete set of entities. We designed their interfaces with clean separation of concerns. Uh workflows and handled the common extensibility patterns. Uh this design
we had the information expert that was the class that owns the data enforces compartment. We had separation of concerns. Uh we had the locker as the handled the access controls and the compartment tracking physical state. Uh
we kept things simple. We had linear scans, right? We didn't overoptimize in any places because we know that the N here in Amazon locker is quite small, 50 to 100 or so compartments. So if you found this helpful, go ahead, as I've
written breakdown. It's going to be linked in the description. Tons of other low-level design content, primers on the website, including a full breakdown on concurrency, which just launched. So please go check that out. Uh, as always,
thank you for watching and best of luck with your interviews.
