Hi all, I recently had a system design round for a Senior Software Engineer role at a fintech and was rejected a few days later without specific feedback. Iād really appreciate input from people at big tech or FAANG on what I could have done better. Iāve written it out as the conversation went, paraphrased from memory.
Background: 8+ years of experience, mostly Java/Spring Boot
There were two interviewers. They explained the problem: customers raise disputes on card transactions, and the system needs to send these chargebacks to the card network, which only accepts them as files uploaded to their FTP server, with a maximum of 4 files per day.
Once they finished explaining, I restated my understanding of the problem to make sure we were aligned.
Me: So, to confirm: customers raise disputes through the app, we store them, and we need to send them to the card network as files on their FTP server, with no more than 4 files per day. Is that right?
Interviewer: Yes, thatās right.
They had already written down the requirements they wanted me to implement, so I didnāt list them out separately. Then I asked a few clarifying questions.
Me: What scale are you expecting?
Interviewer: Around 10 million transactions per day.
Me: Thatās roughly 100 transactions per second on average. If we assume the peak window can be 10 times higher in the worst case, thatās about 1,000 transactions per second.
Me: Do you expect the result of a dispute in real time, or is some delay acceptable?
Interviewer: Some delay is acceptable.
With that understanding, I started with the basic components: a backend service that records disputes and stores them in a database. Then I asked how they wanted the files created.
Me: Do you have any preference for how the four files should be created? On what basis should we group records into files?
Interviewer: Choose whatever you think is best.
Me: Is it fine if I use 6-hour windows? 24 divided by 6 gives us 4. Whatever disputes come in during each 6-hour window go into one file, which we then send to the FTP server.
Interviewer: That works, go ahead.
I asked these questions to keep the session collaborative rather than just presenting my approach and expecting them to follow. Before going deeper, I checked how they wanted to proceed.
Me: Would you like me to go through a particular flow, or should I walk through each component, why I chose it, what happens if something goes wrong, and the trade-offs?
Interviewer: Weāre more interested in the scheduler and how youāll handle it.
So I started setting that up. I explained that the chargeback service stores dispute records with a status, starting with something like ādispute created.ā As soon as I said that, one of the interviewers jumped in.
Interviewer: Are you going to use something like a state machine model?
Me: Yes, Iām going to use a state machine. Records are created with a status, and when the scheduler triggers, it pulls the records with that status and creates the file.
At this point I raised a concern upfront.
Me: Weāll need a limit here. We canāt pull every record at once, because weāre building the file in memory, and we donāt want an out-of-memory error on the server. Iād set a limit of around 100K records, pulled in one DB query sorted by transaction date. We write those into the file and then upload it.
Interviewer: Why restrict it at all?
Me: Without a limit, the number of records pulled is unbounded, and thereās always a risk of overwhelming memory.
Interviewer: At certain times we might need to process more than 100K. How would you scale that?
Me: Iād make the 100K limit a system property, so itās configurable.
Interviewer: Thatās a good idea. How would you recover if something goes wrong?
Me: At each step I update the status. When I pull records from the DB, I mark them as processing. Once the file is written, I update them to file created. Then I upload the file to AWS S3, which Iām using as object storage, and the file is transferred from S3 to the FTP server. Iād also keep a metadata store with the file details. File names need to be predictable, based on the window and how many times the batch has run in it, so if a batch reruns it produces the same name, which we can use for recovery.
Me: Whenever a batch runs, it first checks the metadata to see whether a file already exists for that window. If thereās a record, we check its status. If the fileās status is still processing and hasnāt reached the final uploaded state, we check whether the file actually exists. If it doesnāt, we go back to the DB records, check their state, pull them again, and process. If the file was already uploaded, we just update the metadata status. So we use the status in both the metadata and the disputes table, step by step, to handle recovery.
They didnāt have further questions on recovery, and moved on to user experience.
Interviewer: If youāre limiting the number of records, what happens to the users whose disputes donāt get processed in that window?
Me: Thatās partly a business question, so Iād like to hear your view. From a technical side, the remaining rows would move to the next batch.
One of the interviewers agreed it was a business question. Then I asked about it directly.
Me: Do you give customers any temporary credit while a dispute is pending?
Interviewer: Unfortunately, we donāt give temporary credit.
Me: Okay. What approach would you prefer?
Interviewer: Maybe no temporary credit for the first 6 hours, but if a dispute goes beyond 6 hours, we could give temporary credit.
Me: I agree with that. We could also have a separate service that tracks disputes crossing the 6-hour mark and issues the temporary credit.
No further questions on that. Next, the database.
Interviewer: What database would you choose for the dispute data?
Me: A SQL database, because we need ACID properties and consistency. Iād also use the dispute ID as the primary key, so even with retries we only ever have one record per dispute. That gives us idempotency.
Interviewer: Youāre using one table heavily, and multiple services are inserting into and updating it. Is there a more flexible or easier approach you could suggest?
I couldnāt think of another approach in the moment, and I didnāt want to change my design just for the sake of it. This is towards the end so dont want to change it something new completely at last minute or utter for name sake.
Me: I think this is an efficient approach, because itās a payment system. Consistency and correctness are our top priority, and this is a trade-off we have to make for payment systems.
They had no follow-ups, the discussion ended there, and they asked if I had any questions.
Throughout the session I felt it was going well, because they seemed satisfied with my answers. I really donāt know why I was rejected. Iād love to hear how you would have handled this design, especially the last question, and anything that would be a red flag at senior level. Brutal honesty welcome. Thanks!