<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Staff Engineer Mindset on Medium]]></title>
        <description><![CDATA[Stories by Staff Engineer Mindset on Medium]]></description>
        <link>https://medium.com/@developer_programmer?source=rss-6bdd1f176ebd------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*zFThAygnbIsOpXzQwr8stA.png</url>
            <title>Stories by Staff Engineer Mindset on Medium</title>
            <link>https://medium.com/@developer_programmer?source=rss-6bdd1f176ebd------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 21:28:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@developer_programmer/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[The SQL Migration That Works in Staging Can Destroy Your Production Release]]></title>
            <link>https://medium.com/javarevisited/the-sql-migration-that-works-in-staging-can-destroy-your-production-release-943d98ed78de?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/943d98ed78de</guid>
            <category><![CDATA[sql]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Fri, 13 Nov 2026 16:49:50 GMT</pubDate>
            <atom:updated>2026-11-13T16:49:50.389Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BCyJZh4vbL_Kt5cPy9MTRw.png" /></figure><h4><em>Senior engineers aren’t paid to write more complicated SQL. They’re trusted to understand what happens when a perfectly valid change meets a database that never stops receiving traffic.</em></h4><p>A database migration can pass every automated test, work perfectly in staging, and still bring a production release to a standstill. The SQL might be correct. The application might compile without warnings. Even the deployment pipeline can report success while requests begin accumulating behind a database lock.</p><p>This is one of my favorite examples of how engineering experience changes the way you look at ordinary code. Early in your career, you want to know whether a migration works. Later, you become interested in what happens while it works, how long it takes, and whether the previous application version can survive the change.</p><p>Those questions sound less exciting than designing another distributed system. They’re also the questions that keep customers from discovering your database migration before your monitoring system does.</p><h3>A Harmless Column Rename</h3><p>Imagine you’re working on an order-processing platform built with Spring Boot and PostgreSQL. The orders table contains 80 million rows, and several application instances continuously read and update order records. A developer wants to rename customer_id to buyer_id. The change makes sense because the business has introduced a distinction between buyers and account owners.</p><p>The migration looks innocent:</p><pre>ALTER TABLE orders<br>RENAME COLUMN customer_id TO buyer_id;</pre><p>The statement is usually quick because PostgreSQL doesn’t need to rewrite every row just to rename a column. That makes the change attractive, especially when a team wants to keep its migration scripts small. But a quick metadata change can still require a strong lock. If another transaction is holding a conflicting lock, the migration may wait. Requests arriving behind that waiting migration can then become blocked as well.</p><p>Now consider the deployment itself. During a rolling release, some application instances still execute queries referencing customer_id, while newer instances expect buyer_id.</p><p>One schema change has created an application compatibility problem. The SQL was valid. The release plan was incomplete.</p><h3>The Real Problem Is That Production Runs Multiple Versions of Reality</h3><p>Developers often imagine deployments as a clean transition. Version 1 disappears, version 2 appears, and the database moves to the new schema at the same moment.</p><p>Real deployments are messier.</p><p>Kubernetes may run old and new pods simultaneously. Background workers can continue processing jobs created before the release. A delayed message may be consumed by application code that still expects the previous data model. Rollback makes the situation even more interesting.</p><p>Suppose the new application starts writing data using buyer_id, and an unrelated defect forces you to roll back the deployment. If the old application expects customer_id, restoring the previous container image won&#39;t necessarily restore service.</p><p>A rollback that requires reversing a database migration is considerably more dangerous than rolling back application code. This is why experienced engineers separate schema evolution from application deployment whenever compatibility matters.</p><h3>Expand, Migrate, Contract</h3><p>One practical approach is the expand-and-contract pattern.</p><p>Instead of immediately renaming the existing column, you introduce a new column while preserving the old one.</p><pre>ALTER TABLE orders<br>ADD COLUMN buyer_id BIGINT;</pre><p>At this point, old application instances can continue reading customer_id. Newer code can be deployed with awareness of both fields.</p><p>The next challenge is keeping the values consistent. Depending on the workload, you might temporarily write both columns, use a carefully designed database trigger, or establish a controlled synchronization mechanism. Each option has consequences, particularly when old application instances are still updating records.</p><p>For example, application-level dual writes inside one database transaction can keep two columns consistent for that operation. But if old instances continue writing only customer_id, the new field may become stale unless the migration plan accounts for those writes. After establishing a reliable synchronization strategy, you can backfill historical records in manageable batches.</p><p>Only after verifying the new column’s completeness and switching all readers should you consider removing the old one. The extra steps can feel tedious when the original request was simply to rename a field. But the purpose is to avoid forcing every application component to change simultaneously.</p><p>That flexibility becomes extremely valuable when something goes wrong.</p><h3>Backfilling 80 Million Rows Is a Production Workload</h3><p>A backfill is easy to underestimate because the SQL is straightforward.</p><pre>UPDATE orders<br>SET buyer_id = customer_id<br>WHERE buyer_id IS NULL;</pre><p>On a table containing 80 million records, executing this as one enormous transaction can generate substantial WAL, hold row locks, create dead tuples, increase replication lag, and put pressure on vacuum processing. The exact impact depends on row size, indexing, update patterns, database capacity, and transaction duration. Still, it’s a workload worth planning rather than casually attaching to a deployment.</p><p>A safer approach often involves bounded batches, short transactions, progress checkpoints, and deliberate throttling.</p><p>You might process records in primary-key ranges and monitor database CPU, I/O, WAL generation, replication lag, and application latency between batches.</p><p>There’s another subtle issue. If the backfill and live application writes can modify the same records, you need to define which value wins and how consistency is maintained. Finishing every batch doesn’t prove the migration is correct. You also need verification that new writes remain synchronized and historical records satisfy the intended invariant.</p><h3>Adding an Index Can Be More Dangerous Than the Query You’re Fixing</h3><p>Suppose the new application frequently searches orders by buyer_id.</p><p>A developer notices that the query is slow and adds an index:</p><pre>CREATE INDEX idx_orders_buyer_id<br>ON orders (buyer_id);</pre><p>On a busy PostgreSQL table, a conventional index build can block writes for the duration of the operation.</p><p>PostgreSQL provides concurrent index creation to reduce that disruption:</p><pre>CREATE INDEX CONCURRENTLY idx_orders_buyer_id<br>ON orders (buyer_id);</pre><p>This is often a better option for a live production table, but it isn’t free. Concurrent index creation performs additional work, can wait for existing transactions, and may leave an invalid index if the operation fails.</p><p>It also cannot run inside a transaction block, which matters when your migration framework wraps every migration in a transaction by default. An experienced engineer should know how their migration tooling executes SQL before placing that statement in a release.</p><p>A correct database command can still be deployed incorrectly.</p><h3>The Interview Question I’d Ask a Senior Candidate</h3><p>If I were evaluating a Senior backend engineer, I’d give them this scenario:</p><p>Your team needs to change the structure of a table containing 80 million rows. The application must remain available, multiple service versions may run during deployment, and a rollback must remain possible. I’d be interested in how the candidate approaches the problem before writing SQL.</p><p>Do they ask about the PostgreSQL version and current traffic? Do they investigate long-running transactions and replication lag? Can they explain which changes are backward compatible and how they’ll verify data consistency?</p><p>I’d also want to hear about deployment sequencing.</p><p>The candidate should understand why dropping the old column belongs near the end of the migration, after old application versions and background consumers no longer depend on it. For a Staff-level discussion, I’d introduce additional complications. Several teams own consumers of the same data, one integration cannot be upgraded for six weeks, and the database team is concerned about storage growth during the transition.</p><p>Now the challenge involves coordination and technical judgment across organizational boundaries.</p><p>There’s no single SQL statement that resolves those constraints.</p><h3>What I’d Check Before Approving the Release</h3><p>Before approving a production migration, I’d want a clear answer to a few operational questions.</p><p>First, which locks can the migration acquire, and what happens if it waits behind an existing transaction? A short lock_timeout may be appropriate for certain DDL operations because failing quickly can be safer than allowing a migration to queue behind a busy production workload. Second, how will we measure progress and detect damage? Database metrics should be considered alongside application latency, error rates, replication health, and connection pool behavior.</p><p>Finally, what does rollback actually mean? If the old application can run against the expanded schema, rollback may be relatively straightforward. If the migration has already removed data or changed its meaning, restoring the previous application version might accomplish very little.</p><p>These questions deserve answers before the deployment begins. Nobody enjoys discussing rollback plans during a successful release. People become considerably more interested when the release stops being successful.</p><h3>You Probably Know More Than Your Interviews Are Revealing</h3><p>Database migrations are also a useful reminder for engineers preparing for Senior and Staff interviews. You may already have experience with lock contention, production incidents, difficult rollouts, and data consistency problems. Yet if you describe that work as “I updated the schema and deployed the service,” an interviewer will never understand the engineering judgment involved.</p><p>Try reconstructing one difficult change from your own career.</p><p>Explain the original constraints, the failure modes you considered, and the reasons behind the implementation. Discuss what could have gone wrong during deployment and how you would have recovered.</p><p>If you haven’t worked on a migration at this scale, you can still practice the scenario. Read the database documentation, build a smaller environment with concurrent traffic, and observe what happens when transactions and schema changes compete for locks. That kind of preparation develops useful production knowledge while giving you stronger material for technical interviews.</p><p>A Senior offer shouldn’t depend on how many architecture diagrams you can memorize. Your ability to explain the consequences of engineering decisions deserves to be visible, and practicing that explanation is worth the effort.</p><h3>Free Resources and Early Access</h3><p><strong>Subscribe to My Substack</strong></p><p>I publish deeper engineering articles about Java, Spring Boot, distributed systems, production failures, and Senior/Staff system design interviews. You can follow and subscribe for free here:</p><p><a href="https://substack.com/@devrimozcay1">Devrim Ozcay | ProdRescue | Substack</a></p><p><strong>Download My Free Senior Engineer Interview Playbook</strong></p><p>I’ve created five practical guides covering a 45-minute system design framework, production incident response, architecture decisions, and engineering career preparation. The 27-page collection is completely free.</p><p><a href="https://devrimozcay.gumroad.com/l/fdiown">Senior Engineer Interview Prep: Free 45-Minute System Design Framework + 5 Practical Guides</a></p><p><strong>Help Shape the ProdRescue AI Interview Platform</strong></p><p>I’m researching why experienced engineers struggle with system design interviews, technical evaluations, and Senior/Staff job offers. If you’ve faced those problems, I’d appreciate your feedback. The survey also gives you the option to express interest in early beta testing.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fblue-sea-697d.quartiers047.workers.dev%3A443%2Fhttps%2Fdocs.google.com%2Fforms%2Fd%2Fe%2F1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA%2Fviewform%3Fembedded%3Dtrue&amp;display_name=Google+Docs&amp;url=https%3A%2F%2Fblue-sea-697d.quartiers047.workers.dev%3A443%2Fhttps%2Fdocs.google.com%2Fforms%2Fd%2Fe%2F1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA%2Fviewform%3Fusp%3Dheader&amp;type=text%2Fhtml&amp;scroll=auto&amp;schema=google" width="760" height="675" frameborder="0" scrolling="no"><a href="https://medium.com/media/0ff75ab6d435aa7f849ec31a69970e49/href">https://medium.com/media/0ff75ab6d435aa7f849ec31a69970e49/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=943d98ed78de" width="1" height="1" alt=""><hr><p><a href="https://medium.com/javarevisited/the-sql-migration-that-works-in-staging-can-destroy-your-production-release-943d98ed78de">The SQL Migration That Works in Staging Can Destroy Your Production Release</a> was originally published in <a href="https://medium.com/javarevisited">Javarevisited</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Failed System Design Interviews Until I Stopped Drawing Perfect Architectures]]></title>
            <link>https://medium.com/engineering-playbook/i-failed-system-design-interviews-until-i-stopped-drawing-perfect-architectures-ee57967823fb?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/ee57967823fb</guid>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Fri, 13 Nov 2026 11:31:48 GMT</pubDate>
            <atom:updated>2026-11-13T11:32:53.087Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zFThAygnbIsOpXzQwr8stA.png" /></figure><h4><em>I knew Kafka, PostgreSQL, Redis, and microservices. Then an interviewer asked what would happen if a payment succeeded but the response never reached the client. That question exposed a problem no architecture diagram had prepared me for.</em></h4><p>The first time I was asked to design a payment system in a technical interview, I thought I had done reasonably well. I clarified the requirements, estimated traffic, introduced a PostgreSQL database, and explained how asynchronous processing could reduce the amount of work performed during an HTTP request. I even discussed horizontal scaling before the interviewer asked about it, which felt like the sort of initiative senior candidates were supposed to demonstrate.</p><p>Then he interrupted me with a question that sounded almost insulting in its simplicity.</p><p>“Your service successfully charges the customer, but the client times out before receiving the response. What happens when the client retries?”</p><p>I explained that the API should be idempotent. He nodded and asked how I would implement that guarantee when two requests carrying the same idempotency key arrived simultaneously on different application instances.</p><p>I started describing a Redis lock. He asked what would happen if the instance holding the lock crashed after the payment provider completed the charge but before our database recorded the result. My carefully drawn architecture was still sitting on the whiteboard, looking considerably more confident than the engineer standing beside it.</p><p>That interview changed how I thought about system design preparation. I had spent too much time studying what successful architectures looked like and too little time understanding how those architectures behaved when operations failed halfway through.</p><p>The distinction matters because <strong>Senior and Staff System Design interviews are increasingly difficult once the conversation moves beyond choosing components</strong>. The interviewer wants to know which guarantees your system provides, where those guarantees stop, and whether you understand the operational consequences of your decisions.</p><h3>Why Senior Software Engineers Fail System Design Interviews</h3><p>A surprising number of experienced backend developers prepare for system design interviews by studying completed architectures. They learn how to design a URL shortener, a notification service, a distributed cache, or a messaging platform. After enough practice, the components become familiar, and the candidate begins recognizing patterns before the interviewer has finished describing the problem.</p><p>That familiarity is useful, but it can create false confidence.</p><p>A diagram showing an API gateway, application services, Kafka, Redis, and PostgreSQL tells an interviewer very little about how the system handles partial failures. The same components can support a reliable architecture or an operational disaster depending on transaction boundaries, retry policies, data ownership, and recovery behavior.</p><p>Consider a notification service that sends email, SMS, and push notifications. A candidate might propose publishing messages to Kafka and allowing independent consumers to process each delivery channel. The design looks scalable, and separating the consumers makes sense.</p><p>Now imagine the email provider starts returning HTTP 429 responses.</p><p>The consumer retries immediately, the provider continues rate-limiting, and the backlog grows. Increasing the number of consumers only makes the provider reject requests faster. Meanwhile, messages that have already been delivered may be processed again after consumer failures.</p><p>The interviewer has learned much more from those five minutes of discussion than from the original diagram.</p><p>They can see whether you understand backpressure, exponential backoff, dead-letter handling, idempotency, and the difference between accepting work and successfully completing it.</p><p>Those details are where senior-level engineering judgment becomes visible.</p><h3>The First 90 Seconds of a System Design Interview Matter More Than Most Candidates Realize</h3><p>I used to begin architecture discussions by drawing components almost immediately. It felt productive because I was giving the interviewer something concrete to react to, and I wanted to demonstrate that I understood the technologies involved.</p><p>The problem was that I often committed to an architecture before understanding the constraints.</p><p>Imagine being asked to design a payment processing platform. You might immediately introduce Kafka to decouple services, Redis to reduce database reads, and a microservices architecture to allow independent scaling.</p><p>Then the interviewer explains that financial operations require strict accounting invariants, duplicate charges are unacceptable, and every payment must remain auditable.</p><p>Those requirements change the discussion.</p><p>Before drawing the architecture, I now prefer to establish the business operation, its consistency requirements, expected traffic, and acceptable failure behavior. I want to know whether the system processes actual money, whether it coordinates with external payment providers, and what the user should observe when a request has an uncertain outcome.</p><p>For example, these two requirements sound similar but lead to different designs:</p><p><strong>Requirement A:</strong> The platform must accept 50,000 payment requests per second.</p><p><strong>Requirement B:</strong> The platform must accept 50,000 payment requests per second while ensuring that retries cannot create multiple logical charges for the same operation.</p><p>The first requirement primarily raises questions about throughput and scalability. The second introduces durable idempotency, concurrency control, external-provider semantics, and recovery from ambiguous outcomes.</p><p>A strong opening establishes which problem you’re actually solving.</p><p>I would rather spend the first two minutes discovering a constraint that changes the architecture than spend twenty minutes defending components I never needed.</p><h3>System Design Interview Scenario: Design a Payment System That Survives Retries</h3><p>Let’s build the payment example more carefully.</p><p>A client sends a request to create a payment. The backend validates the request, records the payment attempt, and calls an external payment provider. If the provider confirms the charge, the backend updates the payment state and returns a successful response.</p><p>Under normal conditions, the workflow is straightforward.</p><p>The difficult cases appear when a network connection fails, the application crashes, or two requests race against each other.</p><h3>Failure 1: The Client Retries the Same Payment</h3><p>Suppose the client sends the following request:</p><pre>POST /payments<br>Idempotency-Key: order-7821-payment</pre><pre>{<br>  &quot;orderId&quot;: &quot;7821&quot;,<br>  &quot;amount&quot;: 12500,<br>  &quot;currency&quot;: &quot;USD&quot;<br>}</pre><p>The amount is expressed in minor currency units, so 12500 represents $125.00.</p><p>The server processes the payment successfully, but the response is lost. The client retries with the same idempotency key, expecting the original result.</p><p>A naive implementation could charge the customer twice.</p><p>The first improvement is to persist an idempotency record associated with the operation. The record should capture the request fingerprint, processing state, and eventual result so that repeated requests can be handled consistently.</p><p>A simplified PostgreSQL schema might look like this:</p><pre>CREATE TABLE payment_requests (<br>    id BIGSERIAL PRIMARY KEY,<br>    idempotency_key VARCHAR(128) NOT NULL UNIQUE,<br>    request_hash VARCHAR(64) NOT NULL,<br>    status VARCHAR(24) NOT NULL,<br>    provider_reference VARCHAR(128),<br>    created_at TIMESTAMPTZ NOT NULL DEFAULT now()<br>);</pre><p>The unique constraint matters because two application instances can receive the same request concurrently. A database-enforced uniqueness guarantee gives us a durable coordination point that an in-memory check cannot provide.</p><p>However, that still doesn’t solve the entire problem.</p><p>We need to decide how to handle a duplicate request while the first attempt is processing. We also need to reject reuse of the same key with a different request payload, and define what happens when the original operation has an uncertain outcome.</p><p>An interviewer who asks about idempotency is often interested in those details.</p><h3>Failure 2: The Payment Provider Succeeds, but Our Service Crashes</h3><p>This is where many otherwise convincing designs begin to fall apart.</p><p>Assume our service sends a charge request to the payment provider. The provider processes the payment, but our application crashes before persisting the successful result.</p><p>After restarting, our database still shows the payment as processing.</p><p>Should we retry the provider call?</p><p>If the provider supports durable idempotency keys, we can use the same provider-level key when retrying. That can prevent the provider from creating a second charge, subject to its documented idempotency behavior and retention period.</p><p>If the provider does not offer that guarantee, blindly retrying may be unsafe.</p><p>We may need to query the provider using a stable payment reference, reconcile the external outcome, or move the operation into an uncertain state that requires further investigation.</p><p>This is an important distinction in distributed systems: <strong>a timeout does not prove that an operation failed</strong>.</p><p>It proves that the caller did not receive a definitive response within the expected time.</p><p>That difference has serious consequences when the operation transfers money.</p><p>A database transaction cannot automatically make a remote payment provider participate in the same atomic commit. We need an explicit protocol for handling the boundary between our database and the external system.</p><p>The interviewer doesn’t need you to invent a perfect distributed transaction protocol in forty-five minutes. They need to see that you recognize the failure boundary and can explain a recovery strategy consistent with the business requirements.</p><h3>Failure 3: Two Application Instances Process the Same Request</h3><p>Now assume the system runs across several Kubernetes pods.</p><p>Two identical requests arrive at nearly the same time. Both instances check whether the payment has already been processed, and both initially see no completed record.</p><p>If our implementation performs a read followed by an unprotected insert, both requests may proceed toward the external provider.</p><p>A unique constraint can prevent duplicate idempotency records, but the application must structure its workflow so that only the instance that successfully claims the operation is allowed to initiate the charge.</p><p>That may involve an atomic insert, conditional state transition, or another database-backed coordination mechanism.</p><p>Redis can be useful for some forms of coordination, but a temporary Redis lock alone is not a durable payment guarantee. Lock expiration, process crashes, and network partitions all complicate its behavior.</p><p>The correct design depends on what the database guarantees, how the provider handles retries, and which state transitions must be recoverable.</p><p>This is the kind of explanation that demonstrates experience beyond memorizing architectural patterns.</p><h3>Why Adding Kafka Doesn’t Automatically Make a System Reliable</h3><p>Kafka appears in an enormous number of system design interview answers. Candidates often introduce it because they want to demonstrate scalability, asynchronous processing, and loose coupling.</p><p>Those are legitimate reasons to use a message broker.</p><p>But a message broker also introduces new failure modes.</p><p>Imagine a payment service that updates PostgreSQL and then publishes a PaymentCompleted event. The database transaction commits successfully, but the service crashes before publishing the event.</p><p>The payment exists, yet downstream systems never receive the notification.</p><p>Reverse the order and publish the event first. Now the event may be consumed even though the database transaction later rolls back.</p><p>A common solution is the transactional outbox pattern.</p><p>The application writes the business state change and an outbox record within the same local database transaction. A separate publisher reads committed outbox records and sends the events to the broker.</p><p>That addresses the atomicity gap between the local business update and recording the intent to publish.</p><p>It doesn’t eliminate duplicate event delivery.</p><p>If the publisher sends an event successfully but crashes before marking the outbox record as published, the event may be sent again after recovery.</p><p>Consumers therefore need appropriate idempotency or deduplication strategies.</p><p>A simplified architecture looks like this:</p><pre>Client<br>  |<br>  v<br>Payment API<br>  |<br>  v<br>PostgreSQL Transaction<br>  |-- Payment State<br>  |-- Outbox Event<br>  |<br>  v<br>Outbox Publisher<br>  |<br>  v<br>Message Broker<br>  |<br>  v<br>Idempotent Consumers<br>  |-- Notifications<br>  |-- Reporting<br>  |-- Reconciliation</pre><p>The important part of this diagram isn’t Kafka or PostgreSQL. It’s the reasoning behind the transaction boundary and the recovery behavior.</p><p>When an interviewer asks why you introduced a message broker, explaining throughput is only part of the answer. You should also be able to describe ordering requirements, retry behavior, consumer lag, poison messages, and the operational cost of maintaining the messaging infrastructure.</p><p>Sometimes a simpler synchronous workflow is sufficient.</p><p>Choosing that simpler design can be a stronger senior-level decision than introducing distributed infrastructure without a compelling requirement.</p><h3>The Redis Failure Question That Exposes Weak Architecture Decisions</h3><p>Another common system design interview pattern involves caching.</p><p>The candidate introduces Redis to reduce database load. The interviewer asks what happens when Redis becomes unavailable.</p><p>A typical answer is to fall back to PostgreSQL.</p><p>That sounds reasonable until the interviewer explains that PostgreSQL cannot handle the additional traffic.</p><p>Now the recovery mechanism may trigger a second outage.</p><p>This is a cache stampede problem, and it illustrates why failure handling must be considered alongside normal operating performance.</p><p>A more complete discussion should consider bounded concurrency, request coalescing, stale data policies, circuit breakers, and load shedding. The appropriate combination depends on whether the cached data can safely become stale and how much degradation the product can tolerate.</p><p>For a public product catalog, temporarily serving stale information may be acceptable.</p><p>For an account balance used to authorize a financial transaction, stale data may be unacceptable.</p><p>The same technology can be correct in one architecture and dangerous in another.</p><p>Experienced interviewers are interested in whether you can identify that difference without being handed the answer.</p><h3>Senior vs. Staff Engineer System Design Interviews: What Actually Changes?</h3><p>Senior and Staff interviews often cover similar technologies. The difference is usually in the scope of the decisions you’re expected to make and the consequences you’re expected to consider.</p><p>A Senior Engineer may be asked to design a reliable service, explain its scaling strategy, and handle expected failure scenarios. A Staff Engineer may face additional questions about organizational boundaries, migration strategy, operational ownership, and how the design evolves across multiple teams.</p><p>Consider a company moving from a modular monolith to microservices.</p><p>A candidate can draw the proposed target architecture with independent services and asynchronous communication. That is relatively easy.</p><p>The difficult questions concern the transition.</p><p>How do you migrate data ownership without breaking existing workflows? How do you avoid introducing distributed transactions into operations that were previously atomic? What happens when different teams deploy incompatible changes, and who is responsible for investigating incidents that cross service boundaries?</p><p>A Staff-level answer should account for migration risk, team coordination, observability, and the cost of operating the new architecture.</p><p>Sometimes the best recommendation is to postpone the migration.</p><p>A modular monolith with clear boundaries may satisfy the company’s requirements with less operational complexity. If the organization cannot articulate which constraints require independent deployment or scaling, introducing microservices may create more problems than it solves.</p><p>That judgment is difficult to demonstrate if your interview preparation consists entirely of reproducing popular diagrams.</p><h3>How I Changed My System Design Interview Preparation</h3><p>After struggling with architecture discussions, I began approaching preparation differently.</p><p>Instead of memorizing a complete design and trying to reproduce it, I would take a system I understood and deliberately break one assumption. I might increase traffic tenfold, remove Redis, delay Kafka consumers, or introduce a database failover during a write.</p><p>Then I would ask myself what the system could still guarantee.</p><p>That exercise forced me to think about behavior rather than components.</p><p>I also started practicing explanations aloud. Understanding a trade-off internally is different from communicating it to an interviewer who has limited time and may challenge your assumptions halfway through an answer.</p><p>For example, saying that PostgreSQL provides strong consistency is too vague for a serious architecture discussion. The actual guarantees depend on transaction isolation, replication topology, read routing, and the operations being performed.</p><p>A stronger explanation connects the technology to a specific invariant.</p><p>If the requirement is that a payment cannot be recorded twice for the same logical operation, I should explain which database constraint or transactional mechanism enforces that rule and what happens during concurrent requests.</p><p>This became the foundation of how I organized my system design preparation.</p><h3>The preparation system I built from these lessons</h3><p>I eventually turned that approach into the <a href="https://devrimozcay.gumroad.com/l/ekqckb"><strong>Senior &amp; Staff System Design Interview OS</strong></a>, built around the preparation methods I used myself and the interview weaknesses I had to address. It combines an 89-page interview playbook with a 41-page Visual Architecture Atlas containing 36 architecture diagrams, for 130 pages in total.</p><p>The material focuses on the parts of system design interviews that become difficult after the initial architecture is drawn. It covers requirement clarification, the first 90 seconds of an interview, architecture trade-offs, scaling bottlenecks, dependency failures, and interviewer follow-up questions that force you to reconsider your original assumptions.</p><p>The diagrams are useful for recognizing architectural patterns, but I designed the preparation around explaining why a component belongs in the system and what happens when it fails. You can <a href="https://devrimozcay.gumroad.com/l/ekqckb">explore the complete System Design Interview OS here</a> if you’re preparing for Senior or Staff engineering interviews and want a more structured way to practice.</p><h3>Five Advanced System Design Interview Questions Worth Practicing</h3><p>The following questions are useful because they force you to move beyond architecture vocabulary and explain concrete system behavior.</p><h3>1. How would you prevent duplicate payments when clients retry requests?</h3><p>Start by defining what constitutes the same logical operation. Discuss durable idempotency keys, request fingerprints, concurrency control, and the behavior of the external payment provider.</p><p>Then explain how the system handles an operation whose outcome is uncertain after a timeout.</p><h3>2. How would you design a notification system that handles provider rate limits?</h3><p>Consider per-provider throughput limits, bounded queues, backpressure, retry scheduling, and dead-letter handling. Explain how you would prevent retries from overwhelming the provider and how you would detect messages that are repeatedly failing.</p><p>Also define whether duplicate notifications are acceptable and how delivery attempts are recorded.</p><h3>3. What happens when Redis fails during peak traffic?</h3><p>Estimate the additional load that would reach the database and determine whether the system can absorb it. Discuss request coalescing, bounded fallback traffic, circuit breakers, and whether stale responses are safe for the business operation.</p><p>The objective is to prevent the recovery strategy from creating a cascading failure.</p><h3>4. How do you keep PostgreSQL and Kafka consistent?</h3><p>Explain why a normal database transaction cannot atomically commit a Kafka publication without additional coordination. Discuss the transactional outbox pattern, publisher recovery, duplicate delivery, and idempotent consumers.</p><p>Be precise about which guarantees the proposed design provides and which it does not.</p><h3>5. When should a company avoid microservices?</h3><p>Evaluate independent scaling requirements, deployment constraints, team ownership, data consistency, and operational maturity. A modular monolith may be a better fit when the system’s complexity doesn’t justify distributed coordination.</p><p>A good answer explains what would need to change before microservices became worthwhile.</p><p>These questions are especially valuable because there is rarely a single universally correct architecture. The interviewer is evaluating whether your reasoning remains coherent as the constraints evolve.</p><h3>How to Practice System Design Interviews Without Memorizing Answers</h3><p>One useful exercise is to choose a familiar system and design it under a strict time limit. Spend the opening minutes clarifying requirements, then present the simplest architecture that satisfies them.</p><p>Afterward, introduce a failure that invalidates one of your assumptions.</p><p>If you designed a notification service, imagine the provider becomes unavailable for an hour. If you designed a payment system, imagine the database commits but the response disappears. If you designed a read-heavy API, imagine the cache fails during peak traffic.</p><p>Explain the resulting failure path and revise the design.</p><p>The exercise becomes more useful when you record your explanation or practice with another engineer. You’ll notice where your reasoning becomes vague, where you introduce technologies without justification, and where you rely on guarantees you haven’t actually established.</p><p>Over time, the goal is to become comfortable defending imperfect but deliberate architecture decisions.</p><p>Real production systems are full of trade-offs. Strong system design interviews reflect that reality.</p><h3>Frequently Asked Questions About Senior and Staff System Design Interviews</h3><h3>What is the best way to prepare for a Senior Software Engineer system design interview?</h3><p>Practice designing systems from requirements and explaining the trade-offs behind your decisions. Include capacity estimation, database consistency, caching, asynchronous processing, reliability, and failure recovery. Use architecture diagrams as references, then practice changing assumptions and defending the resulting design.</p><h3>Why do experienced software engineers fail system design interviews?</h3><p>Experience doesn’t automatically translate into a clear interview explanation. Some engineers know the technologies but struggle to communicate constraints, defend trade-offs, or adapt when requirements change. Practicing structured reasoning and realistic failure scenarios can help address that gap.</p><h3>What is the difference between Senior and Staff Engineer system design interviews?</h3><p>Senior interviews commonly emphasize designing and operating reliable systems within a defined scope. Staff interviews may place greater weight on cross-team architecture, migration strategy, organizational constraints, and long-term technical decisions. Expectations vary by company, so candidates should study the role’s actual responsibilities.</p><h3>How do you handle changing requirements in a system design interview?</h3><p>Identify which original assumptions are no longer valid and explain the consequences before changing the architecture. Preserve components that still satisfy the requirements and revise the parts affected by the new constraints. Communicating that reasoning is usually more valuable than immediately drawing an entirely new system.</p><h3>How important is capacity estimation in system design interviews?</h3><p>Capacity estimation helps establish whether a proposed architecture is plausible. Rough calculations for requests per second, storage growth, bandwidth, and peak traffic can reveal scaling bottlenecks early. The estimates don’t need to be perfectly precise, but their assumptions should be explicit and defensible.</p><h3>Should I use Kafka in every system design interview?</h3><p>No. Kafka is appropriate when its messaging, throughput, retention, and consumption characteristics satisfy actual requirements. It introduces operational complexity and delivery considerations that may be unnecessary for smaller or simpler systems. Explain why the broker is needed before adding it to the architecture.</p><h3>How do you explain database consistency in a system design interview?</h3><p>Begin with the business invariant that must be preserved. Then discuss the transaction boundaries, isolation levels, concurrency controls, and replication behavior relevant to that invariant. Avoid describing an entire database as simply consistent or inconsistent without specifying the operation and failure scenario.</p><h3>What are the most important distributed systems concepts for Staff Engineer interviews?</h3><p>Consistency models, idempotency, partial failures, retries, messaging semantics, backpressure, observability, data ownership, and recovery strategies are particularly useful. Staff-level discussions may also include migrations, organizational boundaries, and the operational cost of architectural decisions. Understanding how these concepts interact matters more than memorizing their definitions.</p><h3>How do you answer system design questions when you don’t know the ideal architecture?</h3><p>State your assumptions, identify the most important constraints, and propose a reasonable starting point. Explain the risks of your approach and what additional information would change your decision. Interviewers can evaluate your reasoning even when the problem doesn’t have a single definitive solution.</p><h3>Are architecture diagrams enough to prepare for system design interviews?</h3><p>Architecture diagrams help you recognize patterns and communicate component relationships. They cannot fully demonstrate failure recovery, consistency guarantees, or the reasoning behind technology choices. The strongest preparation combines diagrams with trade-off analysis and realistic follow-up questions.</p><h3>The Part of System Design Interviews I Understand Differently Now</h3><p>I used to measure my preparation by how many systems I could design from memory. If I could draw a URL shortener, chat application, notification platform, and payment service without consulting notes, I assumed I was ready.</p><p>That confidence disappeared whenever an interviewer introduced a failure I hadn’t rehearsed.</p><p>The more useful measure became whether I could explain the behavior of my design when an operation completed only partially, a dependency became unavailable, or a business requirement invalidated my original assumptions.</p><p>I still study architecture diagrams. They’re useful references, especially when comparing common patterns and understanding how systems are structured.</p><p>But I spend considerably more time thinking about what happens between the components.</p><p>That’s where many production incidents begin, and it’s where some of the most revealing Senior and Staff interview questions come from.</p><h3>Go Deeper: System Design, Production Engineering, and Senior/Staff Interviews</h3><p>I write more detailed engineering breakdowns on my <a href="https://substack.com/@devrimozcay1"><strong>free Substack</strong></a>, including distributed systems failures, backend architecture decisions, production debugging, and the technical judgment expected from experienced engineers. If you enjoy understanding why an architecture works under normal traffic and what happens when its assumptions fail, those are the subjects I explore there.</p><p>For structured interview preparation, I built the <a href="https://devrimozcay.gumroad.com/l/ekqckb"><strong>Senior &amp; Staff System Design Interview OS</strong></a> from my own preparation methods and interview experience. It includes a 130-page system design resource with 36 architecture diagrams, an 89-page playbook, and exercises focused on difficult follow-up questions, scaling decisions, architecture trade-offs, and production failure scenarios.</p><p>The material is designed for engineers who already know the fundamentals and want to become more confident explaining technical decisions when an interviewer starts pushing beyond the diagram.</p><p><a href="https://devrimozcay.gumroad.com/l/ekqckb"><strong>Explore the Senior &amp; Staff System Design Interview OS</strong></a></p><p>staff engineer system design interview, system design interview preparation, advanced system design interview questions, distributed systems interview, system design interview mistakes, payment system design interview, Kafka system design interview, system design architecture tradeoffs.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ee57967823fb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-failed-system-design-interviews-until-i-stopped-drawing-perfect-architectures-ee57967823fb">I Failed System Design Interviews Until I Stopped Drawing Perfect Architectures</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Cut PostgreSQL Query Time by 91%. The Index Wasn’t the Fix.]]></title>
            <link>https://medium.com/engineering-playbook/we-cut-postgresql-query-time-by-91-the-index-wasnt-the-fix-372c3e5104d5?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/372c3e5104d5</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[postgresql]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Thu, 12 Nov 2026 16:20:32 GMT</pubDate>
            <atom:updated>2026-11-12T16:21:17.395Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xxRdPAUK-Pzu5_8ef70ndQ.png" /></figure><h4><em>Our first optimization made the query faster in staging and barely moved production latency. The real problem was how Hibernate, PostgreSQL, and the API contract interacted under load.</em></h4><p>The first optimization looked convincing. A query that had been taking around 900 milliseconds in our staging benchmark dropped to 80 milliseconds after we added a composite index. The execution plan improved, buffer reads decreased, and the engineer who proposed the change had every reason to believe we’d solved the performance problem. We deployed it expecting a noticeable improvement in the account dashboard.</p><p>Production latency barely moved.</p><p>The endpoint’s p95 response time was still above two seconds during peak traffic. PostgreSQL CPU utilization remained elevated, and the HikariCP connection pool continued approaching saturation. We had made one SQL statement significantly faster without making the business operation much faster.</p><p>That result changed the investigation. We stopped asking how to optimize the slowest query and started asking what actually happened between an incoming HTTP request and the completed response.</p><p>The case below is a reconstructed engineering scenario, with illustrative measurements rather than claimed production results. The investigation reflects the kind of analysis I’d use on a Java, Spring Boot, Hibernate, and PostgreSQL system where conventional query tuning has stopped producing meaningful gains.</p><h3>Our Original Architecture Looked Reasonable</h3><p>The endpoint returned account information for a B2B SaaS dashboard. Customers could see their active subscriptions, recent invoices, payment status, and a summary of their usage. The application was built with Spring Boot, Hibernate, and PostgreSQL, with Redis used for a limited set of frequently accessed reference data.</p><p>The dashboard had grown gradually. The original API returned account metadata and a subscription summary, but later releases added billing details and usage information. Instead of redesigning the read path, the team extended the existing service and reused the same JPA entity relationships.</p><p>Nothing in the controller suggested a serious problem.</p><pre>@GetMapping(&quot;/accounts/{accountId}/dashboard&quot;)<br>public AccountDashboardResponse getDashboard(<br>        @PathVariable UUID accountId) {<br><br>  return dashboardService.getDashboard(accountId);<br>}</pre><p>The service loaded the account, mapped its relationships into response objects, and returned the result. Most of the work lived inside repository calls and mapping code, which made the endpoint appear simpler than the database workload it generated.</p><p>Our first mistake was assuming that a simple service method implied a simple execution path.</p><p>The second was trusting the duration of the most expensive SQL statement as a reasonable approximation of the endpoint’s database cost.</p><h3>We Optimized the Query Everyone Was Complaining About</h3><p>The slow-query logs pointed toward a statement retrieving recent invoices for an account.</p><p>The query filtered by account_id, ordered invoices by creation time, and returned the latest records.</p><pre>SELECT id, account_id, amount, status, created_at<br>FROM invoices<br>WHERE account_id = $1<br>ORDER BY created_at DESC<br>LIMIT 50;</pre><p>The table contained millions of invoices. The existing indexes were useful for other access patterns, but the query plan showed more work than we expected for a request that needed only fifty rows.</p><p>We added a composite index.</p><pre>CREATE INDEX CONCURRENTLY idx_invoices_account_created<br>ON invoices (account_id, created_at DESC);</pre><p>The change was technically justified. It aligned the index with the equality filter and ordering requirement, allowing PostgreSQL to retrieve the relevant rows more efficiently.</p><p>In the illustrative benchmark, the statement dropped from approximately 900 milliseconds to 80 milliseconds.</p><p>If we had been evaluating that query in isolation, the optimization would have been a success.</p><p>The problem was that the endpoint didn’t execute the query in isolation.</p><p>During a single dashboard request, Hibernate was issuing additional statements to load subscription relationships, invoice line items, payment metadata, and usage records.</p><p>Some queries were individually fast. There were simply too many of them.</p><h3>The Trace Told a Different Story Than the Slow-Query Log</h3><p>We added request-level tracing around the dashboard operation and correlated the trace with database activity.</p><p>The result was uncomfortable.</p><p>The optimized invoice query accounted for only part of the endpoint’s database time. Entity mapping triggered additional SQL statements, and the number of statements increased with the number of invoices returned.</p><p>For an account with fifty recent invoices, the application could issue queries for the invoices themselves, then additional queries for associated entities.</p><p>The behavior depended on the entity mappings, fetch configuration, and which relationships the mapper accessed.</p><p>It was a classic Hibernate N+1 pattern, although the actual request contained several related query families rather than one neat textbook example.</p><p>The mapper looked innocent:</p><pre>return invoices.stream()<br>    .map(invoice -&gt; new InvoiceResponse(<br>        invoice.getId(),<br>        invoice.getAmount(),<br>        invoice.getStatus(),<br>        invoice.getLineItems().size()<br>    ))<br>    .toList();</pre><p>If lineItems was a lazy collection that had not already been initialized, accessing it could trigger another database query for each invoice.</p><p>The service didn’t explicitly execute those queries. Hibernate did it while the application constructed the response.</p><p>This explained why the index improvement had barely affected production latency. We had reduced the cost of one statement while leaving the rest of the request’s database round trips intact.</p><p>At that point, I wanted two numbers for every representative request: how many SQL statements it executed and how much total time those statements consumed.</p><p>The slowest query was no longer our primary unit of investigation.</p><h3>We Tried JOIN FETCH. It Created a Different Problem.</h3><p>The first proposed correction was to fetch the related entities eagerly in one query.</p><p>For small collections, a targeted fetch join can eliminate repeated round trips. It is a legitimate Hibernate optimization when the resulting data volume and query shape are understood.</p><p>Our dashboard had a less convenient requirement.</p><p>It needed the fifty most recent invoices, each potentially containing multiple line items. Joining invoices to line items could multiply the number of SQL result rows.</p><p>Fifty invoices with an average of eight line items could produce hundreds of joined rows before Hibernate reconstructed the entity graph.</p><p>That row multiplication affected network transfer, memory allocation, and result processing.</p><p>Pagination made the design more troublesome. Combining collection fetch joins with limits can prevent the database from applying pagination in the intended way, depending on the query and Hibernate behavior.</p><p>We enabled the Hibernate setting that fails when pagination over a collection fetch would otherwise be handled in memory:</p><pre>spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch=true</pre><p>The setting was useful because it converted a potentially expensive behavior into an explicit failure during development.</p><p>It didn’t solve the dashboard query. It forced us to acknowledge that the read model itself needed attention.</p><p>We had been trying to make a complex entity graph behave like a lightweight API response.</p><h3>The Better Fix Was to Stop Loading Objects We Didn’t Need</h3><p>The dashboard wasn’t an entity editor. It didn’t need fully managed invoice aggregates with every relationship available for later modification.</p><p>It needed a small, defined set of fields.</p><p>That distinction gave us a simpler design.</p><p>We replaced broad entity loading with targeted projections for the invoice summary. The query returned the fields required by the response contract and avoided initializing unrelated associations.</p><p>For counts and totals, we used explicit aggregation queries where appropriate rather than loading entire collections into Java merely to count them.</p><p>For example:</p><pre>SELECT<br>    i.id,<br>    i.amount,<br>    i.status,<br>    i.created_at,<br>    COUNT(li.id) AS line_item_count<br>FROM invoices i<br>LEFT JOIN invoice_line_items li<br>    ON li.invoice_id = i.id<br>WHERE i.account_id = $1<br>GROUP BY i.id, i.amount, i.status, i.created_at<br>ORDER BY i.created_at DESC<br>LIMIT 50;</pre><p>This illustrates the projection approach, although the precise production query would depend on schema constraints, row cardinality, and execution plans. On large tables, it can be preferable to select the fifty invoice IDs first and aggregate line items only for that bounded set.</p><p>The key improvement was controlling how much data the application requested.</p><p>Instead of allowing entity traversal to determine database access dynamically, the endpoint used queries designed around its response requirements.</p><p>We also separated information that genuinely needed transactional freshness from information that could tolerate delayed updates.</p><p>The dashboard had been treating all fields as though they required identical consistency and latency guarantees.</p><p>They didn’t.</p><p>A recently confirmed payment status deserved stronger freshness guarantees than a historical usage chart. Making that distinction reduced the amount of work required on the critical response path.</p><h3>The Connection Pool Was Still a Problem</h3><p>After reducing the query count, the endpoint became substantially faster in controlled tests.</p><p>Under sustained concurrency, however, we still saw occasional connection acquisition delays.</p><p>The earlier investigation had focused on the maximum number of HikariCP connections. This time we examined how long each request occupied a connection and whether the application held transactional resources while performing unrelated work.</p><p>One service method used a read-only transaction around the entire dashboard assembly process.</p><p>That transaction included database reads and additional application-side processing.</p><p>A read-only transaction can be useful, but it doesn’t mean the method is free of transactional resource costs. Depending on when the connection is acquired and how the persistence context is used, the application may retain database resources longer than necessary.</p><p>We reviewed the transaction boundaries and removed unnecessary work from the transactional section.</p><p>The goal wasn’t to make every transaction as short as theoretically possible. We wanted database resources to remain occupied only for the period required to preserve the operation’s intended consistency.</p><p>That change mattered under concurrency because connection-pool pressure is affected by connection occupancy time.</p><p>A useful approximation is Little’s Law: under stable conditions, the average number of operations in a system relates to arrival rate and average time spent there.</p><p>For a connection pool, reducing the time each operation holds a connection can improve the number of requests the same pool can support, assuming the workload and database capacity allow it.</p><p>Increasing the pool size would not have addressed the unnecessarily long occupancy.</p><h3>The Numbers Finally Started Moving Together</h3><p>We repeated the benchmark with a representative dataset and a fixed concurrency profile.</p><p>This time, we measured the complete request rather than reporting only the slowest SQL statement.</p><p>&lt;escape&gt;</p><p>MetricOriginalAfter indexAfter read-path redesignInvoice query duration900 ms80 ms80 msSQL statements per request1261266Endpoint p95 latency2,400 ms2,180 ms410 msHikariCP acquisition p95310 ms290 ms24 ms</p><p>&lt;/escape&gt;</p><p>These are illustrative benchmark values, not measured results from a named production system. They show why the initial optimization was insufficient and how I would evaluate the broader correction.</p><p>The index reduced one query’s duration by roughly 91%. Yet the endpoint’s p95 latency improved by less than 10% after that change alone.</p><p>The meaningful improvement came when we reduced repeated database access and shortened the time requests occupied constrained resources.</p><p>In this example, endpoint p95 fell from 2,400 milliseconds to 410 milliseconds after the broader redesign, an improvement of approximately 83%.</p><p>Those numbers are more useful to an engineering leader than a statement claiming that one SQL query became dramatically faster.</p><p>Customers experience request latency. Infrastructure pays for the total workload. Engineers need to understand the relationship between them.</p><h3>We Also Changed How We Reviewed Performance Pull Requests</h3><p>The technical fix addressed the immediate endpoint, but the incident exposed a problem in our development process.</p><p>Our pull request reviews focused on repository methods, indexes, and obvious algorithmic complexity. We rarely examined the number of SQL statements generated by a complete API operation.</p><p>That allowed database access patterns to change without attracting attention.</p><p>We added integration tests that exercised representative dashboard requests and inspected Hibernate statistics. For critical read paths, the team could detect unexpected increases in statement count before deployment.</p><p>We didn’t establish one universal SQL-count threshold for every endpoint. Some operations legitimately require more database interactions than others.</p><p>Instead, we created expectations for the workflows where query amplification would be expensive.</p><p>We also made performance reviews more specific.</p><p>A change to an entity relationship or DTO mapper deserved attention if it could alter lazy-loading behavior. A new dashboard field required an explanation of where its data came from and whether it introduced another query or remote dependency.</p><p>These practices weren’t particularly glamorous. They reduced the chance that a harmless-looking response field would quietly multiply database work.</p><p>The team had previously treated performance as something to investigate after an alert.</p><p>We began treating database access behavior as part of the API contract.</p><h3>What I’d Do Differently on the Next System</h3><p>The next time a Spring Boot service shows high PostgreSQL latency, I wouldn’t begin by assuming the slowest query is responsible for the slow endpoint.</p><p>I’d first trace a representative request and identify its total database workload.</p><p>That includes the number of statements executed, their cumulative duration, connection acquisition delays, transaction boundaries, and any SQL triggered during entity mapping or serialization.</p><p>Then I’d compare the behavior under light and sustained load.</p><p>A request that executes 120 individually fast queries may perform acceptably on a developer laptop while becoming expensive under real concurrency. A query that is genuinely slow may require indexing, query restructuring, or changes to the data model.</p><p>Those are different problems, and they deserve different fixes.</p><p>I’d also resist optimizing every endpoint with aggressive eager fetching. Loading more data in fewer queries can be useful, but it can create its own memory and pagination problems.</p><p>For read-heavy SaaS endpoints, purpose-built projections are often easier to reason about than exposing large JPA entity graphs to the response layer.</p><p>The final decision should be driven by the workload and the consistency requirements of the operation.</p><h3>The Index Was Correct. Our Diagnosis Was Too Narrow.</h3><p>The composite index stayed.</p><p>It was a valid improvement, and removing it would have made the invoice query slower again.</p><p>What changed was our understanding of the incident.</p><p>The endpoint had accumulated responsibilities over several releases, and Hibernate had made the resulting database access patterns easy to overlook. Our first benchmark measured a SQL statement, while customers were waiting for a much larger operation.</p><p>The index solved the problem we had measured. It simply wasn’t the problem that dominated the user experience.</p><p>For an engineering leader, this is the part worth remembering. Performance work should be evaluated against the business operation it is supposed to improve, with enough instrumentation to explain why the numbers changed.</p><p>Otherwise, a team can celebrate a 91% query improvement while customers continue staring at the same slow dashboard.</p><h3>Backend Performance &amp; Architecture Consulting</h3><p>I’m Devrim Ozcay, founder of <strong>ProdRescue AI</strong>, an independent engineering consulting practice focused on Java and Spring Boot systems, PostgreSQL performance, distributed architectures, and production reliability.</p><p>I work with SaaS founders, CTOs, and engineering leaders who need an external technical assessment of backend performance problems, inefficient data-access patterns, transaction behavior, and architectural risks that are difficult to isolate during normal development.</p><p>Our engagements include focused architecture reviews, technical risk assessments, written recommendations, and ongoing engineering advisory. Monthly consulting plans start at <strong>$750</strong>.</p><p><strong>Explore consulting services:</strong></p><p><a href="https://devrimozcay.gumroad.com/l/uwzfw">ProdRescue AI: Backend Reliability, Architecture &amp; Production Engineering Consulting</a></p><p><strong>ProdRescue AI:</strong></p><p><a href="https://www.prodrescueai.com/">ProdRescue: AI Postmortem &amp; RCA Generator for Backend Teams</a></p><p><strong>Business inquiries:</strong> <a href="mailto:info@prodrescueai.com">info@prodrescueai.com</a></p><p>If your team has already optimized SQL queries but still sees high API latency, connection-pool pressure, or unpredictable PostgreSQL performance, email me a brief description of the system and the changes you’ve tried. We can discuss whether a focused backend architecture review would help identify the remaining bottlenecks.</p><h3>Frequently Asked Questions</h3><h3>Why is my Spring Boot API slow even after optimizing PostgreSQL queries?</h3><p>The endpoint may execute many additional SQL statements through Hibernate lazy loading, entity mapping, or other repository calls. Connection acquisition delays, transaction duration, and downstream dependencies can also dominate response time.</p><h3>How do I detect N+1 queries in Spring Boot and Hibernate?</h3><p>Inspect generated SQL and Hibernate statistics while executing representative API requests. Look for repeated queries triggered by accessing relationships during DTO mapping, serialization, or collection traversal.</p><h3>Is JOIN FETCH always better than lazy loading in Hibernate?</h3><p>No. Fetch joins can reduce database round trips, but collection joins may multiply result rows and create pagination or memory problems. Targeted projections or bounded batch loading may be more appropriate.</p><h3>How do I reduce HikariCP connection acquisition time?</h3><p>Investigate transaction duration, database query performance, connection occupancy, and application concurrency. Increasing pool size can help in some circumstances, but it can worsen database contention when the underlying workload is inefficient.</p><h3>Should I use DTO projections instead of JPA entities for read-heavy APIs?</h3><p>DTO projections are often useful when an endpoint needs a defined subset of fields and doesn’t require managed entity behavior. They can reduce unnecessary data loading and make SQL access patterns easier to control.</p><h3>How should I benchmark PostgreSQL performance in a SaaS application?</h3><p>Measure complete business operations under representative data volume and concurrency. Include request latency percentiles, SQL statement count, cumulative database time, connection acquisition latency, and resource utilization.</p><p>Spring Boot PostgreSQL performance, Hibernate N+1 query, Spring Boot slow API, HikariCP connection acquisition time, Hibernate DTO projection, PostgreSQL query optimization, JPA performance tuning, Spring Boot database bottleneck.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=372c3e5104d5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/we-cut-postgresql-query-time-by-91-the-index-wasnt-the-fix-372c3e5104d5">We Cut PostgreSQL Query Time by 91%. The Index Wasn’t the Fix.</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Our Staff Engineer Refused to Return to the Office. We Hired Two People to Replace Him]]></title>
            <link>https://medium.com/engineering-playbook/our-staff-engineer-refused-to-return-to-the-office-we-hired-two-people-to-replace-him-68dd01450709?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/68dd01450709</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:13:39 GMT</pubDate>
            <atom:updated>2026-11-11T18:13:56.760Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zFThAygnbIsOpXzQwr8stA.png" /></figure><h4><em>HR called it a culture decision. Finance called it an expensive hiring problem. The engineering team had a more uncomfortable explanation.</em></h4><p>The email arrived at 8:42 on a Monday morning, two hours before our engineering leadership meeting. Starting in January, every employee within commuting distance of an office would be required to work on-site four days a week. Exceptions would require executive approval, and managers were instructed to treat the policy as a company-wide operating standard rather than a subject for individual negotiation.</p><p>Our Staff Engineer, Daniel, forwarded the announcement to his manager with a short response. He had been working remotely for four years, had led the redesign of our payment infrastructure, and was responsible for several services that operated across three engineering teams. He wanted to know whether the company intended to evaluate his work differently after January.</p><p>His manager replied that the policy was about collaboration, mentorship, and rebuilding engineering culture. Daniel asked which of his responsibilities had become harder to perform remotely. The manager suggested discussing it during their next one-on-one.</p><p>That conversation lasted twenty-seven minutes. Daniel explained that his work already involved engineers in different cities, that most architectural discussions happened through shared documents, and that production incidents were handled through remote collaboration regardless of where anyone sat. His manager acknowledged the points but said the company needed consistent expectations.</p><p>Daniel asked for an exception and was denied. Six weeks later, he resigned.</p><p>The engineering director described the departure as unfortunate but necessary to preserve fairness. HR emphasized that the company could not create separate rules for highly compensated employees. The CEO praised the leadership team for maintaining a consistent culture.</p><p>Three months later, we had hired two engineers to absorb Daniel’s responsibilities. One focused on backend architecture, while the other took ownership of reliability and infrastructure coordination. Both were capable, experienced professionals, and neither had done anything wrong.</p><p>Together, their compensation exceeded Daniel’s previous package by a substantial margin. The transition had also consumed hundreds of engineering hours, delayed two projects, and exposed gaps in our understanding of systems Daniel had maintained for years.</p><p>During the next budget review, our CFO asked why enforcing a collaboration policy had required additional engineering headcount.</p><p>Nobody had included that possibility in the original return-to-office proposal.</p><h3>The Return-to-Office Policy Was Written for a Different Kind of Work</h3><p>Our company had grown rapidly during the remote-work years. Engineering teams were distributed across several locations, and most technical decisions were documented asynchronously. Developers used GitHub for code reviews, shared design documents for architecture discussions, and incident channels for production coordination.</p><p>The company still maintained offices, but attendance varied by team. Some employees preferred working on-site, while others came in for planning sessions or occasional collaboration days. There was no universal schedule, and managers generally evaluated performance through delivery, technical impact, and team responsibilities.</p><p>The new policy changed that arrangement. Leadership argued that remote work had weakened informal communication and made it harder for newer employees to learn from experienced colleagues. Those concerns were legitimate enough to deserve investigation, particularly in teams where onboarding and mentoring had become inconsistent.</p><p>However, the policy applied broadly without distinguishing between teams that worked primarily in one location and teams whose members were geographically distributed. It also assumed that physical attendance would improve collaboration even when the people who needed to collaborate were sitting in different offices.</p><p>Daniel’s team illustrated the problem. His closest engineering partners were located in three cities, and his most important meetings already took place through video calls. Returning to the office would have changed his physical location without placing most of his collaborators in the same room.</p><p>The policy had been designed around a general belief about company culture. Nobody had demonstrated how four office days would improve the specific engineering work Daniel performed.</p><h3>Staff Engineers Create Value That Doesn’t Fit an Attendance Dashboard</h3><p>Daniel’s responsibilities extended well beyond implementing features. He reviewed architectural decisions across teams, helped engineers resolve difficult production problems, and maintained technical context that connected several business-critical systems. His calendar contained design reviews, mentoring sessions, and operational discussions that rarely resulted in visible individual deliverables.</p><p>His influence was especially important during incidents. When a payment service experienced unusual latency, Daniel could often identify which downstream dependencies were relevant and which recent changes deserved investigation. He knew the historical reasons behind several architectural compromises and understood which parts of the system were safe to modify under pressure.</p><p>That expertise had developed over years of maintaining the platform. It was not tied to his home office, the company’s headquarters, or the number of hours he spent near other employees.</p><p>The engineering director believed that experienced engineers should be physically available to mentor junior developers. Daniel agreed that mentoring mattered, but he questioned whether office attendance was an effective measure of mentorship. He regularly reviewed designs with engineers in other locations and had created internal technical workshops that employees could attend regardless of geography.</p><p>The director suggested that spontaneous conversations were difficult to reproduce remotely. Daniel acknowledged that informal interactions could be useful, but he wanted the company to examine whether those benefits justified the costs of changing established working arrangements.</p><p>The discussion never reached that level of detail. Leadership had already decided that consistent attendance was the priority.</p><h3>The Staff Engineer Asked One Question HR Couldn’t Answer</h3><p>During his exception review, Daniel presented evidence of his work. He showed cross-team architecture proposals, mentoring records, production incident contributions, and delivery outcomes from the previous year. His argument was that the company should evaluate whether remote work had reduced his effectiveness before requiring a change.</p><p>HR responded that exceptions based on individual performance would create fairness concerns. If one employee received permission to remain remote, others might request the same arrangement. The company wanted a policy that managers could apply consistently.</p><p>Daniel asked whether fairness meant treating every role identically or evaluating employees according to the requirements of their work. The HR representative said the policy was intended to establish shared expectations across the organization. His manager added that leadership believed the long-term cultural benefits would outweigh short-term disruption.</p><p>Daniel asked whether those benefits had been measured. The answer was that the company expected to evaluate the policy after implementation.</p><p>The exception was denied because approving it would have conflicted with the policy’s stated objective. Daniel left the meeting with no further appeal available.</p><p>A few days later, he began interviewing.</p><h3>The Resignation Looked Ordinary Until We Opened the Ownership Map</h3><p>Daniel gave the company a standard notice period and offered to document his responsibilities before leaving. His manager accepted the resignation professionally and began preparing a transition plan. The initial assumption was that his work could be redistributed among existing senior engineers until a replacement was hired.</p><p>The ownership review complicated that assumption. Daniel was involved in payment processing, database architecture, incident response, and technical decisions across several teams. Some responsibilities were clearly documented, while others existed through informal consultation and historical knowledge.</p><p>One senior engineer could take ownership of the payment services, but doing so would reduce her availability for a major migration project. Another engineer understood the infrastructure but lacked experience with the business rules governing transaction recovery. The engineering manager could coordinate the work, but he was already responsible for delivery planning and personnel management.</p><p>The team eventually divided Daniel’s responsibilities into separate areas. Backend architecture would require one experienced engineer, while reliability and operational coordination would require another. The director initially considered hiring a single Staff Engineer, but the available candidates did not consistently match the combination of expertise Daniel had developed internally.</p><p>The recruiting team recommended opening two positions. Leadership approved the plan because the affected systems were too important to leave without clear ownership.</p><p>The company had rejected Daniel’s exception partly to avoid creating a precedent. It was now creating two new positions to replace the capabilities that precedent might have retained.</p><h3>The Cost of Replacing a Staff Engineer Wasn’t Just Salary</h3><p>The finance team initially compared Daniel’s compensation with the proposed replacement packages. That calculation was straightforward, but it did not capture the full cost of the transition. Recruiting required time from hiring managers and senior engineers, while onboarding reduced the capacity of employees who were already responsible for ongoing delivery.</p><p>The two new engineers also needed to learn the platform. They understood distributed systems and backend architecture, but they had not participated in the incidents and design decisions that shaped our existing services. Their early work therefore involved reconstructing context from documentation, code history, and conversations with remaining team members.</p><p>Several projects slowed during the transition. A payment reconciliation improvement was delayed because the engineer responsible for it had been reassigned to operational support. An infrastructure modernization initiative also lost momentum while the team established new ownership boundaries.</p><p>The engineering director argued that these were temporary costs. He was correct that onboarding expenses would decline as the new engineers became productive. However, the original policy decision had not considered those costs at all.</p><p>The CFO asked for an estimate of the financial impact. The engineering manager could identify additional compensation, recruiting expenses, and some delayed project work, but other costs were difficult to quantify reliably. The company had not maintained a model for evaluating the business impact of losing critical engineering expertise.</p><p>Finance began treating the resignation as a retention case that had never received a proper economic review.</p><h3>Remote Work Productivity Was Never the Actual Disagreement</h3><p>The return-to-office debate had become emotionally charged across the company. Some employees believed remote work improved concentration and flexibility, while others preferred the social interaction and faster informal communication of office environments. Both groups had legitimate experiences, but the policy discussion increasingly treated those preferences as competing ideologies.</p><p>Daniel’s argument was narrower. He wanted his working arrangement evaluated according to the responsibilities of his role and the outcomes he delivered. He had not claimed that remote work was universally superior or that office attendance had no value.</p><p>The engineering director believed shared physical space could improve mentoring and collaboration. That belief was reasonable enough to test, but the company had implemented a universal rule before establishing which problems it was solving. It had also failed to consider whether different engineering functions might benefit from different arrangements.</p><p>For example, a newly formed team working on a tightly coupled project might benefit from regular in-person planning sessions. A distributed infrastructure team responsible for global production systems may already depend on asynchronous communication and remote incident coordination. Applying identical attendance requirements to both teams does not guarantee identical benefits.</p><p>The company had treated consistency as evidence of good management. Daniel had questioned whether consistency was useful when the underlying work differed substantially.</p><p>The resignation forced leadership to confront the distinction.</p><h3>The New Engineers Were Excellent. The Transition Was Still Expensive.</h3><p>The two replacements joined within several months of Daniel’s departure. One had extensive experience designing backend services, while the other specialized in reliability engineering and operational practices. Both quickly became respected members of the organization.</p><p>Their technical ability was not the problem. The challenge was transferring ownership of systems whose important decisions had accumulated over years. Documentation explained how components worked, but it did not always explain why certain alternatives had been rejected.</p><p>The backend engineer proposed simplifying a payment workflow that appeared unnecessarily complicated. During review, another team member discovered that the additional state transitions had been introduced after an earlier incident involving uncertain payment outcomes. The design looked excessive without that history, but removing it would have recreated a known failure mode.</p><p>The reliability engineer encountered a similar issue with an internal retry mechanism. The implementation contained safeguards that seemed redundant until the team found an old incident report describing how duplicate events had affected downstream processing. Daniel had been involved in both incidents and understood the relationship between the code and the operational constraints.</p><p>The new engineers eventually reconstructed the necessary context. They also improved documentation and clarified ownership boundaries, which made the organization less dependent on any single individual.</p><p>Those improvements were valuable. They did not erase the cost of losing someone who already possessed the knowledge.</p><h3>The CEO Wanted Collaboration. The Engineers Wanted a Definition.</h3><p>After the transition, the CEO asked engineering leadership whether the return-to-office policy had improved collaboration. The director reported that office attendance had increased and that employees were spending more time together. The CEO considered those encouraging signs.</p><p>Our engineering manager asked whether attendance was the same as collaboration. He had observed more people in the office, but many still spent substantial portions of their day on video calls with colleagues in other locations. The physical environment had changed more than the structure of the work.</p><p>The director suggested that cultural improvements would take time to appear. The manager agreed that long-term effects mattered, but argued that the company needed specific outcomes to evaluate. If the objective was better mentoring, the organization should examine onboarding effectiveness and access to experienced engineers. If the objective was faster decisions, it should study decision delays and the causes behind them.</p><p>The CEO asked whether engineering leadership opposed the policy. The manager said the team needed a way to distinguish useful collaboration improvements from increased attendance. Without that distinction, the company could declare success simply because employees followed the rule.</p><p>The conversation was uncomfortable because it challenged a decision leadership had already presented as a cultural priority. However, the resignation and replacement costs had made the financial consequences difficult to ignore.</p><p>The CFO supported a more detailed evaluation. He wanted to know whether the policy was improving business outcomes enough to justify its implementation costs.</p><h3>The Return-to-Office Policy Created a Retention Risk Nobody Modeled</h3><p>The company eventually reviewed employee feedback and retention data. Some engineers appreciated more frequent in-person interaction, especially those who lived near the office and preferred structured collaboration days. Others reported longer commutes, reduced flexibility, and frustration with attending virtual meetings from office desks.</p><p>The results varied across teams. Employees working primarily with local colleagues described different experiences from those collaborating with distributed groups. The company had expected a universal policy to produce broadly similar benefits, but the effects depended heavily on how teams actually operated.</p><p>The retention analysis also revealed that several experienced engineers were reconsidering their long-term plans. They had not necessarily decided to resign, but the policy had changed the value proposition of remaining with the company. Remote flexibility had been part of their working arrangements for years, and removing it affected how they compared internal opportunities with external offers.</p><p>Leadership initially interpreted the feedback as resistance to change. The engineering manager argued that employees were responding to a material change in employment conditions. Whether leadership considered that response reasonable did not eliminate the business risk.</p><p>The company began examining the cost of losing specialized expertise in critical roles. It also considered whether attendance requirements should reflect team structure, collaboration needs, and operational responsibilities.</p><p>The policy remained in place during the review, but exceptions became easier to discuss when managers could demonstrate a clear business case.</p><h3>Staff Engineer Retention Is an Engineering Risk Management Problem</h3><p>Losing a Staff Engineer can affect more than delivery capacity. Staff-level engineers often influence architecture across teams, maintain institutional knowledge, and help organizations navigate complex technical decisions. Their value is partly reflected in the work they complete and partly in the mistakes they help others avoid.</p><p>That does not mean Staff Engineers should receive unlimited flexibility or that companies must accommodate every preference. Organizations have legitimate operational needs, and some roles require physical presence. The important question is whether a particular requirement is justified by the work and whether its benefits outweigh the associated costs.</p><p>Our company had treated Daniel’s request primarily as an HR policy issue. The decision was evaluated according to consistency and precedent, while the operational consequences of losing him received limited attention. Only after his resignation did engineering and finance examine the full impact.</p><p>The experience changed how managers approached retention discussions. Critical-role decisions began involving engineering leadership and finance earlier, particularly when an employee’s responsibilities were difficult to replace. The company also improved documentation and succession planning to reduce dependence on individual engineers.</p><p>Those changes made the organization more resilient. They also revealed that retention was not simply a matter of employee satisfaction; it was part of managing the risks associated with operating complex technical systems.</p><h3>The Company Eventually Introduced Team-Based Flexibility</h3><p>The revised policy allowed engineering teams to propose working arrangements based on collaboration requirements and operational needs. Managers had to explain how the arrangement supported delivery, mentoring, and team effectiveness. Exceptions were no longer treated automatically as threats to organizational fairness.</p><p>Some teams continued working primarily from the office. Others adopted scheduled collaboration days or maintained distributed arrangements with periodic in-person sessions. The company still expected accountability and clear performance standards, but attendance was no longer the only visible measure of collaboration.</p><p>The engineering director remained concerned about consistency. The CFO responded that consistency should exist in how decisions were evaluated, even when the resulting arrangements differed. A policy could be fair without requiring every employee to work in exactly the same way.</p><p>The new approach required more management judgment. Leaders had to understand their teams, identify collaboration problems, and evaluate whether proposed arrangements addressed those problems. That was more demanding than enforcing a universal schedule, but it also created room for decisions grounded in actual work.</p><p>Daniel did not return. He had accepted a role at another company and was satisfied with the move. Our replacements continued improving the systems they inherited, and the engineering organization gradually recovered its previous delivery capacity.</p><p>The company eventually reached a more balanced position on office attendance. The change arrived after the employee whose departure triggered the review had already moved on.</p><h3>The Real Cost of Return-to-Office Policies Depends on Who Leaves</h3><p>The debate about remote work often becomes a contest between competing assumptions about productivity and culture. Some teams benefit substantially from working together in person, while others operate effectively across locations. The relevant question for engineering leadership is how working arrangements affect the specific responsibilities, collaboration patterns, and outcomes of the organization.</p><p>Our company had introduced a broad policy without adequately considering the retention risks associated with critical engineering roles. Daniel’s resignation forced the organization to confront costs that were absent from the original proposal. Replacing his capabilities required additional compensation, recruiting effort, onboarding time, and operational adjustments.</p><p>The two new engineers were successful, and the company eventually improved its documentation and ownership practices. Those outcomes were valuable, but they did not establish that the original policy decision had been economically sound. The organization had made a cultural decision without fully evaluating its engineering consequences.</p><p>The CFO’s final review focused on that distinction. He did not argue that employees should never return to the office, and he did not suggest that every experienced engineer deserved an exception. He wanted leadership to evaluate policy decisions using the same financial discipline applied to other operational changes.</p><p>The engineering director acknowledged that the company had underestimated the cost of losing Daniel. He also admitted that attendance had been easier to measure than the collaboration improvements leadership hoped to achieve.</p><p>The revised policy was less rigid and required more judgment from managers. It reflected a recognition that different engineering teams could have different operational needs while still being held to consistent standards of performance.</p><p>Daniel’s former desk remained empty for several months. The two engineers who replaced his responsibilities eventually worked from different offices, coordinating most of their technical decisions through the same shared documents and video calls he had used.</p><h3>Frequently Asked Questions About Remote Work and Engineering Retention</h3><h3>Are return-to-office policies causing software engineers to quit?</h3><p>Return-to-office requirements can influence employee retention, particularly when they materially change established working arrangements. The impact varies by organization, labor-market conditions, employee preferences, and the availability of alternative jobs.</p><h3>Is remote work better for software engineers?</h3><p>Remote work can support concentration, flexibility, and distributed collaboration, while office work may improve certain forms of informal communication and mentoring. The best arrangement depends on team structure, responsibilities, and individual circumstances.</p><h3>Why do Staff Engineers prefer remote work?</h3><p>Some Staff Engineers value remote work because their responsibilities involve cross-team coordination, architecture reviews, and asynchronous communication. Preferences vary, and many experienced engineers also appreciate in-person collaboration.</p><h3>What is the difference between Senior and Staff Engineer responsibilities?</h3><p>Senior Engineers typically own complex technical work within a team or domain, while Staff Engineers often influence architecture and technical direction across multiple teams. Exact expectations differ between companies.</p><h3>How much does it cost to replace a Staff Engineer?</h3><p>Replacement costs depend on compensation, recruiting expenses, onboarding time, knowledge transfer, and the impact on ongoing projects. Engineers with extensive institutional knowledge or critical system ownership may be particularly difficult to replace quickly.</p><h3>Do return-to-office policies improve collaboration?</h3><p>They can improve certain forms of collaboration, especially when team members work in the same location and benefit from frequent in-person interaction. However, increased attendance does not automatically establish improved engineering outcomes.</p><h3>How can engineering managers improve remote team collaboration?</h3><p>Managers can establish clear communication practices, document technical decisions, improve onboarding, and create opportunities for deliberate collaboration. The approach should reflect the team’s actual working patterns.</p><h3>Why is Staff Engineer retention important?</h3><p>Staff Engineers often provide technical leadership, architectural continuity, and cross-team problem-solving capabilities. Losing that expertise can affect delivery, operational reliability, and organizational knowledge.</p><h3>Should companies offer remote work exceptions to senior engineers?</h3><p>Exceptions can be appropriate when they support business needs and are evaluated through transparent criteria. Companies should consider role requirements, fairness, operational impact, and retention risks.</p><h3>How should companies measure engineering productivity?</h3><p>Engineering productivity should be evaluated through multiple signals, including delivery effectiveness, quality, reliability, collaboration, and developer experience. Attendance and activity metrics alone provide an incomplete picture.</p><h3>Free: The Engineer’s High-Stakes Playbook</h3><p>Senior engineering careers are shaped by technical decisions, organizational expectations, and the ability to recognize when a working arrangement no longer supports your goals. Understanding your responsibilities and the value you provide becomes especially important during compensation, promotion, and career negotiations.</p><p>I created a free engineering playbook covering production investigation, system design reasoning, and critical career decisions. It’s designed for engineers who want to make stronger decisions when technical responsibilities and organizational incentives begin pulling in different directions.</p><p><a href="https://devrimozcay.gumroad.com/l/fdiown"><strong>Get the Free Engineer’s High-Stakes Playbook</strong></a></p><h3>Help Us Build a Better System Design Interview Tool</h3><p>Senior and Staff Engineer interviews increasingly evaluate technical leadership, architectural judgment, and the ability to explain complex tradeoffs. Those skills matter whether engineers work remotely, in the office, or across distributed teams.</p><p>At ProdRescue AI, we’re researching an interactive AI-powered system design interview platform for engineers preparing for Senior, Staff, and Principal roles. We’re exploring an architecture canvas, realistic interviewer follow-up questions, and structured feedback on scalability, reliability, data consistency, and engineering tradeoffs. Your feedback will help shape the first release, and you can request early access to the private beta.</p><p><a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header"><strong>Take the 3–4 Minute System Design Tool Survey</strong></a></p><p>I also publish engineering stories about remote work, software careers, AI-assisted development, backend architecture, and the decisions that shape engineering organizations. If you enjoy discussions about what makes engineers effective and how companies manage technical talent, you’ll find more of them on my Substack.</p><p><a href="https://substack.com/@devrimozcay1"><strong>Subscribe to My Engineering Writing on Substack</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=68dd01450709" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/our-staff-engineer-refused-to-return-to-the-office-we-hired-two-people-to-replace-him-68dd01450709">Our Staff Engineer Refused to Return to the Office. We Hired Two People to Replace Him</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Got Rejected From 10 Software Engineer Jobs. Then I Stopped Saying I Knew Everything]]></title>
            <link>https://medium.com/engineering-playbook/i-got-rejected-from-10-software-engineer-jobs-then-i-stopped-saying-i-knew-everything-3ab743d5f1ad?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/3ab743d5f1ad</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:12:37 GMT</pubDate>
            <atom:updated>2026-11-11T18:13:01.298Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TDJgUlWu-SyXiZZRGgAC4g.png" /></figure><h4><em>I spent 76 days preparing for technical interviews, memorizing answers, and trying to sound like a Senior Engineer. The interview that changed everything started with a question I couldn’t answer.</em></h4><p>The interviewer asked me what would happen if a PostgreSQL transaction was interrupted while waiting for a row lock. I knew the general behavior, but I couldn’t remember the exact distinction between a statement timeout, a lock timeout, and a transaction being canceled by the client. Instead of admitting that, I started explaining transaction isolation levels.</p><p>He listened for about thirty seconds before interrupting me.</p><p>“That wasn’t my question,” he said, looking directly into the camera. “I’m asking what happens to the transaction after the statement is canceled.”</p><p>I tried again, this time discussing rollback behavior and connection management. Some of what I said was correct, but I was mixing database behavior with assumptions about how Spring handled exceptions. The interviewer asked whether I’d tested the scenario myself, and I realized I was about to spend another five minutes defending an answer I wasn’t confident about.</p><p>I told him I hadn’t tested that exact case.</p><p>He waited.</p><p>Then I said I didn’t know the precise behavior and would need to verify it before making a production decision.</p><p>He nodded, opened a shared document, and asked me to explain how I’d investigate it.</p><p>For the first time in seventy-six days, an interviewer seemed more interested in what I’d do when I didn’t know something than in whether I could produce an answer immediately.</p><h3>I Had Started the Search With More Confidence Than Preparation</h3><p>I’d left my previous backend engineering job after several years working with Java, Spring Boot, PostgreSQL, Redis, and asynchronous processing systems. I’d been involved in production incidents, database migrations, and architecture discussions that required making decisions with incomplete information. I considered myself a capable engineer, although I knew there were areas where my knowledge was less developed.</p><p>When I started applying for Senior Backend Engineer positions, I expected technical interviews to focus on the kind of work I’d been doing. I assumed companies would ask about production failures, database performance, and designing reliable services. Some did, but many interviews felt more like a test of how quickly I could recall details from documentation.</p><p>The first rejection came after a Java concurrency interview. The interviewer asked me to explain the difference between volatile and synchronized, and I gave a reasonable answer about visibility and mutual exclusion. Then he asked whether volatile made a compound operation atomic, and I hesitated before giving an incomplete explanation.</p><p>The feedback said my understanding of concurrency fundamentals needed improvement.</p><p>I spent the following weekend studying the Java Memory Model. I reviewed happens-before relationships, atomic operations, and the circumstances where synchronization was necessary. By Monday, I could explain the topic more clearly, although I was frustrated that one question had apparently outweighed years of production experience.</p><p>The second rejection came after a system design interview. I proposed a message broker for an event-processing platform, but the interviewer questioned whether the expected workload justified the operational complexity. I defended the design because I’d used similar architectures before, even though I hadn’t established the throughput requirements.</p><p>The recruiter said the team wanted someone who demonstrated stronger judgment when selecting technologies.</p><p>I added the feedback to my spreadsheet.</p><p>Then I started studying system design more aggressively.</p><h3>Every Rejection Added Another Topic to My Study Plan</h3><p>By the fourth interview, my preparation notes had become enormous. I had sections covering Java concurrency, PostgreSQL indexing, Redis eviction policies, Kafka consumer groups, distributed locks, transaction isolation, and Kubernetes networking. I could explain concepts I’d never implemented and discuss failure scenarios I’d only encountered in articles.</p><p>That seemed like progress.</p><p>The problem was that I was starting to confuse familiarity with understanding.</p><p>During the fourth interview, an Engineering Manager asked how I’d investigate a sudden increase in API latency. I described checking application metrics, database performance, and external dependencies. He asked what I’d do if the database metrics looked normal but request latency had doubled.</p><p>I said I’d examine thread pool utilization and garbage collection behavior.</p><p>He asked what I’d expect to see if garbage collection were responsible.</p><p>I explained that long pauses could delay request processing, but I couldn’t remember which JVM metrics would distinguish allocation pressure from other causes. Instead of acknowledging the gap, I continued discussing garbage collection algorithms.</p><p>The interviewer eventually moved on.</p><p>The rejection arrived two days later.</p><p>The fifth company asked me about Kafka exactly-once semantics. I’d read about the feature and understood that Kafka could coordinate certain producer and consumer operations, but I struggled to explain its limitations when a workflow involved an external database. I gave an answer that sounded confident while overlooking an important boundary.</p><p>The interviewer challenged me with a scenario involving a successful database commit followed by a consumer crash.</p><p>I explained that Kafka transactions could help prevent duplicate processing.</p><p>He asked how a Kafka transaction would roll back a PostgreSQL commit.</p><p>I stopped talking.</p><p>The question was fair, and I knew I’d made a mistake. I’d treated a feature name as a guarantee that applied to the entire business workflow, even though the database and Kafka weren’t participating in one atomic transaction.</p><p>I corrected myself, but the damage was done.</p><p>The recruiter later said the team had concerns about my depth of understanding.</p><p>That feedback bothered me more than the others because I knew exactly what had happened.</p><p>I’d answered too quickly because I wanted to sound knowledgeable.</p><h3>I Started Practicing Answers Instead of Solving Problems</h3><p>After the sixth rejection, I changed my preparation routine. I began recording myself answering common interview questions and listening for hesitation, unnecessary detail, and weak explanations. I wanted to sound more confident, so I practiced until the answers became smooth.</p><p>I prepared stories about production incidents, difficult technical decisions, and disagreements with managers. I rehearsed explanations of database locking, message delivery guarantees, and distributed system failures. I even practiced how I’d respond when an interviewer interrupted me.</p><p>The preparation made me more comfortable speaking.</p><p>It also made me less comfortable thinking.</p><p>During the seventh interview, a Staff Engineer asked how I’d design a service that processed customer payments asynchronously. I started explaining idempotency keys, durable state transitions, and retry behavior before he’d finished describing the requirements.</p><p>He asked whether I’d considered that some payments might need immediate confirmation.</p><p>I said the system could return an acknowledgment and complete the operation later.</p><p>He asked whether that behavior would satisfy the business requirement.</p><p>I realized I hadn’t asked.</p><p>We spent the next twenty minutes revising a design I’d introduced before understanding the problem.</p><p>The eighth rejection was similar. I was asked to investigate a hypothetical production incident, and I immediately started listing the metrics I’d check. The interviewer asked which metric I’d examine first and why, and I struggled because I’d prepared a comprehensive answer rather than a prioritized investigation.</p><p>The ninth company rejected me after a behavioral interview. The Engineering Manager asked about a time I’d made a technical mistake, and I described an incident where a configuration change had increased database load. I spent most of the answer explaining how we’d detected and corrected the problem.</p><p>He asked what I’d personally done wrong.</p><p>I started explaining the circumstances that had made the mistake possible.</p><p>He repeated the question.</p><p>I eventually admitted that I hadn’t validated the configuration under representative load before approving the change.</p><p>The manager thanked me and moved on.</p><p>The feedback said I needed to demonstrate stronger accountability.</p><p>I thought that was unfair until I listened to my recording of the answer.</p><p>I’d spent nearly four minutes describing the incident without clearly acknowledging my own mistake.</p><h3>The Tenth Rejection Made Me Question My Experience</h3><p>The tenth company was a financial technology business hiring a Senior Backend Engineer. The role involved Java services, PostgreSQL, and transaction processing, which matched my previous work closely. I passed the initial coding round and reached a technical interview with a Principal Engineer.</p><p>He asked about a production incident involving duplicate financial transactions. I described how we’d investigated repeated message delivery and added safeguards to prevent duplicate business effects. He asked how we’d handled operations where the external payment provider returned a timeout.</p><p>I explained that we’d used idempotency keys and checked the provider’s transaction status before retrying.</p><p>He asked what happened if the status endpoint was also unavailable.</p><p>I said we’d retry later.</p><p>He asked how we’d prevent the retry mechanism from repeatedly contacting an unavailable provider.</p><p>I started discussing exponential backoff.</p><p>He asked how we’d handle a transaction that remained unresolved for several hours.</p><p>I described a reconciliation process, but I hadn’t considered how the system should represent the uncertain outcome to customers during that period. The interviewer kept introducing realistic failure scenarios, and I kept trying to produce immediate answers.</p><p>By the end, I was exhausted.</p><p>The recruiter called four days later and said the team had decided not to proceed. The feedback was that my experience seemed relevant, but I needed to demonstrate more structured reasoning when dealing with unfamiliar failure scenarios.</p><p>I thanked her and ended the call.</p><p>Then I opened my spreadsheet.</p><p>Ten rejections in seventy-six days.</p><p>I had more technical notes than when I’d started, but I wasn’t sure I was becoming a better engineer.</p><h3>My Friend Asked Me to Explain Something I Didn’t Know</h3><p>That weekend, I met a former colleague named Daniel. We’d worked together on several backend services, and he knew how much time I’d been spending on interview preparation. I told him about the latest rejection and complained that companies seemed to expect candidates to know every possible failure scenario.</p><p>Daniel listened for a while.</p><p>Then he asked me a question about PostgreSQL behavior that I couldn’t answer immediately.</p><p>I started explaining what I thought would happen.</p><p>He interrupted me and asked whether I knew or was guessing.</p><p>I said I was making an educated guess.</p><p>He asked why I hadn’t said that at the beginning.</p><p>I told him interviewers didn’t usually reward uncertainty.</p><p>Daniel disagreed.</p><p>He said there was a difference between being uncertain and being careless. An engineer who admitted a knowledge gap and explained how to investigate it could be more useful than someone who gave a confident answer that turned out to be wrong.</p><p>I told him that sounded reasonable in theory, but technical interviews often rewarded speed.</p><p>He said some did.</p><p>Then he asked whether I’d want to work with an engineer who confidently approved a database change without understanding its consequences.</p><p>I said no.</p><p>He asked why I was trying to behave like that during interviews.</p><p>I didn’t have an answer.</p><p>We spent the next hour discussing how I’d approached the previous ten interviews. Daniel pointed out that I was treating every question as a test of whether I already knew the answer. When I encountered something unfamiliar, I tried to connect it to a topic I’d studied and produce an explanation quickly.</p><p>That approach worked when the connection was valid.</p><p>When it wasn’t, I sounded confident about something I didn’t understand.</p><p>Daniel suggested I practice a different kind of interview preparation. Instead of memorizing more answers, I should work through unfamiliar problems and explain how I’d investigate them.</p><p>I wasn’t convinced.</p><p>But I was tired enough to try.</p><h3>The Eleventh Company Asked a Question I Couldn’t Answer</h3><p>The next opportunity came from a recruiter at a software company building infrastructure for business customers. The position involved maintaining Java services, improving database performance, and investigating production incidents.</p><p>The first interview was with an Engineering Manager who asked about my previous projects. We discussed a service migration, a difficult database performance issue, and how I’d handled technical disagreements.</p><p>The conversation went well.</p><p>The second round was with a Staff Engineer named Michael. He explained that the interview would involve discussing production scenarios rather than writing code. He wanted to understand how I approached problems when the available information was incomplete.</p><p>He started with a PostgreSQL transaction that had been interrupted while waiting for a row lock.</p><p>He asked what would happen to the transaction after the statement was canceled.</p><p>I began explaining transaction isolation.</p><p>Michael stopped me.</p><p>He said that wasn’t the question.</p><p>I tried again, discussing rollback behavior and how Spring might handle exceptions. He asked whether I’d tested the scenario, and I realized I was relying on assumptions about several different layers of the system.</p><p>I told him I didn’t know the precise behavior.</p><p>He nodded.</p><p>Then he asked how I’d find out.</p><p>I explained that I’d first separate PostgreSQL behavior from application framework behavior. I’d reproduce the scenario using two database sessions, create a lock conflict, and trigger the relevant timeout or cancellation mechanism. I’d inspect the transaction state afterward and verify whether subsequent statements could execute before rollback.</p><p>Michael asked how I’d distinguish a PostgreSQL lock timeout from a client-side cancellation.</p><p>I said I’d examine the database error codes, server logs, and the behavior of the client connection. I’d also verify the relevant PostgreSQL documentation rather than relying on memory.</p><p>He asked how I’d test the behavior in a Spring Boot application.</p><p>I described writing an integration test against a real PostgreSQL instance, controlling the transaction boundaries, and checking how the framework handled the exception. I said I’d avoid assuming that behavior observed through JPA was identical to what happened in a raw database session.</p><p>Michael seemed satisfied.</p><p>We moved on to another scenario.</p><h3>The Next Question Was Worse</h3><p>Michael described a service that occasionally returned successful responses even though some downstream operations had failed. The application used asynchronous processing, and the team suspected that errors were being swallowed somewhere in the workflow.</p><p>He asked where I’d start.</p><p>I said I’d first clarify what the successful response was supposed to mean. If it only acknowledged that the request had been accepted, a downstream failure might be expected and should be represented through a separate operation status. If the response promised completed processing, then the system had a correctness problem.</p><p>Michael asked me to assume the response was intended to confirm completion.</p><p>I said I’d trace a single request through the relevant services and identify where the system decided the operation had succeeded. I’d examine logs, traces, and persisted state to determine whether the response was generated before all required operations completed.</p><p>He introduced another constraint.</p><p>The team didn’t have distributed tracing.</p><p>I said I’d use whatever correlation identifiers were available and inspect the relevant database records and message metadata. If correlation was insufficient, I’d add targeted instrumentation in a controlled environment to reproduce the failure.</p><p>He asked whether I’d immediately introduce a tracing platform.</p><p>I said no.</p><p>I’d want to understand the scope of the problem and the team’s existing observability before introducing another system. Better tracing might be valuable, but it wouldn’t automatically fix incorrect success semantics.</p><p>Michael nodded.</p><p>Then he asked how I’d handle a case where the operation’s final outcome couldn’t be determined.</p><p>I paused.</p><p>I told him I’d need to understand the business consequences before choosing a recovery strategy. For a financial operation, I wouldn’t blindly retry an uncertain outcome without a way to establish whether the original operation had completed.</p><p>He asked what I’d do if the external provider couldn’t confirm the result immediately.</p><p>I said I’d represent the operation as unresolved, preserve the information needed for reconciliation, and avoid telling the customer it had definitely failed or succeeded until the system had authoritative evidence.</p><p>We discussed the trade-offs for another fifteen minutes.</p><p>I didn’t know every answer.</p><p>But I was no longer trying to pretend I did.</p><h3>The Interview Ended Without a Perfect Solution</h3><p>Near the end, Michael asked whether I’d change anything about my investigation approach.</p><p>I said I’d probably prioritize establishing the system’s success semantics earlier because several later decisions depended on that definition. I’d also want to identify which failures could be safely retried and which required reconciliation.</p><p>He asked whether I thought the design was complete.</p><p>I said no.</p><p>We’d discussed several important failure scenarios, but I hadn’t addressed operational ownership, alerting, or how the system would recover after a prolonged outage. I explained which questions I’d investigate next and why they mattered.</p><p>Michael thanked me.</p><p>He said he’d enjoyed the discussion and appreciated that I’d been clear about which behaviors I understood and which required verification.</p><p>The interview ended after seventy minutes.</p><p>I closed my laptop and realized something unusual.</p><p>I wasn’t trying to remember every question I’d answered incorrectly.</p><p>I was thinking about the problems we’d discussed.</p><p>For the first time in weeks, a technical interview had felt like engineering work.</p><h3>The Feedback Was Different This Time</h3><p>The recruiter called two days later.</p><p>She said the technical team wanted to move forward.</p><p>I asked whether Michael had provided any feedback.</p><p>She said he’d been impressed by my structured reasoning and the way I’d handled uncertainty. He’d specifically mentioned that I hadn’t rushed into solutions when the requirements were incomplete.</p><p>I almost laughed.</p><p>For ten interviews, I’d been trying to eliminate uncertainty from my answers. I’d studied more topics, rehearsed explanations, and practiced speaking confidently because I thought that was what senior engineers were expected to do.</p><p>Now the first interviewer who’d explicitly praised my approach had done so because I was willing to acknowledge what I didn’t know.</p><p>The final interview was with the Engineering Director. He asked about my previous projects, how I handled production incidents, and what I’d do if a team needed to make a technical decision without enough information.</p><p>I explained that I’d identify the assumptions, evaluate the consequences of being wrong, and look for ways to reduce uncertainty before committing to an irreversible decision. I also said that sometimes teams had to proceed without complete information, but they should understand the risks they were accepting.</p><p>The director asked whether I’d ever made a decision that turned out badly.</p><p>I described the configuration change that had increased database load.</p><p>This time, I started by acknowledging my mistake.</p><p>I’d approved the change without validating it under representative traffic. The team had recovered quickly, but the incident had exposed a weakness in our deployment process. We added load testing for similar changes and improved the monitoring used during rollouts.</p><p>The director asked what I’d learned.</p><p>I said I’d become more careful about distinguishing assumptions from verified behavior, especially when a change could affect production reliability.</p><p>We discussed the incident for another ten minutes.</p><p>The interview ended with a conversation about the team’s current challenges.</p><h3>I Received an Offer Three Days Later</h3><p>The recruiter called on Friday afternoon and said the company wanted to hire me. The salary was within the range we’d discussed, and the team hoped I could start the following month.</p><p>I accepted.</p><p>After the call, I opened the spreadsheet I’d been maintaining since the beginning of the search. It contained ten rejections, dozens of technical questions, and notes about the mistakes I’d made during interviews.</p><p>I added the new offer.</p><p>Then I looked through the earlier entries.</p><p>Several rejections had been justified. I’d misunderstood requirements, overlooked failure scenarios, and struggled to explain technical decisions clearly. Some companies had preferred candidates with different experience, and others had provided feedback that was too vague to be useful.</p><p>I couldn’t know whether admitting uncertainty would have changed those outcomes.</p><p>But I could see how my preparation had gradually pushed me toward a behavior I didn’t respect in other engineers.</p><p>I’d been trying to sound certain about things I hadn’t verified.</p><p>That wasn’t how I approached production incidents.</p><p>When a service failed, I didn’t assume I knew the cause because I’d seen a similar problem before. I checked metrics, examined evidence, tested hypotheses, and changed my understanding when new information appeared.</p><p>During interviews, I’d been doing almost the opposite.</p><p>I heard a familiar technical term and rushed to produce an answer.</p><h3>I Still Prepare for Questions I Can’t Answer</h3><p>I haven’t stopped studying for technical interviews. Java concurrency, PostgreSQL transaction behavior, distributed systems, and production reliability still matter. A senior engineer needs a strong technical foundation, and uncertainty isn’t an excuse for avoiding difficult topics.</p><p>But I prepare differently now.</p><p>When I encounter a question I can’t answer, I try to identify exactly what I don’t understand. I separate facts from assumptions and think about how I’d verify the behavior in a real system.</p><p>Sometimes that means writing a small test. Other times it means reading documentation, examining source code, or discussing the problem with someone who has more experience.</p><p>I also practice explaining uncertainty clearly.</p><p>There’s a difference between saying I have no idea and saying I understand the general behavior but need to verify a particular edge case. The second answer gives an interviewer something useful to evaluate, especially when the role involves making decisions about production systems.</p><p>I still remember Michael asking what happened to a PostgreSQL transaction after a canceled statement.</p><p>After the interview, I reproduced several cancellation and timeout scenarios using real database sessions. I examined the error states, tested the behavior through Spring, and wrote down the differences I’d previously been mixing together.</p><p>The exercise took less than an afternoon.</p><p>I learned more from it than I had from several evenings of memorizing interview answers.</p><p>I still have the notes.</p><p>They’re in the same folder as the spreadsheet from those seventy-six days, alongside the questions I answered badly and the feedback I received from companies that rejected me.</p><p>I don’t look at the rejection count very often anymore.</p><p>But I occasionally open the PostgreSQL test when I’m preparing for a difficult technical discussion. It reminds me that the most dangerous answer in engineering is often the one that sounds convincing before anyone has checked whether it’s true.</p><p>I wish I’d understood that before the tenth rejection.</p><p>I might have spent less time trying to sound like a senior engineer and more time demonstrating how I actually worked.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for Java and backend engineering interviews, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers concurrency, transaction management, PostgreSQL, and production debugging. For architecture interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, reliability, and explaining engineering trade-offs under pressure.</p><p>I also write about production engineering, system design interviews, and software engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in practicing realistic architecture scenarios, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ab743d5f1ad" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-got-rejected-from-10-software-engineer-jobs-then-i-stopped-saying-i-knew-everything-3ab743d5f1ad">I Got Rejected From 10 Software Engineer Jobs. Then I Stopped Saying I Knew Everything</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Failed 11 Software Engineer Interviews. The Twelfth Asked Me to Delete My Code]]></title>
            <link>https://medium.com/engineering-playbook/i-failed-11-software-engineer-interviews-the-twelfth-asked-me-to-delete-my-code-f31bce6f1e4c?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/f31bce6f1e4c</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:09:45 GMT</pubDate>
            <atom:updated>2026-11-11T18:10:02.129Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vjsayTDxsmmavXhU0JdZzw.png" /></figure><h4><em>After 81 days of rejections, I finally reached a coding interview where everything worked. Then the interviewer told me to throw away my solution and start again with 23 minutes left.</em></h4><p>The interviewer watched me delete forty-seven lines of working Java code. I’d spent the previous half hour implementing a solution that passed every test he’d provided, and I was beginning to think the interview might actually go well. Then he changed one requirement, asked me to remove the implementation, and told me I had twenty-three minutes to solve the problem again.</p><p>I looked at the clock in the corner of my screen. There were other ways to adapt the code, and deleting it seemed unnecessary, but I didn’t want to spend another interview arguing about the instructions. I’d already been rejected eleven times in eighty-one days, and I was becoming painfully familiar with the sound of a recruiter explaining that the team had decided to move forward with someone else.</p><p>I asked whether I could keep the original implementation in a separate file for reference. He said he’d prefer a clean solution and wanted to see how I’d approach the problem with the new constraint. I deleted the code, opened a blank class, and tried to remember the last time anyone had asked me to discard working software because a requirement had changed.</p><p>It was an ordinary Wednesday afternoon. I had $2,840 left in my savings account, three unanswered recruiter emails, and a Java interview that was beginning to feel like an expensive practical joke.</p><h3>The First Four Rejections Had Made Sense</h3><p>My job search started after I left a backend engineering position where I’d spent several years working with Java, Spring Boot, PostgreSQL, and internal services that processed financial transactions. I was comfortable investigating production incidents and maintaining systems with complicated business rules, but I’d never been particularly good at solving algorithmic problems while someone watched my screen.</p><p>The first company asked me to implement an LRU cache without using an existing library. I understood the data structures, but I made a mistake updating the linked list when an existing key was accessed. The tests caught it, and I spent the remaining time debugging pointer changes that should have been straightforward.</p><p>The second rejection came after a system design interview. I was asked to design a job scheduling platform, and I proposed a distributed architecture before clarifying whether the company actually needed to execute jobs across multiple regions. The interviewer spent most of the session pulling me back toward the requirements, which was embarrassing because I’d criticized exactly that kind of overengineering during architecture reviews at my previous company.</p><p>The third company wanted someone with more experience building infrastructure on AWS. I’d deployed applications to cloud environments, but I hadn’t personally designed every part of the networking and security configuration. The hiring manager was direct about the gap, and I appreciated that he didn’t pretend the decision was about cultural fit.</p><p>The fourth interview was the one that bothered me. The interviewer asked me to implement a bounded queue, and I wrote a solution using a lock and condition variables. It passed the tests, but I struggled to explain how interruption should be handled when a producer was waiting for capacity.</p><p>The feedback said my concurrency knowledge wasn’t strong enough for a senior role.</p><p>I’d spent years debugging concurrent services in production. I knew how to identify transaction conflicts, investigate thread pool exhaustion, and recognize when an asynchronous workflow could process the same operation twice. But I hadn’t been able to explain one detail of Java interruption semantics clearly enough during a forty-five-minute exercise.</p><p>I spent the following weekend reviewing ReentrantLock, Condition, BlockingQueue, and the difference between interruption and cancellation. By Sunday evening, I understood the topic considerably better, although I was also starting to resent how much of my job search involved studying things I&#39;d rarely needed to implement from scratch.</p><h3>By Interview Seven, I Had Started Hiding My Experience</h3><p>The next few interviews were strange because I was technically improving while becoming less confident about describing my previous work. I could answer more questions about Java collections and concurrency, but I was increasingly worried about saying something that an interviewer might interpret as insufficiently senior.</p><p>During the fifth interview, I described a production incident involving a PostgreSQL database that had become overloaded after a deployment. The interviewer asked how we’d identified the problem, and I explained the query metrics, connection pool behavior, and application traces we’d examined.</p><p>He asked whether I’d personally written the fix.</p><p>I said another engineer had implemented part of the database change while I’d handled the application-side investigation and rollout verification. He asked whether I’d been the technical lead, and I explained that responsibility had been shared between several engineers.</p><p>The rejection arrived three days later. The feedback said I needed to demonstrate stronger ownership of complex projects.</p><p>For the sixth interview, I tried to emphasize my individual contributions more clearly. I described the decisions I’d made, the risks I’d identified, and the changes I’d implemented. The interviewer asked how I’d collaborated with the team, and I realized I’d spent so much time proving ownership that I’d barely mentioned the other engineers.</p><p>The company rejected me after the behavioral round.</p><p>By the seventh interview, I’d started preparing different versions of the same stories. One emphasized technical depth, another focused on leadership, and a third highlighted collaboration. I wasn’t inventing achievements, but I was choosing which parts of my experience to discuss based on what I thought the interviewer wanted to hear.</p><p>That made every conversation exhausting.</p><p>I remember finishing one interview and realizing I’d spent almost an hour talking about work I genuinely enjoyed without sounding particularly interested in any of it. I’d become so focused on avoiding rejection that I was speaking like someone presenting evidence in a legal dispute.</p><h3>The Eighth Rejection Was the First One I Didn’t Understand</h3><p>The eighth company was a mid-sized SaaS business hiring a Senior Backend Engineer to improve its data processing platform. The role involved Java services, PostgreSQL, and event-driven workflows, all of which matched my background.</p><p>The technical interview went well. I explained how I’d investigate delayed message processing, discussed the consequences of retrying operations after timeouts, and answered questions about transaction boundaries. The interviewer asked thoughtful follow-up questions, and the conversation felt like a discussion between engineers.</p><p>Two days later, the recruiter said the technical feedback was positive and scheduled a final conversation with the Engineering Manager.</p><p>We discussed team structure, code reviews, and how the company handled production incidents. I asked about the deployment process and whether engineers were expected to participate in on-call rotations. The manager gave detailed answers, and I left the interview believing I had a reasonable chance of receiving an offer.</p><p>The rejection arrived the following Monday.</p><p>The recruiter said the company had chosen someone whose experience was more closely aligned with its immediate needs. I asked whether there was a specific area where I could improve, but she said the team hadn’t provided additional feedback.</p><p>I added the rejection to my spreadsheet and stared at the screen.</p><p>The first few rejections had given me something concrete to work on. This one offered nothing beyond the knowledge that another person had been preferred.</p><p>I was beginning to understand why job searches could make experienced engineers question their abilities even when they were performing reasonably well.</p><h3>Interview Eleven Lasted Seventeen Minutes</h3><p>The eleventh interview was with a company that advertised a Senior Java Engineer position. The recruiter had described the role as primarily backend development, with responsibility for maintaining services and improving performance.</p><p>The interviewer joined the call seven minutes late and immediately asked whether I’d worked with Java 21. I said yes, although most of my recent production work had used Java 17. He asked me to explain virtual threads, and I described their purpose, how they differed from traditional platform threads, and the situations where they could improve the scalability of blocking workloads.</p><p>He asked whether virtual threads made synchronized code faster.</p><p>I explained that they didn’t automatically improve CPU-bound work and that pinning could affect scalability in certain situations. I also mentioned that the relevant behavior depended on the JDK version and the code being executed.</p><p>He interrupted me and asked for a simpler answer.</p><p>I tried again.</p><p>He then asked whether I’d used virtual threads in production. I said I hadn’t deployed a production system built around them, although I’d experimented with them and understood the trade-offs.</p><p>He said the company needed someone with practical Java 21 experience.</p><p>I reminded him that the job description listed Java 17 or newer and that the recruiter had confirmed my background was appropriate. He said the team had recently changed its requirements.</p><p>The interview ended after seventeen minutes.</p><p>I closed my laptop and went for a walk because I couldn’t think of anything useful to do with the rest of the afternoon.</p><p>For the first time, I seriously considered applying for positions below the senior level. I wasn’t convinced that would solve anything, but I was tired of spending weeks preparing for interviews that sometimes seemed unrelated to the work companies actually needed done.</p><h3>The Twelfth Company Didn’t Ask Me to Explain My Résumé</h3><p>The twelfth opportunity came through a recruiter named Hannah. She contacted me about a Senior Backend Engineer position at a company building software for logistics businesses. The engineering team maintained Java services responsible for processing shipments, calculating prices, and coordinating updates between external systems.</p><p>The job description wasn’t particularly exciting. It mentioned Spring Boot, PostgreSQL, REST APIs, and experience with distributed systems. There were no promises about revolutionizing an industry or building the next generation of artificial intelligence.</p><p>That was refreshing.</p><p>During our first conversation, Hannah asked about my previous projects and the kinds of problems I enjoyed solving. I told her I liked investigating difficult production behavior, improving unreliable systems, and designing services that other engineers could maintain without needing to understand every historical accident behind the architecture.</p><p>She laughed and said the team had plenty of historical accidents.</p><p>The first technical interview was with a Staff Engineer named Thomas. He asked about database transactions, message processing, and how I’d approach a service that occasionally produced duplicate customer notifications.</p><p>We discussed the difference between duplicate delivery and duplicate business effects. I explained how I’d investigate whether messages were being redelivered, whether consumers were retrying operations, and whether the database enforced the necessary uniqueness constraints.</p><p>Thomas asked how I’d verify the fix.</p><p>I described the tests I’d write and the production metrics I’d monitor. He seemed satisfied, and we spent the remaining time discussing the company’s existing architecture.</p><p>The recruiter called the next morning to schedule a coding interview.</p><p>I opened my preparation notes and tried not to get excited.</p><h3>The Coding Exercise Looked Almost Too Simple</h3><p>The interviewer was another Senior Engineer named Alex. He explained that the exercise involved processing a stream of events representing changes to customer orders. Each event contained an order identifier, a sequence number, and a new status.</p><p>The initial requirement was to maintain the latest status for each order. Events could arrive out of order, and the implementation needed to ignore updates with sequence numbers older than the most recently processed event.</p><p>I asked whether two events could have the same sequence number.</p><p>Alex said they could, but duplicate events would contain the same status.</p><p>I asked whether the input needed to be processed concurrently.</p><p>He said the initial version could assume a single thread.</p><p>I implemented the solution using a map that stored the latest sequence number and status for each order. The code was straightforward, and the tests passed. I added a test for out-of-order events and another for duplicate delivery.</p><p>Alex asked me to explain the time complexity.</p><p>I said each event required an expected constant-time map lookup and update, so processing (n) events would take expected (O(n)) time. Memory usage would grow with the number of distinct order identifiers retained.</p><p>He nodded.</p><p>Then he changed the requirement.</p><p>The system now needed to support a query that returned the status of an order at any historical sequence number.</p><p>I started explaining how I’d extend the data structure to retain history rather than only the latest state. I suggested storing an ordered collection of updates for each order and using binary search to locate the relevant version.</p><p>Alex asked whether I’d be comfortable rewriting the implementation around that requirement.</p><p>I said yes.</p><p>Then he asked me to delete the original code.</p><p>I looked at the clock.</p><p>Twenty-three minutes remained.</p><h3>I Deleted the Code and Immediately Regretted It</h3><p>My first instinct was to create a map from order identifiers to lists of events. If the events arrived in sequence order, I could append each update and use binary search for historical queries. But the original requirement allowed out-of-order delivery, which meant I couldn’t assume the list would remain sorted.</p><p>I considered using a TreeMap for each order, with sequence numbers as keys. That would make insertion and historical lookup logarithmic in the number of stored versions for that order. It also meant I needed to define exactly what a historical query should return when no event existed at the requested sequence number.</p><p>I asked Alex whether the query should return the latest known status at or before the requested sequence number.</p><p>He said yes.</p><p>I asked whether sequence numbers were unique per order or globally.</p><p>He said they were per order.</p><p>I started implementing the new version.</p><p>After about ten minutes, I had the core structure working. Each order mapped to a navigable map of sequence numbers and statuses. Incoming events were inserted into the appropriate history, and historical queries used floorEntry to find the latest event at or before the requested sequence number.</p><p>Alex asked what would happen if the same sequence number arrived twice with different statuses.</p><p>I reminded him that the original requirement said duplicate events would contain the same status.</p><p>He smiled and said the new version should detect conflicting duplicates rather than silently overwrite them.</p><p>I added a check.</p><p>Then I made a mistake.</p><p>While refactoring the code, I changed the method responsible for retrieving the current status. Instead of using lastEntry, I accidentally used the same lookup method as the historical query and passed an incorrect sequence number.</p><p>One of the tests failed.</p><p>I had six minutes left.</p><p>I started debugging, found the mistake, and corrected it. The tests passed again, but I hadn’t added every edge case I wanted.</p><p>Alex asked whether I was satisfied with the implementation.</p><p>I said the core behavior worked, but I’d want to add tests for empty histories, conflicting duplicate events, and large sequence numbers before considering it complete.</p><p>He asked whether I’d change anything about the data structure.</p><p>I said it was reasonable for the stated requirements, although retaining every event indefinitely would create a storage problem in a long-running service. If the history needed to be durable or the number of events became large, I’d reconsider whether an in-memory structure was appropriate.</p><p>He nodded and ended the exercise.</p><p>I closed the editor feeling exhausted.</p><h3>The Interviewer Asked Why I Hadn’t Refused</h3><p>Before ending the call, Alex asked me something unexpected.</p><p>He wanted to know why I’d agreed to delete the original implementation when I could have adapted it.</p><p>I told him he’d explicitly asked for a rewrite, and I’d assumed he wanted to evaluate how I approached the new requirement.</p><p>He said that was partly true, but he hadn’t required me to discard the working code. He’d asked whether I’d be comfortable rewriting it, and I’d agreed without discussing the cost.</p><p>I thought back to the conversation.</p><p>He was right.</p><p>I’d been so focused on following the interviewer’s instructions that I hadn’t explained why deleting the implementation might be unnecessary. In a real project, I would have preserved the working version, added tests for the new behavior, and refactored incrementally.</p><p>Alex asked what I’d do differently if the same situation occurred during a production change.</p><p>I told him I’d first identify which parts of the existing implementation could be reused. I’d write tests for the historical query requirement, change the data model, and keep the previous behavior working throughout the refactor.</p><p>He asked why I hadn’t done that during the interview.</p><p>I hesitated.</p><p>Then I told him the truth.</p><p>I’d failed eleven interviews in less than three months, and I’d become reluctant to challenge anything an interviewer asked me to do. I was worried that questioning the instruction would make me look difficult or unwilling to adapt.</p><p>Alex listened.</p><p>He said he’d seen candidates become overly cautious during interviews, especially when they’d been searching for work for a long time. He also said that experienced engineers were expected to question expensive changes when a safer approach was available.</p><p>We talked for another few minutes about how technical interviews differed from normal engineering work.</p><p>Then the call ended.</p><h3>I Thought I’d Failed Again</h3><p>I spent the evening replaying the exercise. The code had worked, but I’d made an avoidable mistake and hadn’t finished all the tests. I’d also admitted that I’d been rejected eleven times, which I immediately regretted because I worried it made me sound desperate.</p><p>I opened my spreadsheet and added notes about the exercise.</p><p>The most important observation wasn’t about TreeMap or binary search. It was that I&#39;d agreed to discard working code without asking whether the rewrite was necessary.</p><p>At my previous job, I’d pushed back against changes that introduced unnecessary risk. I’d argued for smaller deployments, better tests, and incremental migrations. Yet during the interview, I’d abandoned those habits because I was afraid of disappointing someone who controlled the hiring decision.</p><p>That realization bothered me more than the failed test.</p><p>I’d spent eighty-one days preparing to demonstrate my engineering skills, and the interview process had gradually changed how I behaved. I was becoming more willing to follow instructions I didn’t fully agree with, even when my professional experience suggested a better approach.</p><p>I didn’t know whether Alex had intended to test that.</p><p>But I knew I hadn’t handled the situation the way I would have at work.</p><h3>The Recruiter Called Two Days Later</h3><p>Hannah said the engineering team wanted to move forward.</p><p>I asked whether Alex had provided feedback.</p><p>She said he’d been impressed by my technical reasoning and appreciated that I’d recovered from the implementation mistake without becoming defensive. He’d also mentioned our discussion about rewriting working code.</p><p>I asked whether that had been a concern.</p><p>She said he’d viewed it as a useful conversation about how I approached technical decisions under pressure. The team wanted to schedule a final interview with the Engineering Manager.</p><p>I was relieved, although I tried not to assume the process would end with an offer.</p><p>The final interview took place the following week. The manager asked about production incidents, technical disagreements, and how I handled changing requirements. I described a project where a business team had requested a major change shortly before release, and we’d negotiated a smaller implementation that met the immediate need without destabilizing the system.</p><p>He asked how I’d persuaded the team.</p><p>I explained the technical risks, the alternatives we’d considered, and how we’d divided the work into smaller changes. I also acknowledged that the original request hadn’t been unreasonable; the problem was the amount of risk involved in delivering it under the proposed deadline.</p><p>The manager seemed interested in the details.</p><p>We spent the remaining time discussing the team’s architecture and the challenges they expected the new engineer to handle.</p><p>Three days later, Hannah called with an offer.</p><p>I accepted.</p><h3>The Twelfth Interview Didn’t Teach Me a New Algorithm</h3><p>I don’t think deleting the code was a particularly good way to evaluate an engineer. The exercise could have tested the same design skills without requiring a candidate to discard a working implementation under time pressure. I also don’t know whether Alex would have evaluated me differently if I’d refused the rewrite.</p><p>What made the interview memorable was how quickly I’d abandoned my normal engineering judgment.</p><p>During those eighty-one days, I’d become increasingly focused on passing interviews rather than demonstrating how I actually worked. I memorized answers, practiced coding exercises, and tried to anticipate what each interviewer wanted to hear.</p><p>Some of that preparation was necessary. I’d made genuine technical mistakes during earlier interviews, and studying helped me correct them. I became better at explaining concurrency, database behavior, and system design trade-offs.</p><p>But I’d also become less comfortable saying that a requirement was unclear or that a proposed approach might be unnecessarily risky.</p><p>In production, those questions matter.</p><p>A senior engineer who silently accepts every instruction can create problems just as easily as someone who argues about every decision. The difficult part is knowing when to challenge an assumption and how to do it without turning the conversation into a contest.</p><p>I still have the coding exercise from that interview.</p><p>A few weeks after starting the new job, I recreated the problem on my own laptop. I implemented the original version, added the historical query requirement, and refactored the code incrementally while keeping the tests passing.</p><p>It took less time than the interview rewrite.</p><p>That didn’t prove I should have refused Alex’s instruction. It simply confirmed that I’d had a reasonable alternative and hadn’t taken the time to discuss it.</p><p>I kept both implementations.</p><p>The first reminds me of what I wrote when I was trying to pass an interview. The second reminds me of how I would have approached the same problem if nobody had been watching the clock.</p><p>I still practice coding problems before interviews, and I still make mistakes when someone asks me to explain an unfamiliar requirement under pressure. That hasn’t changed.</p><p>But when an interviewer asks me to throw away working code, I now ask what problem we’re trying to solve before I reach for the delete key.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for Java and backend engineering interviews, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers concurrency, transaction management, PostgreSQL, and production debugging. For architecture interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, reliability, and explaining engineering trade-offs under pressure.</p><p>I also write about production engineering, system design interviews, and software engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in practicing realistic architecture scenarios, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f31bce6f1e4c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-failed-11-software-engineer-interviews-the-twelfth-asked-me-to-delete-my-code-f31bce6f1e4c">I Failed 11 Software Engineer Interviews. The Twelfth Asked Me to Delete My Code</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Got Rejected From 7 Software Engineer Interviews. One Interviewer Finally Showed Me Why]]></title>
            <link>https://medium.com/engineering-playbook/i-got-rejected-from-7-software-engineer-interviews-one-interviewer-finally-showed-me-why-b36c70a2a7a3?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/b36c70a2a7a3</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:07:52 GMT</pubDate>
            <atom:updated>2026-11-11T18:08:10.694Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hf7YIYqnFM4XRkAkiYAtlA.png" /></figure><h4><em>I spent 58 days studying Java, system design, and distributed systems. The problem wasn’t that I couldn’t answer the questions. It was what happened when someone challenged my answers.</em></h4><p>The interviewer closed my code editor with twenty minutes left in the session. I thought we’d finished early because my solution had passed the tests, but he hadn’t even looked at the final implementation. He leaned toward the camera, opened his notebook, and asked me whether I knew why the interview had become difficult.</p><p>I was confused. We’d spent forty minutes implementing an in-memory cache with expiration, and I’d answered every question he asked about concurrency and memory usage. There had been a disagreement about one design decision, but I’d explained my reasoning and believed the conversation was going reasonably well.</p><p>He told me my solution was technically defensible. Then he said he’d stopped evaluating the code fifteen minutes earlier because he wanted to see how I responded when someone disagreed with me.</p><p>I remember staring at the screen, trying to understand whether that was supposed to be feedback or another interview question. I’d spent almost two months wondering why companies kept rejecting me after technically strong interviews. Now someone was telling me that the most important part of the assessment had happened while I thought we were discussing a cache.</p><h3>Seven Interviews in 58 Days</h3><p>I’d started looking for a Senior Backend Engineer position after leaving a company where I’d worked on Java services, database-heavy applications, and production systems that occasionally behaved like they’d been designed by people who disliked sleep. I had several years of experience, and I was comfortable discussing the kind of problems that rarely appear in coding tutorials. I’d investigated connection pool exhaustion, fixed transaction boundaries, and spent enough time reading PostgreSQL execution plans to recognize when an innocent-looking query was about to ruin someone’s afternoon.</p><p>The first company rejected me after a coding interview. I wrote a working solution, but I ran out of time before handling an important edge case. The interviewer pointed it out, and I tried to explain how I’d fix it rather than implementing the correction. The feedback said my solution lacked completeness, which seemed reasonable even though I thought the core approach had been sound.</p><p>The second rejection came after a system design interview. I was asked to design an event-processing service, and I proposed Kafka before clarifying the expected throughput or operational constraints. The interviewer questioned whether the system needed Kafka at all, and I spent several minutes defending the choice. Looking back, I’d been more interested in explaining the technology than understanding the problem.</p><p>The third company rejected me after a behavioral round. The Engineering Manager asked about a technical disagreement, and I described a situation where I’d argued against a database migration because I believed it introduced unnecessary risk. I explained the technical details carefully, including the locking behavior and the potential impact on production traffic.</p><p>The manager asked how the disagreement had been resolved.</p><p>I said we’d eventually followed my recommendation.</p><p>He asked what I’d learned from the experience, and I told him it had reinforced the importance of understanding database behavior before approving production changes. He thanked me and moved on to another question.</p><p>The rejection arrived four days later. The recruiter said the team had concerns about collaboration and wanted someone who demonstrated stronger cross-functional communication.</p><p>I thought the feedback was unfair.</p><p>I’d prevented a risky deployment, and the company seemed more interested in how politely I’d disagreed than whether my concerns had been correct. I complained about it to a friend, who asked whether I’d explained what the other people involved had been trying to achieve.</p><p>I said their deadline had been unrealistic.</p><p>He suggested that wasn’t quite the same thing.</p><h3>I Started Preparing for Interviews Like They Were Exams</h3><p>After the fourth rejection, I changed my preparation routine. Every morning, I solved a coding problem before checking email. In the afternoon, I reviewed system design topics, and in the evening, I practiced explaining production incidents from my previous jobs.</p><p>I created documents covering Java concurrency, JVM memory management, database isolation levels, Redis caching strategies, and message delivery guarantees. I could explain the difference between at-least-once and at-most-once delivery without opening a browser. I could also describe several approaches to distributed locking, although I occasionally wondered whether I’d ever encounter a real system that needed half the complexity interviewers seemed to enjoy discussing.</p><p>The preparation helped me answer technical questions more confidently. During the fifth interview, I explained how I’d investigate a slow Spring Boot API and walked through the metrics I’d examine before changing configuration. The interviewer challenged my assumptions about database connection pooling, and I explained why increasing the pool size could make an overloaded database perform worse.</p><p>He asked whether there were circumstances where increasing the pool size would help.</p><p>I said there were, but only if the database had capacity and the application was unnecessarily restricting concurrency. He asked how I’d establish that, and I described the measurements I’d collect.</p><p>The conversation continued for another fifteen minutes. I thought it had gone well because I’d defended my reasoning with technical evidence.</p><p>The company rejected me after the next round.</p><p>The sixth interview involved a coding exercise with concurrent requests. I implemented the solution using synchronization and explained why the shared state needed protection. The interviewer asked whether I’d considered a different approach using immutable data structures.</p><p>I said the suggested approach would introduce unnecessary complexity for the requirements. He asked me to compare the two implementations anyway, and I spent several minutes explaining why mine was simpler.</p><p>The recruiter later told me the team had concerns about how I approached alternative solutions.</p><p>I was annoyed.</p><p>I thought interviewers wanted engineers who could make decisions and explain their reasoning. Apparently, some of them also wanted candidates who were willing to reconsider those decisions every time someone suggested something else.</p><p>By the seventh interview, I’d started expecting technical discussions to become arguments.</p><p>I didn’t notice that expectation changing the way I behaved.</p><h3>The Seventh Interview Started With a Cache</h3><p>The company built infrastructure software for business customers. Its backend services were written primarily in Java, and the engineering team maintained systems that handled substantial request volumes. The recruiter said the role required strong problem-solving skills and the ability to work independently on complex technical problems.</p><p>The first interview was with a Staff Engineer named Michael. He was friendly, spoke slowly, and seemed more interested in how I approached problems than how quickly I could produce code. We spent twenty minutes discussing my previous experience before moving into a live coding exercise.</p><p>He asked me to implement an in-memory cache with expiration.</p><p>The initial requirements were straightforward. The cache needed to support get, put, and removal operations, and entries should expire after a configurable duration. He said I could use standard Java libraries and should explain my decisions as I worked.</p><p>I started with a ConcurrentHashMap and stored each value alongside an expiration timestamp. On reads, the implementation checked whether the entry had expired and removed it if necessary. I explained that expired entries could remain in memory until accessed unless we introduced a cleanup mechanism.</p><p>Michael asked whether I considered that acceptable.</p><p>I said it depended on the workload and memory constraints. For a small cache with bounded usage, lazy expiration might be sufficient. For a long-running service with many keys that were rarely read again, we’d need an eviction strategy to avoid retaining expired entries indefinitely.</p><p>He nodded.</p><p>Then he asked what would happen if two threads attempted to update the same key simultaneously.</p><p>I explained that ConcurrentHashMap provided thread-safe map operations, but that wouldn&#39;t automatically make a sequence of operations atomic. If the cache needed conditional updates or compound state transitions, we&#39;d need to define those semantics explicitly.</p><p>He asked me to add a computeIfAbsent operation that avoided duplicate loading when multiple threads requested the same missing key.</p><p>I modified the implementation and discussed how the loader should behave if it threw an exception. We also talked about whether the expiration timestamp should be calculated before or after the value was loaded.</p><p>Everything felt normal until Michael asked whether I’d considered using an existing caching library instead of building the implementation ourselves.</p><p>I said that in production, I’d probably use Caffeine unless there was a specific reason to implement a cache from scratch.</p><p>He asked why.</p><p>I explained that production caching involved more than thread-safe storage. We’d need to consider eviction policies, expiration semantics, memory usage, statistics, and behavior under concurrent access. A mature library would already handle many of those concerns.</p><p>Michael said he agreed, but he wanted to explore a scenario where the team had decided to maintain a small custom cache.</p><p>I told him that decision would need a strong justification.</p><p>He smiled and asked me to assume the decision had already been made.</p><p>I said I’d still question it.</p><p>That’s when the conversation changed.</p><h3>I Thought We Were Debating Architecture</h3><p>Michael asked what I’d do if the team had good reasons for keeping the implementation simple. Perhaps the cache was used in only one service, held a small number of entries, and didn’t need advanced eviction policies. Maybe introducing another dependency would create more maintenance work than the cache itself.</p><p>I explained that those constraints made sense, but I’d still prefer an established library because concurrency bugs were difficult to detect. I mentioned that even a small cache could develop subtle problems around expiration and loading behavior.</p><p>He asked whether I could imagine a situation where the custom implementation was the better choice.</p><p>I said it was possible, but unlikely.</p><p>He asked me to describe one.</p><p>I repeated that a small cache with limited requirements might be manageable, although I wouldn’t recommend it without understanding the operational risks.</p><p>Michael stopped typing.</p><p>He looked at me for a moment and asked whether I thought he’d suggested something unreasonable.</p><p>I told him I didn’t think the idea was unreasonable, but I believed it introduced unnecessary risk.</p><p>He asked why I kept returning to that conclusion when he’d already narrowed the requirements.</p><p>I started explaining concurrency again.</p><p>He interrupted me.</p><p>He said he understood the technical concerns and wasn’t asking me to abandon them. He wanted to know whether I could evaluate a decision within the constraints he’d provided, even if it wasn’t the choice I’d make independently.</p><p>I felt myself becoming irritated.</p><p>I’d spent weeks being rejected after technical interviews, and now I was being challenged for refusing to endorse an implementation I didn’t believe was appropriate. I thought the whole point of hiring a senior engineer was to bring judgment to technical decisions.</p><p>I told him that senior engineers shouldn’t agree with an approach simply because someone more experienced suggested it.</p><p>Michael said he agreed.</p><p>Then he asked whether I thought agreeing and understanding were the same thing.</p><p>I didn’t answer immediately.</p><p>He closed the code editor.</p><p>We still had twenty minutes left.</p><h3>The Feedback I Hadn’t Expected</h3><p>Michael told me the implementation was mostly correct and that my technical reasoning had been sound. He wasn’t concerned about my understanding of concurrency or expiration. What concerned him was that I’d treated every alternative he introduced as something I needed to defeat.</p><p>I told him I’d been trying to explain the risks.</p><p>He said he’d understood the risks after my first explanation. He’d continued changing the constraints because he wanted to see whether I’d adapt my recommendation when the problem changed.</p><p>Instead, I’d kept defending the original conclusion.</p><p>He asked whether I’d noticed that he’d agreed with several of my points.</p><p>I thought about the conversation and realized he had. He’d acknowledged the risks of custom caching, agreed that mature libraries were useful, and accepted that concurrency required careful handling. But each time he introduced a narrower scenario, I’d returned to the same argument.</p><p>Michael said that senior engineers often worked with incomplete information and competing priorities. A good technical decision wasn’t always the most sophisticated or theoretically safest option. Sometimes the team needed a small, understandable solution that met the actual requirements without creating unnecessary maintenance work.</p><p>I agreed with that.</p><p>He asked why I hadn’t approached the exercise that way.</p><p>I didn’t have an immediate answer.</p><p>After a moment, I told him I’d been rejected from several interviews recently and had become overly focused on proving that my decisions were technically correct. I said I hadn’t realized how defensive I’d sounded until he explained what he’d been evaluating.</p><p>Michael listened without interrupting.</p><p>He told me that technical confidence was valuable, but it became difficult to work with when every discussion turned into a contest. He said the engineers he trusted most were comfortable changing their minds when new information appeared.</p><p>We spent the remaining time discussing how I’d approach the cache differently.</p><p>I explained that I’d begin by clarifying the expected number of entries, expiration behavior, memory limits, and operational requirements. If the cache was small, isolated, and unlikely to grow, a custom implementation might be reasonable. I’d still document the concurrency assumptions and add tests for expiration and duplicate loading.</p><p>Michael nodded.</p><p>He said that was the discussion he’d been trying to have.</p><p>The interview ended a few minutes later.</p><p>I didn’t know whether I’d passed.</p><p>For once, I wasn’t particularly interested in guessing.</p><h3>I Went Back Through My Previous Rejections</h3><p>That evening, I opened the spreadsheet I’d been maintaining since the beginning of the search. I read the feedback from the third interview, where the Engineering Manager had questioned my collaboration skills. Then I looked at the notes from the sixth company, which had raised concerns about how I evaluated alternative solutions.</p><p>The comments had bothered me because they seemed vague.</p><p>Now I wondered whether I’d been ignoring a pattern.</p><p>I thought about the database migration story I’d told during the third interview. I’d focused on the fact that my technical recommendation had been correct. I hadn’t explained why the Product Manager wanted the migration completed quickly or how we’d worked together to find a compromise.</p><p>I remembered the sixth interview, where I’d dismissed an alternative concurrency approach because I believed my implementation was simpler. I hadn’t explored whether the alternative might have advantages under different requirements.</p><p>None of those situations proved that the companies had rejected me for the same reason.</p><p>But I could see how my behavior might have created a similar impression.</p><p>I’d been treating technical interviews as opportunities to demonstrate certainty. When an interviewer challenged an answer, I assumed they wanted me to defend it. If they suggested another approach, I felt pressure to explain why mine was better.</p><p>That habit had probably developed over years of working in environments where engineers were expected to justify every decision. During production incidents, hesitation could be expensive, and confidence sometimes helped teams move quickly.</p><p>But confidence wasn’t the same as refusing to reconsider.</p><p>I had become so worried about looking uncertain that I was making it difficult for interviewers to have a normal technical conversation with me.</p><h3>The Rejection Arrived Anyway</h3><p>Three days after the cache interview, the recruiter emailed to say the company wouldn’t be moving forward. She thanked me for my time and said the team had decided to pursue another candidate.</p><p>I asked whether Michael had provided feedback.</p><p>She said he’d appreciated my technical knowledge but had concerns about collaboration and adaptability during the exercise.</p><p>I wasn’t surprised.</p><p>I also wasn’t particularly angry.</p><p>For the first time during the search, I understood what the feedback referred to. I could remember the exact moments when I’d dismissed alternative approaches without exploring them. I could also remember how uncomfortable I’d felt when Michael challenged my reasoning.</p><p>I replied to the recruiter and thanked her for the opportunity.</p><p>Then I sent Michael a short message through LinkedIn.</p><p>I told him I’d appreciated the discussion and that his feedback had helped me recognize something I’d been missing in previous interviews. I didn’t ask him to reconsider the decision or explain why I’d behaved the way I had. I simply thanked him for being direct.</p><p>He replied the following day.</p><p>He said he was glad the conversation had been useful and wished me luck with the search.</p><p>That was the end of it.</p><h3>The Next Interview Wasn’t Easier</h3><p>The next company asked me to design a service that processed customer events and updated account state. The interviewer was a Principal Engineer who had spent several years working on distributed systems. He introduced failure scenarios throughout the discussion and challenged nearly every design decision I made.</p><p>Early in the interview, I proposed using an asynchronous workflow for processing events. He asked whether synchronous processing might be simpler.</p><p>My first instinct was to explain why asynchronous systems were better suited to handling variable workloads.</p><p>Instead, I asked what latency requirements the customers had and whether the upstream service could tolerate waiting for confirmation.</p><p>He explained that most requests needed a response within two hundred milliseconds, but the business operation itself could complete later. We discussed the difference between acknowledging receipt and confirming completion, then explored which parts of the workflow needed durable state.</p><p>Later, I suggested using a message broker to decouple processing stages. The interviewer asked whether the team could implement the same behavior using a database-backed work queue.</p><p>I didn’t immediately dismiss the idea.</p><p>We compared the approaches based on expected throughput, operational complexity, recovery behavior, and the team’s existing infrastructure. I explained that a database-backed queue might be sufficient at modest scale, particularly if the team already operated PostgreSQL reliably and wanted to avoid another distributed component.</p><p>The interviewer challenged that conclusion too.</p><p>He asked what would happen if processing volume increased significantly or if workers needed independent scaling. We discussed how the design might evolve and which measurements would justify introducing a dedicated broker.</p><p>The conversation lasted seventy minutes.</p><p>I made mistakes during it.</p><p>At one point, I overlooked a failure scenario involving an operation that had committed successfully before the worker crashed. The interviewer pointed it out, and I acknowledged the problem before adjusting the design.</p><p>I didn’t try to explain why my original approach had been reasonable.</p><p>I fixed it.</p><p>The recruiter called two days later to schedule a final interview.</p><h3>The Final Interview Felt Like a Conversation</h3><p>The Engineering Manager asked about my previous projects and how I handled technical disagreements. I described the database migration I’d discussed during an earlier interview, but this time I explained the business context before describing the technical problem.</p><p>The Product Manager had been trying to meet a customer deadline. The engineering team was concerned about the migration’s impact on production traffic, and I’d initially argued against the proposed schedule. We eventually agreed on a staged rollout that reduced the risk while allowing part of the feature to ship on time.</p><p>The manager asked what I’d do differently.</p><p>I said I’d present the trade-offs earlier and spend more time understanding why the deadline mattered. My technical concerns had been legitimate, but I’d made the conversation harder by treating the schedule as an engineering mistake rather than a business constraint we needed to work around.</p><p>He asked whether I’d ever changed my mind during an architecture discussion. I described a project where I’d initially favored introducing a message broker, but another engineer had suggested using a simpler database-backed workflow. After reviewing the workload and operational requirements, we’d chosen the simpler approach.</p><p>The manager asked whether that decision had worked.</p><p>I said it had worked for the original requirements, although the team later revisited the architecture when processing volume increased. I explained what we’d learned and why the initial decision hadn’t necessarily been wrong just because the system eventually needed to evolve. We spent the rest of the conversation discussing the team’s current challenges. I left the interview feeling tired but comfortable. The company made an offer the following week. I accepted.</p><h3>I Still Disagree With Some of Those Interviewers</h3><p>I don’t think every rejection was fair. Some interviewers asked vague questions and seemed frustrated when candidates interpreted them differently. Others introduced requirements late in an exercise and treated the resulting design changes as evidence of poor judgment.</p><p>I’ve also encountered interviewers who confused confidence with arrogance and disagreement with a lack of collaboration. A candidate can challenge an idea respectfully and still be a good teammate. Senior engineers sometimes need to push back when a decision introduces serious production risk, even when that makes the conversation uncomfortable.</p><p>But Michael hadn’t asked me to agree with him.</p><p>He’d asked me to consider a different set of constraints.</p><p>I’d spent most of the interview explaining why my original recommendation was better, even after the problem had changed. My technical knowledge hadn’t disappeared, but I’d made it harder for him to understand how I’d work with other engineers.</p><p>That distinction mattered.</p><p>I still prepare carefully for technical interviews. I review Java concurrency, database transactions, distributed systems, and the kinds of production failures that don’t appear in clean architecture diagrams. I want to be able to explain my reasoning clearly, especially when an interviewer challenges it.</p><p>The difference is that I no longer assume every challenge requires a defense.</p><p>Sometimes the interviewer has information I don’t have. Sometimes they’re testing whether I can adapt to new requirements. Occasionally, they’re simply wrong, and the right response is to explain why without turning the discussion into a personal contest.</p><p>I still have the notes from Michael’s interview.</p><p>They include the cache implementation, the concurrency questions, and the feedback about adaptability. I also wrote down the moment he closed the editor because I hadn’t realized how much of the interview I’d spent arguing about a decision he wasn’t asking me to defend.</p><p>I wish I’d recognized the pattern earlier.</p><p>It might have saved me several rejections, although I can’t know how those companies would have evaluated me if I’d behaved differently. What I do know is that I became better at technical interviews when I stopped treating every disagreement as a threat to my competence. The Java questions didn’t become easier. I just became more willing to listen before answering.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for Java and backend engineering interviews, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers concurrency, transaction management, PostgreSQL, and production debugging. For architecture interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, reliability, and explaining technical trade-offs under pressure.</p><p>I also write about production engineering, system design interviews, and software engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in practicing realistic architecture scenarios, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b36c70a2a7a3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-got-rejected-from-7-software-engineer-interviews-one-interviewer-finally-showed-me-why-b36c70a2a7a3">I Got Rejected From 7 Software Engineer Interviews. One Interviewer Finally Showed Me Why</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Passed 6 Software Engineer Interviews. Then HR Asked Me for My Last Salary]]></title>
            <link>https://medium.com/engineering-playbook/i-passed-6-software-engineer-interviews-then-hr-asked-me-for-my-last-salary-603ee3d9b0ac?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/603ee3d9b0ac</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:05:27 GMT</pubDate>
            <atom:updated>2026-11-11T18:05:44.313Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EEJKsRlkX4MEhi5TbcKcaw.png" /></figure><h4><em>I spent 72 days trying to prove I was worth hiring as a Senior Engineer. One question about my previous paycheck made me realize the company and I had been negotiating two completely different jobs.</em></h4><p>The recruiter asked for my previous salary eleven minutes after telling me I’d passed the final interview. I’d spent nearly a month speaking with engineers, completing a coding exercise, and defending architectural decisions in front of two people who had considerably more experience than I did. The Engineering Director had said my background was exactly what the team needed, and the recruiter had already started discussing possible start dates.</p><p>Then she asked what I’d earned at my previous company. I told her I preferred to discuss compensation based on the responsibilities of the new position and the range we’d agreed on during our first conversation. She laughed politely and said she understood, but the compensation committee needed my salary history to prepare the offer.</p><p>I reminded her that she’d advertised the position at $145,000 to $175,000. We’d discussed my expectation of $160,000 before the first technical interview, and she’d confirmed it was within budget. She said none of that had changed, although she still needed the number.</p><p>I gave it to her.</p><p>There was a short silence before she asked whether the amount included bonuses. I told her it didn’t, and she said she’d get back to me after speaking with the compensation team.</p><p>The offer arrived three days later.</p><p>It was $128,000.</p><h3>I Had Already Been Rejected Five Times</h3><p>My job search had started in February, after I’d decided to leave a backend engineering position where I’d spent several years working with Java, Spring Boot, PostgreSQL, and distributed systems. I had enough production experience to apply for senior roles, but I wasn’t under the impression that every company would agree with my assessment. Some organizations expected senior engineers to lead projects independently, while others seemed to want someone who could design an entire platform, manage a team, and occasionally perform minor miracles with Kubernetes.</p><p>The first rejection came after a live coding interview. I’d implemented the main functionality correctly but missed an edge case involving concurrent updates. The interviewer asked how I’d prevent two requests from overwriting each other’s changes, and I started discussing application-level synchronization before considering whether the database could enforce the necessary constraint.</p><p>I knew the answer afterward, which made the rejection more irritating. I’d worked with optimistic locking before, but under interview pressure, I’d reached for a complicated solution to a problem that already had a reasonable one.</p><p>The second company rejected me after a system design round. I designed a notification service, discussed queues and retries, and explained how I’d handle temporary failures. The interviewer kept asking about customer preferences, and I realized too late that I’d designed the delivery infrastructure without properly considering when messages should be sent in the first place.</p><p>The third rejection came after a behavioral interview. The Engineering Manager wanted examples of cross-team leadership, and I described a production migration where I’d handled most of the technical work. He asked how I’d influenced other teams, and I struggled because I’d been responsible for implementation rather than organizational coordination.</p><p>That feedback was useful, even if I didn’t particularly enjoy receiving it.</p><p>By the fourth rejection, I’d started keeping a spreadsheet. I tracked interview stages, salary ranges, technical questions, and the reasons companies gave for rejecting me. The document helped me prepare, although it also made the entire process feel like a particularly unpleasant performance review conducted by strangers.</p><p>The fifth company took twenty-three days to reject me. I’d completed the coding round and spoken with the Engineering Manager, but the team eventually chose someone with more experience in its cloud infrastructure. The recruiter apologized for the delay and said she’d enjoyed working with me.</p><p>I thanked her.</p><p>Then I opened another job posting.</p><h3>The Sixth Company Looked Different</h3><p>The sixth opportunity came from a recruiter named Melissa. She contacted me about a Senior Backend Engineer position at a company building software for financial services businesses. The engineering team was expanding, and they needed someone comfortable with transaction processing, asynchronous workflows, and production reliability.</p><p>The job description mentioned Java, Spring Boot, PostgreSQL, Kafka, and AWS. I’d worked with most of those technologies, and the responsibilities sounded closer to my actual experience than several previous positions. More importantly, the advertised salary range was $145,000 to $175,000, which made the role financially attractive.</p><p>During our first conversation, Melissa asked about my compensation expectations. I told her I was targeting around $160,000, depending on the responsibilities and overall package. She said that was comfortably within the approved range and that the company wasn’t looking to hire at the bottom of the band.</p><p>I asked whether the role was definitely classified as Senior Engineer.</p><p>She confirmed it was.</p><p>That mattered because I’d already encountered companies advertising senior positions while evaluating candidates against intermediate-level compensation bands. I didn’t want to spend another month interviewing only to discover that the actual budget had never matched the job description.</p><p>Melissa assured me the position had been approved.</p><p>We scheduled the first technical interview for the following Tuesday.</p><h3>The Technical Interviews Were Better Than I Expected</h3><p>The first interviewer was a Staff Engineer named Andrew. He asked about my previous work with transaction processing and wanted to understand how I’d handled failures in asynchronous systems. We discussed a service where RabbitMQ messages triggered database updates, and he asked what happened if the database transaction committed but the consumer crashed before acknowledging the message.</p><p>I explained how we’d designed the processing operation to tolerate duplicate delivery. We discussed unique operation identifiers, database constraints, and the importance of making the business state transition idempotent. Andrew challenged a few assumptions, but the conversation felt like an architecture review rather than an examination.</p><p>The next round was a coding exercise involving account transfers. I needed to implement the business logic, validate account states, and ensure that concurrent requests couldn’t produce inconsistent balances. The interviewer introduced a scenario where two transfers attempted to debit the same account simultaneously.</p><p>I explained the trade-offs between optimistic and pessimistic locking, then implemented a version using database transactions and a locking strategy appropriate for the exercise. We discussed deadlock avoidance, transaction boundaries, and how the implementation would behave under higher load.</p><p>The interviewer said he’d enjoyed the discussion.</p><p>Two days later, Melissa called to say I’d passed.</p><p>The third round involved system design. The Engineering Director asked me to design a payment-processing workflow that could survive partial failures across multiple services. I started by clarifying the requirements, particularly whether the system needed immediate confirmation or could tolerate asynchronous completion.</p><p>We discussed duplicate requests, retries, and the difference between a failed operation and an operation whose outcome was unknown. I explained why blindly retrying a timed-out payment request could be dangerous without a stable idempotency key and a way to recover the authoritative result.</p><p>The director asked how I’d investigate a situation where customers were reporting duplicate charges despite the service returning errors. I described how I’d correlate request identifiers, payment-provider responses, database records, and message-processing logs before deciding whether the duplicates were real or merely duplicate notifications.</p><p>He nodded and said the team had encountered similar problems.</p><p>For the first time during the search, I felt that my production experience was being evaluated on its own terms.</p><h3>The Final Interview Made Me Think an Offer Was Coming</h3><p>The final conversation was with the Engineering Director and a Product Manager. They wanted to understand how I handled disagreements, estimated complex work, and communicated technical risks to people who didn’t spend their days reading logs.</p><p>The Product Manager described a situation where a customer had requested a feature that would require changing several services. The engineering team believed the work would take six weeks, but the commercial team had promised delivery in three. She asked what I’d do if I were responsible for the backend implementation.</p><p>I explained that I’d first identify which parts of the feature were essential for the customer and which could be delivered later. I’d also want to understand the technical risks, particularly whether the change affected existing transaction behavior or required a database migration. If the full scope couldn’t be delivered safely, I’d propose a smaller release with clear limitations rather than quietly accepting a deadline I didn’t believe.</p><p>She asked what I’d do if leadership insisted on the original deadline.</p><p>I told her I’d document the risks, present realistic alternatives, and help the team make an informed decision. I’d worked in environments where engineers were expected to solve every scheduling problem through overtime, and I didn’t think that was a sustainable substitute for planning.</p><p>The director seemed comfortable with the answer.</p><p>We spent the final fifteen minutes discussing the team’s current problems. They wanted to reduce incident frequency, improve deployment confidence, and make it easier for engineers to understand how transactions moved between services.</p><p>I asked whether the company had dedicated time for reliability work.</p><p>The director said it did, although urgent customer commitments occasionally disrupted those plans. He described several improvements already underway, including better tracing and a gradual effort to reduce dependencies between services.</p><p>The conversation ended after seventy minutes.</p><p>The next morning, Melissa called and said the engineering team wanted to move forward.</p><p>I thought the difficult part was over.</p><h3>The Salary Question Came After Everything Else</h3><p>Melissa sounded pleased when she told me I’d passed. She said the Engineering Director had been particularly impressed by my experience with production failures and that the team believed I could contribute quickly.</p><p>Then she asked about my previous compensation.</p><p>I’d earned $105,000 at my last company. That salary had been established several years earlier, before I’d taken on additional responsibilities and gained more experience with complex backend systems. It also reflected the compensation practices of a different organization, which was one reason I hadn’t considered it particularly relevant to the new role.</p><p>I explained that my previous salary was lower than the range we’d discussed, but I was targeting $160,000 because of the responsibilities and market level of the position.</p><p>Melissa said she understood.</p><p>She asked whether the $105,000 included bonuses, stock, or other benefits. I told her it was the base salary and that the company hadn’t offered meaningful equity compensation.</p><p>She said she’d submit the information to the compensation committee.</p><p>I didn’t expect the offer to match my exact target automatically. I understood that companies had internal salary structures and that compensation depended on experience, interview performance, and the scope of the role.</p><p>But we’d discussed the range before I’d invested nearly a month in the process.</p><p>I assumed the offer would at least fall within it.</p><p>Three days later, Melissa sent the compensation details.</p><p>The base salary was $128,000.</p><p>There was a modest annual bonus and a standard benefits package, but the guaranteed compensation was $17,000 below the advertised minimum.</p><p>I read the email twice.</p><p>Then I called her.</p><h3>The Recruiter Said the Offer Was a Significant Increase</h3><p>Melissa explained that the compensation committee had reviewed my experience, interview feedback, and previous salary. The team was enthusiastic about hiring me, but the committee believed $128,000 was an appropriate starting point.</p><p>I asked why the offer was below the advertised range.</p><p>She said the published range represented the broader compensation band and that individual offers depended on internal leveling.</p><p>I reminded her that the position had been advertised as Senior Backend Engineer and that she’d confirmed the approved range during our first conversation.</p><p>She acknowledged that we’d discussed it.</p><p>Then she said the proposed salary represented an increase of more than twenty percent over my previous base compensation.</p><p>I asked what that had to do with the value of the new position.</p><p>Melissa explained that the company considered previous compensation as one input when evaluating offers. She said the committee also wanted to maintain internal equity and avoid placing new hires too high within the band.</p><p>I understood the internal equity argument. If existing engineers with similar responsibilities were earning substantially less, the company had a legitimate compensation problem to address.</p><p>But I couldn’t understand why my previous employer’s salary decision should determine what this company was willing to pay for work it had already evaluated.</p><p>I asked whether the engineering team had recommended a different level.</p><p>Melissa said the technical feedback supported the senior classification.</p><p>I asked whether the role’s responsibilities had changed.</p><p>She said they hadn’t.</p><p>Then I asked whether the company would have offered more if I’d previously earned $150,000.</p><p>She didn’t answer directly.</p><p>Instead, she said the compensation committee considered each candidate individually.</p><p>That was the moment I stopped thinking of the offer as a misunderstanding.</p><h3>I Asked the Engineering Director a Question HR Couldn’t Answer</h3><p>I emailed the Engineering Director and thanked him for the interviews. I explained that I was interested in the position but concerned about the difference between the advertised compensation range and the offer.</p><p>He agreed to speak with me the following afternoon.</p><p>I told him the offer was $128,000, despite the published range starting at $145,000. He seemed surprised and asked whether I’d discussed the difference with Melissa.</p><p>I said I had.</p><p>He explained that engineering managers provided hiring recommendations, but compensation decisions were handled by HR and finance. He said he’d supported hiring me at the senior level and hadn’t been aware of the final number before it was sent.</p><p>I asked whether the team would expect me to perform the same responsibilities described during the interviews.</p><p>He said yes.</p><p>The role involved owning backend services, participating in architectural decisions, helping improve production reliability, and supporting less experienced engineers.</p><p>I asked whether someone hired at $128,000 would have different responsibilities from someone hired at $160,000.</p><p>He said the responsibilities would be determined by the engineering level rather than the individual’s salary.</p><p>That answer made sense from an organizational perspective.</p><p>It also confirmed that the company was asking me to perform the same job for substantially less compensation than we’d discussed.</p><p>The director said he’d speak with HR and see whether there was room to adjust the offer.</p><p>I thanked him.</p><p>For the next two days, I tried to decide what number I’d be willing to accept.</p><h3>My Savings Were Making the Decision More Complicated</h3><p>I’d been looking for work for seventy-two days. My savings were shrinking, and I’d already spent money on expenses I hadn’t expected when the search began. Every additional month without income made the next interview feel more important than the previous one.</p><p>The difference between $128,000 and $160,000 was $32,000 per year before taxes. That wasn’t a small amount, especially when I considered future raises and how long I might remain at the company.</p><p>But $128,000 was still more than I’d earned previously.</p><p>I could accept the offer, start earning again, and potentially negotiate a raise after demonstrating my value. Several friends suggested that approach because they knew how much the search had been affecting me.</p><p>One friend told me that a twenty-two percent increase was a good outcome after being unemployed.</p><p>I understood his reasoning.</p><p>Another asked whether I was prepared to lose the offer over a salary disagreement when I had no competing offer.</p><p>That question bothered me because I didn’t have a confident answer.</p><p>I’d spent weeks trying to convince companies that I was a capable senior engineer. Now a company wanted to hire me, and I was considering walking away because the compensation process felt unfair.</p><p>I wondered whether I was being stubborn.</p><p>I also wondered how I’d feel six months later if I accepted the offer and discovered that other engineers performing similar work had been hired at substantially higher salaries.</p><p>I couldn’t know what anyone else earned.</p><p>But I knew what the company had advertised and what we’d discussed before the interviews.</p><p>Those were the facts I kept returning to.</p><h3>The Revised Offer Was Still Below the Range</h3><p>Melissa called on Friday afternoon. She said the Engineering Director had advocated for an adjustment and that the compensation committee had approved a revised offer of $138,000.</p><p>She sounded pleased.</p><p>I thanked her for the effort and asked whether the company could reach $150,000. That was below my original target, but it was within the advertised range and reflected a compromise I could accept.</p><p>Melissa said she’d already pushed as far as she could.</p><p>She explained that $138,000 was the maximum approved amount and that the company needed an answer by Monday.</p><p>I asked whether there was an opportunity to revisit compensation after six months.</p><p>She said the company conducted annual performance reviews and that salary adjustments depended on business conditions and individual performance. There wasn’t a guaranteed six-month review.</p><p>I asked whether a signing bonus could help bridge the difference.</p><p>She said the company wasn’t offering one for the position.</p><p>I thanked her and said I’d think about it.</p><p>That weekend was unpleasant.</p><p>I opened the offer several times, compared the compensation with my expenses, and looked at the job description again. The engineering work still interested me, and the people I’d interviewed with seemed capable.</p><p>I didn’t think the company was necessarily a bad employer.</p><p>But I was uncomfortable with how the compensation conversation had unfolded. The range had been presented as approved, my expectations had been confirmed, and the offer had fallen below the minimum only after the company learned my previous salary.</p><p>I couldn’t prove that salary history was the deciding factor.</p><p>The timing and the recruiter’s explanation made it difficult to ignore.</p><h3>I Turned Down the Offer on Monday</h3><p>I called Melissa before lunch and told her I appreciated the revised offer but wouldn’t be accepting it.</p><p>She asked whether I’d reconsider if the company could provide additional flexibility around remote work or vacation. I told her those benefits were valuable, but they didn’t resolve the compensation difference.</p><p>She sounded disappointed and said the engineering team had been excited about hiring me.</p><p>I believed her.</p><p>That was what made the decision difficult.</p><p>I’d enjoyed the technical interviews and thought I could do the work well. I wasn’t rejecting the company because the engineers had treated me badly or because the role was uninteresting.</p><p>I was declining because the compensation process had changed the terms of a conversation we’d started almost a month earlier.</p><p>After the call, I sat at my desk and stared at the spreadsheet.</p><p>Five rejections, one offer declined, and seventy-two days without a new job.</p><p>I wasn’t particularly proud of how the numbers looked.</p><p>For the rest of the afternoon, I questioned the decision.</p><h3>The Next Company Asked About Salary on the First Call</h3><p>Two weeks later, I spoke with another recruiter about a Senior Backend Engineer role. The company built infrastructure software for business customers and needed someone with experience designing reliable Java services.</p><p>The recruiter asked about my salary expectations during our first conversation.</p><p>I said I was targeting $155,000 to $165,000, depending on the role’s responsibilities and the overall package.</p><p>He confirmed that the range was compatible with the position.</p><p>Then he asked whether I was comfortable sharing my previous salary.</p><p>I said I preferred to keep the discussion focused on the new role and its compensation band.</p><p>He said that was fine.</p><p>We moved on to my technical background.</p><p>The interview process took three weeks. I completed a Java coding exercise, discussed database performance with a Staff Engineer, and participated in a system design interview about processing customer transactions across multiple services.</p><p>I made a few mistakes.</p><p>During the coding round, I initially overlooked an edge case involving transaction retries. The interviewer pointed it out, and we discussed how the application should behave when the database operation succeeded but the client received a timeout.</p><p>I explained the failure scenario, corrected the implementation, and added a test.</p><p>The interviewer seemed satisfied.</p><p>The Engineering Manager asked about production incidents, technical disagreements, and how I approached unfamiliar systems. I described the work I’d actually done and tried to avoid turning every answer into a performance.</p><p>The company made an offer at $158,000.</p><p>I accepted.</p><h3>I Don’t Think Every Company Uses Salary History the Same Way</h3><p>Looking back, I can’t say whether the first company’s compensation committee would have offered me more if I’d refused to disclose my previous salary. They might have made the same decision based on internal budgets, leveling policies, or other factors I couldn’t see.</p><p>I also can’t know whether accepting $138,000 would have been a mistake. The role might have provided excellent experience, and the company might have increased my compensation later.</p><p>Those possibilities don’t change what happened during the process.</p><p>I’d spent weeks demonstrating my technical experience against a role with an advertised salary range. The company evaluated my coding ability, system design judgment, and production experience before deciding it wanted to hire me.</p><p>Then the compensation conversation shifted toward what I’d earned somewhere else.</p><p>That was difficult to reconcile with the way the technical interviews had been conducted.</p><p>The experience also made me think about how much information candidates are expected to provide during hiring. Companies ask about previous projects, difficult decisions, mistakes, employment gaps, and sometimes compensation history. Candidates are expected to answer clearly while knowing relatively little about how the organization evaluates those answers.</p><p>I don’t think every recruiter who asks about salary history is trying to underpay someone. Some are following established processes, and others may be working within policies they didn’t create.</p><p>But candidates should understand that the number they provide can become part of the negotiation, even when the new role has different responsibilities and a published compensation range.</p><p>I still keep notes from that job search.</p><p>The sixth company has the longest entry because I recorded every stage, the original salary discussion, the first offer, and the revised amount. I also wrote down the questions I wished I’d asked before agreeing to the technical interviews.</p><p>I haven’t deleted those notes.</p><p>The experience changed how I discuss compensation, but it didn’t make me better at Java or system design. I’d already demonstrated those skills during the interviews.</p><p>What changed was my willingness to ask for clarity before investing weeks in a hiring process.</p><p>I still prepare for coding rounds, architecture discussions, and questions about production failures. I want to demonstrate that I can do the work, and I understand that companies need to evaluate candidates carefully.</p><p>I also want to know whether we’re discussing the same job at the same compensation level.</p><p>After seventy-two days of interviews, that seemed like a reasonable thing to establish before anyone asked me to write another line of code.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for Java and backend engineering interviews, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers transaction management, concurrency, PostgreSQL, and production debugging. For architecture interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, reliability, and explaining engineering trade-offs under pressure.</p><p>I also write about production engineering, system design, and software engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in realistic system design practice, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=603ee3d9b0ac" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-passed-6-software-engineer-interviews-then-hr-asked-me-for-my-last-salary-603ee3d9b0ac">I Passed 6 Software Engineer Interviews. Then HR Asked Me for My Last Salary</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Failed 8 Senior Software Engineer Interviews. Then I Found Out What My References Were Saying]]></title>
            <link>https://medium.com/engineering-playbook/i-failed-8-senior-software-engineer-interviews-then-i-found-out-what-my-references-were-saying-df2dc3fb0454?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/df2dc3fb0454</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[leadership]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:03:39 GMT</pubDate>
            <atom:updated>2026-11-11T18:03:57.214Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L0yuohmH4zLEiDnc43DPpA.png" /></figure><h4><em>I spent 67 days fixing my technical answers, rewriting my résumé, and wondering why companies kept disappearing after the final round. One phone call made me question the entire search.</em></h4><p>The recruiter called at 6:12 p.m., nearly an hour after I’d given up waiting for her. She sounded uncomfortable, which was unusual because she’d been cheerful throughout the interview process. I’d completed four rounds for a Senior Backend Engineer position, including a Java coding assessment and a system design interview that had gone surprisingly well. The hiring manager had even asked whether I could start before the end of the month.</p><p>She told me the company wouldn’t be moving forward. I asked whether the engineering team had raised any concerns, expecting another explanation about leadership experience or architectural judgment. Instead, she said the decision had been made after the reference checks, and she wasn’t authorized to share the details.</p><p>I sat at my desk for several minutes after the call, looking at the names I’d provided. One belonged to a former Engineering Manager, another to a Staff Engineer I’d worked with for nearly two years, and the third to a colleague who’d helped me investigate several difficult production incidents. I trusted all three, or at least I thought I did. The possibility that someone had said something negative about me hadn’t occurred to me until that evening.</p><p>What bothered me was that this wasn’t the first company to reject me after a promising final interview. It was the eighth rejection in sixty-seven days, and I was running out of explanations that made sense.</p><h3>The First Month Wasn’t Particularly Alarming</h3><p>I’d started looking for a new position after leaving a backend engineering role where I’d spent several years working on Java, Spring Boot, PostgreSQL, and asynchronous processing systems. I wasn’t expecting the market to be easy, but I had enough production experience to believe I could compete for senior positions. I’d handled incidents, reviewed architecture proposals, helped junior engineers, and spent more nights than I wanted debugging services that behaved perfectly in staging.</p><p>The first rejection came after a coding interview. I misunderstood part of the requirement, built a solution around the wrong assumption, and spent the final fifteen minutes trying to repair it. The interviewer was polite, but I knew I’d made a mistake before the call ended. I wrote down what happened and moved on, assuming the next interview would go better.</p><p>The second company rejected me after a system design round. They’d asked me to design a platform for processing large batches of customer events, and I’d spent too much time discussing Kafka before establishing the business requirements. When the interviewer introduced delayed events and conflicting updates, my design became increasingly complicated. The feedback said I needed to improve how I clarified constraints, which was difficult to argue with.</p><p>By the third interview, I was preparing more carefully. I practiced explaining transaction boundaries, database locking, and failure recovery without turning every answer into a lecture. I also started recording the questions I’d struggled with, because I didn’t want to keep making the same mistakes under different circumstances.</p><p>That approach seemed to work. I reached the final round at the third company, had a productive conversation with the Engineering Director, and received positive feedback from the recruiter. Then the company decided to hire someone with more experience leading cross-team initiatives.</p><p>I was disappointed, but I understood the decision. Someone else had been a stronger match, and there wasn’t much I could do about that.</p><p>The fourth rejection was less clear. I’d completed the technical interviews, discussed salary, and provided references when the recruiter requested them. A week later, she emailed to say the team had decided to pursue another candidate. I asked for feedback and received a polite response that didn’t explain anything.</p><p>I didn’t think much about the references at the time.</p><p>That was probably my first mistake.</p><h3>I Was Getting Better at Interviews and Worse at Getting Hired</h3><p>By the fifth interview, I could explain most of the technical topics companies were asking about without needing to rehearse every sentence. I knew how to discuss optimistic locking, PostgreSQL query plans, Spring transaction management, and the operational consequences of asynchronous messaging. I also understood that a good system design interview involved asking questions before drawing boxes, something I’d learned after embarrassing myself during the second rejection.</p><p>My confidence improved during the technical rounds, but the results didn’t. Companies kept telling me the engineering feedback was strong, then rejecting me after the final conversation. Sometimes the explanation involved leadership experience, and sometimes the recruiter said another candidate was a better fit. A few companies stopped responding altogether, which was especially irritating after they’d spent weeks asking me to make time for interviews.</p><p>I started wondering whether there was something wrong with the way I presented myself. Perhaps I sounded too confident, or maybe I wasn’t demonstrating enough ownership when discussing previous projects. I watched recordings of mock interviews, practiced answering behavioral questions, and asked a friend to challenge my explanations whenever I became vague.</p><p>He told me I sounded like someone who’d spent too much time preparing for interviews. My answers were technically accurate, but I kept adding details that nobody had asked for. He said I needed to explain what I’d actually done instead of trying to demonstrate that I understood every possible failure mode.</p><p>I tried to follow his advice. During the sixth interview, I described a production incident involving a Spring Boot service that had been exhausting its database connection pool. I explained how we’d initially suspected slow queries, discovered that requests were holding connections during external HTTP calls, and changed the transaction boundaries after verifying the failure behavior.</p><p>The interviewer seemed satisfied. He asked how we’d tested the change, and I explained the integration tests and gradual rollout we’d used to avoid introducing another incident. We spent another twenty minutes discussing related problems, and I left the call feeling that I’d finally communicated my experience clearly.</p><p>The company rejected me eleven days later.</p><p>The recruiter said the technical feedback had been positive, but the hiring team had decided not to proceed. I asked whether there was a specific concern, and she said she couldn’t provide additional details.</p><p>I added another row to my spreadsheet.</p><h3>The Seventh Company Asked for References Before the Final Interview</h3><p>The seventh opportunity came through a recruiter who’d contacted me about a Senior Java Engineer position at a financial technology company. The role involved maintaining payment services and improving the reliability of asynchronous workflows. The salary was reasonable, and the Engineering Manager seemed genuinely interested in my experience with production incidents.</p><p>After the second technical round, the recruiter asked me to provide three professional references. I sent the same names I’d used during previous applications because those people had worked closely with me and understood the systems I’d helped maintain. I assumed the company would contact them only if it was seriously considering an offer.</p><p>A few days later, I completed the final interview. The Engineering Director asked about technical disagreements, project ownership, and how I’d handled situations where my recommendations weren’t accepted. I described a migration where I’d raised concerns about a database change that could introduce locking problems during peak traffic.</p><p>The director asked whether the team had followed my recommendation. I explained that we’d eventually agreed on a safer rollout after reviewing the risks together. He seemed satisfied with the answer, and the interview ended with a discussion about the team’s current architecture.</p><p>The rejection arrived the following week. The recruiter thanked me for my time and said the company had decided to move forward with another candidate. I asked whether the reference checks had raised any concerns, but she said she couldn’t discuss the internal evaluation process.</p><p>That was the first time I seriously considered whether my references might be affecting the outcome.</p><p>I contacted the Staff Engineer I’d listed and asked whether any companies had called him. He said two recruiters had reached out, and he’d spoken positively about my technical skills and production experience. He also mentioned that one recruiter had asked several questions about how I handled disagreements with managers.</p><p>I asked what he’d said.</p><p>He told me he’d described me as someone who cared deeply about technical correctness and occasionally needed reminding that business constraints mattered too. He said he’d also explained that I was dependable during incidents and willing to take responsibility when things went wrong.</p><p>That sounded reasonable, although I wondered how it might have been interpreted by someone who’d never worked with me.</p><p>I thanked him and ended the call.</p><h3>The Eighth Rejection Finally Made Me Ask an Uncomfortable Question</h3><p>The eighth company was the one whose recruiter called me at 6:12 p.m. I’d passed the technical interviews, discussed salary, and received encouraging feedback from the Engineering Manager. The team wanted someone who could take ownership of several Java services and help improve production reliability, which matched the work I’d been doing for years.</p><p>After the rejection, I contacted my former Engineering Manager. His name was Robert, and we’d worked together during a difficult period when the team had been under pressure to deliver several projects simultaneously. We’d disagreed about deadlines and technical priorities, but I’d believed we’d ended our working relationship professionally.</p><p>I asked whether he’d been contacted by any recruiters.</p><p>He said he’d spoken with three companies.</p><p>I asked what they’d wanted to know.</p><p>He explained that most questions concerned my technical abilities, reliability, and communication. He’d told them I was a capable backend engineer who understood production systems and could investigate difficult problems independently.</p><p>Then he mentioned that some recruiters had asked whether he’d hire me again.</p><p>I asked how he’d answered.</p><p>Robert was quiet for a moment before saying he’d told them it would depend on the role and the team. He believed I was technically strong, but he thought I sometimes struggled when project priorities changed unexpectedly. He also said I could become frustrated when management decisions conflicted with my technical recommendations.</p><p>I didn’t respond immediately.</p><p>We’d discussed those disagreements before, and I knew he hadn’t invented them. There had been meetings where I’d become irritated because I believed the team was accepting unnecessary production risk. I’d argued strongly about deployment deadlines and occasionally made it obvious that I thought a decision was foolish.</p><p>But hearing Robert describe those situations as a reason he might hesitate to hire me again was different.</p><p>I asked whether he’d told recruiters about the projects I’d delivered successfully or the incidents I’d helped resolve.</p><p>He said he had.</p><p>Then he added that reference checks were supposed to provide a balanced assessment.</p><p>I understood his point, but I also realized I’d made an assumption that had never been tested. I’d listed Robert because he’d been my manager and could verify my responsibilities. I hadn’t actually asked whether he felt comfortable recommending me for another senior engineering role.</p><p>That was an important distinction.</p><h3>I Had Chosen References Based on Their Titles</h3><p>After speaking with Robert, I looked at the reference list I’d been sending to companies. I’d selected people with impressive job titles because I thought recruiters would take their opinions seriously. An Engineering Manager and a Staff Engineer seemed more credible than colleagues who’d worked beside me every day.</p><p>What I hadn’t considered was whether those people had the clearest understanding of my work or would provide the kind of reference I expected.</p><p>Robert had managed a team of engineers and was responsible for delivery schedules, staffing decisions, and performance reviews. His experience working with me was shaped by those responsibilities. He remembered the technical disagreements because they had affected his job, even when the underlying engineering concerns were legitimate.</p><p>The Staff Engineer had worked more closely with me on architecture and production incidents. He’d seen me investigate failures, review code, and help other engineers understand difficult problems. His assessment was more focused on technical judgment, although he also remembered occasions when I’d become frustrated during disagreements.</p><p>Neither perspective was necessarily dishonest.</p><p>The problem was that I’d treated professional references as a formality. I’d assumed that people who respected my technical abilities would automatically recommend me enthusiastically, regardless of how they viewed other aspects of my work.</p><p>I called another former colleague named Daniel. We’d worked together on a payment processing service for almost two years, and he’d been involved in several of the incidents I discussed during interviews. I asked whether he’d be comfortable serving as a reference and whether he had any concerns about recommending me.</p><p>He said he’d be happy to help.</p><p>Then he asked why I was suddenly worried about references.</p><p>I explained what had happened.</p><p>Daniel listened and said something I hadn’t expected. He told me Robert’s comments weren’t entirely surprising because we’d had several tense meetings during the final months of the project. He also said the team had respected my technical judgment, even when my communication could have been better.</p><p>I asked whether he’d mention those disagreements if a recruiter asked.</p><p>He said he wouldn’t pretend they hadn’t happened. But he’d explain the circumstances and describe how I’d worked with the team to resolve them.</p><p>That answer made me more comfortable than a promise to say only positive things.</p><h3>I Changed the Way I Prepared for Reference Checks</h3><p>For the next application, I asked each potential reference whether they felt comfortable giving a strong, honest recommendation for the specific kind of role I was pursuing. I explained the responsibilities, the seniority level, and the aspects of my experience the hiring team was likely to evaluate.</p><p>I didn’t ask anyone to hide problems or invent achievements. I wanted to know whether they genuinely believed I was a good fit and whether they could discuss my work with enough context to make their assessment useful.</p><p>One former colleague declined because we hadn’t worked together closely enough in recent years. I appreciated the honesty and removed him from the list. Another said he’d be happy to provide a reference but wanted to review the projects we’d completed together so he could give accurate examples.</p><p>I also stopped using Robert as a reference for roles where I needed someone to speak confidently about my technical leadership. He’d been honest about his reservations, and I didn’t want to put either of us in an awkward position by continuing to list him without discussing those concerns.</p><p>That didn’t mean I could erase his perspective. A future employer might still ask for a previous manager or contact someone independently where permitted. I needed to be prepared to discuss my professional relationships honestly rather than assuming a different reference list would solve every problem.</p><p>I also worked on the issue Robert had raised.</p><p>During interviews, I began explaining technical disagreements with more attention to how I’d communicated, what alternatives I’d offered, and whether I’d helped the team reach a workable decision. I stopped describing situations as though the main objective had been proving that my technical assessment was correct.</p><p>The change felt uncomfortable at first.</p><p>I was used to talking about production incidents in terms of symptoms, root causes, and fixes. Discussing the human side required admitting that I could be technically right and still handle a disagreement poorly.</p><p>That was harder than explaining PostgreSQL locking.</p><h3>The Ninth Interview Was Different</h3><p>The ninth company was a smaller SaaS business hiring a Senior Backend Engineer for its transaction platform. The first interview was with an Engineering Manager who asked about my experience maintaining production services. We discussed Java, Spring Boot, database performance, and the operational challenges of processing asynchronous events.</p><p>The technical rounds went well. I completed a coding exercise involving concurrent updates and participated in a system design interview about handling delayed and duplicate messages. The Staff Engineer challenged several assumptions, and I explained the trade-offs without trying to turn every answer into a demonstration of how much I knew.</p><p>During the final interview, the Engineering Manager asked about a disagreement I’d had with another engineer. I described a situation where we’d argued about deploying a database migration before a busy trading period. I’d believed the change introduced unnecessary risk, while the project manager was concerned about missing a customer deadline.</p><p>I explained that my initial communication had been too confrontational. I’d focused on the technical danger without presenting a practical alternative, which made the discussion less productive. We eventually agreed on a staged rollout with additional monitoring, but the process had taken longer than necessary because I hadn’t framed the problem well.</p><p>The manager asked what I’d learned.</p><p>I told him that raising a risk was only part of the job. A senior engineer also needed to help the team make a decision under real constraints, even when the available options were imperfect.</p><p>He nodded and moved on.</p><p>A few days later, the recruiter requested references.</p><p>This time, I sent the names of people who’d worked directly with me on the responsibilities the company cared about. I’d spoken with each of them beforehand, and they understood the role and felt comfortable providing an honest assessment.</p><p>The company completed the checks and scheduled a final conversation about compensation.</p><p>I received an offer the following week.</p><p>I accepted.</p><h3>I Still Don’t Know What Happened at Every Company</h3><p>It’s tempting to look back at those sixty-seven days and conclude that my references were responsible for all eight rejections. That would be a convenient explanation, particularly because it would mean my technical performance had been better than the results suggested.</p><p>But I don’t know that.</p><p>Several companies rejected me before requesting references. Others had legitimate reasons to prefer candidates with different experience. I made mistakes during coding interviews, struggled with system design questions, and occasionally failed to communicate my work clearly.</p><p>Even the eighth rejection didn’t prove that Robert’s comments had been the deciding factor. The recruiter said the decision followed the reference checks, but she didn’t explain which concerns mattered or how the hiring team evaluated them.</p><p>What I do know is that I’d spent weeks trying to improve the parts of the interview process I could see. I studied Java, practiced architecture discussions, rewrote my résumé, and rehearsed behavioral questions. I treated references as paperwork that happened after the important decisions had already been made.</p><p>That assumption was wrong.</p><p>A professional reference is another person’s account of what it was like to work with you. It includes technical ability, but it can also include communication, reliability, judgment, and how you behave when things become difficult. Those details may matter considerably to a company hiring someone who will influence architectural decisions and work across teams.</p><p>I still think Robert could have described some situations differently. I also recognize that he experienced our disagreements from a perspective I didn’t fully understand at the time. We were responsible for different things, and the same meeting could look very different depending on which responsibilities mattered most to you.</p><p>I haven’t spoken with him since that conversation.</p><p>I don’t particularly enjoy remembering it, but I no longer assume that someone will recommend me simply because we worked together for several years.</p><p>Before listing a reference now, I ask whether they’re comfortable recommending me for the position. I explain the responsibilities and give them an opportunity to decline. If they have concerns, I’d rather hear them directly than discover them through a rejection email after spending a month interviewing.</p><p>I still have the spreadsheet from those sixty-seven days. The entries contain technical questions, salary ranges, interview feedback, and notes about what I wanted to improve. The eighth company has a longer comment than the others because I added everything I learned after the reference checks.</p><p>The ninth entry says <em>offer accepted</em>.</p><p>For a while, I wanted to delete the earlier rows. They reminded me of a period when I’d spent almost every day wondering whether I was good enough to work as a senior engineer.</p><p>I kept them.</p><p>They remind me that technical interviews reveal only part of what companies are trying to understand. The rest often comes from conversations about how you work, how you handle disagreement, and whether people who know you professionally would choose to work with you again.</p><p>I wish I’d understood that before the eighth rejection.</p><p>It would have saved me several uncomfortable phone calls, although I’m not sure I would have been ready to hear the answers any earlier.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for technical interviews involving Java, Spring Boot, PostgreSQL, and real production problems, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers backend architecture, transaction management, concurrency, and production debugging. For system design interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, reliability, scalability, and explaining technical decisions under pressure.</p><p>I also write about production debugging, system design interviews, and engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in realistic system design practice, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=df2dc3fb0454" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-failed-8-senior-software-engineer-interviews-then-i-found-out-what-my-references-were-saying-df2dc3fb0454">I Failed 8 Senior Software Engineer Interviews. Then I Found Out What My References Were Saying</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Got Rejected From 9 Software Engineer Jobs. The Worst Interview Was the One I Passed]]></title>
            <link>https://medium.com/engineering-playbook/i-got-rejected-from-9-software-engineer-jobs-the-worst-interview-was-the-one-i-passed-5d976d930f23?source=rss-6bdd1f176ebd------2</link>
            <guid isPermaLink="false">https://medium.com/p/5d976d930f23</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Staff Engineer Mindset]]></dc:creator>
            <pubDate>Wed, 11 Nov 2026 18:00:55 GMT</pubDate>
            <atom:updated>2026-11-11T18:01:12.748Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EUWLZVjfkRDLEd8Kyhsbvg.png" /></figure><h4><em>For 54 days, I thought my biggest problem was failing technical interviews. Then a company offered me the job, and I discovered something I hadn’t considered during the entire search.</em></h4><p>The recruiter called at 4:36 on a Tuesday afternoon and told me the engineering team wanted to make an offer. I was standing in a supermarket, holding a carton of milk, and trying to remember whether I’d already paid my electricity bill. After nine rejections in less than two months, I had imagined this conversation enough times that hearing it happen felt strangely ordinary.</p><p>She told me the base salary was $118,000. The company would send the contract that evening, and they wanted me to start within three weeks. I thanked her, stepped outside because the supermarket was too noisy, and asked whether I could speak with the Engineering Manager one more time before accepting.</p><p>There was a pause. She asked whether something was wrong with the offer, and I said the compensation was fine. I just had a question about the team’s on-call rotation that nobody had answered clearly during the interviews.</p><p>She said she’d arrange a call.</p><p>I hung up and looked at the milk in my hand. I’d finally received an offer for a Senior Backend Engineer position, and instead of feeling relieved, I was trying to figure out why everyone had avoided telling me how often engineers got paged at night.</p><h3>The First Rejection Had Been Easy to Explain</h3><p>I’d started looking for a new job after leaving a backend engineering position that had become increasingly difficult to enjoy. The work involved Java, Spring Boot, PostgreSQL, and a collection of internal services that had grown considerably more complicated than anyone originally intended. I was comfortable with the technology, although I knew my system design skills needed work if I wanted to move into a stronger senior role.</p><p>My first interview was with a fintech company. The coding exercise involved implementing a transaction history endpoint, and I made a stupid mistake while handling pagination. I noticed it near the end, tried to correct it too quickly, and introduced another bug.</p><p>The interviewer was polite. He gave me time to explain what had gone wrong, but I could tell I hadn’t demonstrated the level of care the company expected. The rejection arrived two days later, and I didn’t spend much time arguing with it.</p><p>The second interview was harder to accept. I completed the coding round, discussed database indexing with a Staff Engineer, and reached the final system design interview. They asked me to design a notification platform capable of handling millions of messages per day, and I spent too much time discussing Kafka partitions before establishing what delivery guarantees the business actually required.</p><p>The interviewer kept asking what happened when a customer changed their notification preferences while messages were already queued. I answered, but I hadn’t designed the system around that requirement, so every new constraint made the architecture uglier. By the end, I was adding components to solve problems created by components I’d introduced twenty minutes earlier.</p><p>The feedback said I needed to improve how I clarified requirements before proposing a solution.</p><p>That one was fair too.</p><p>I wrote the feedback in a spreadsheet and started preparing more carefully.</p><h3>By the Fourth Interview, I Was Practicing Answers I Didn’t Believe</h3><p>The next few weeks became repetitive. I woke up, checked LinkedIn, submitted applications, answered recruiter emails, and spent evenings reviewing topics I hadn’t thought about since university. I practiced Java concurrency questions while eating dinner and watched system design explanations at twice their normal speed because there never seemed to be enough time.</p><p>One interviewer asked how ConcurrentHashMap worked internally. Another wanted to discuss garbage collection tuning, even though the role involved building REST APIs for an internal business application. A third asked me to design a distributed rate limiter and seemed annoyed when I asked whether the limits were per customer, per API key, or per IP address.</p><p>I started treating every question as something I should already know.</p><p>When I failed an interview, I’d spend the following evening studying the exact topic I’d struggled with. That seemed sensible until I realized I was preparing for the previous company’s interview instead of the next one.</p><p>My notes became ridiculous. I had pages about Java memory models, PostgreSQL execution plans, Kubernetes readiness probes, Kafka consumer rebalancing, and Redis eviction policies. Some of it was useful, but I was collecting technical information faster than I could turn it into practical understanding.</p><p>During the fourth interview, a Staff Engineer asked me to describe a production incident I’d personally investigated. I started explaining a database connection pool problem, then interrupted myself to mention metrics, tracing, transaction isolation, and the importance of identifying the root cause before changing configuration.</p><p>He stopped me.</p><p>“Can you tell me what actually happened?”</p><p>I realized I’d spent almost three minutes describing how a competent engineer should investigate an incident without explaining what I’d done during mine.</p><p>I started again.</p><p>The service had been timing out during peak traffic. We’d initially suspected slow SQL queries, but traces showed that some requests were holding database connections while waiting for an external service. We’d changed the transaction boundaries, tested the failure behavior, and deployed the fix gradually.</p><p>The interviewer nodded and asked why I hadn’t started with that.</p><p>I didn’t have a good answer.</p><h3>The Fifth Rejection Hurt More Than the Others</h3><p>The fifth company was a software business with around two hundred employees. The role matched my experience closely, and the recruiter had been unusually clear about the interview process. There would be a Java coding round, a system design discussion, and a final conversation with the Engineering Manager.</p><p>I passed the first two.</p><p>The final interview was with a manager named Laura. She asked about my previous work, how I’d handled technical disagreements, and what kind of engineering environment helped me perform well. We spent almost an hour discussing a difficult migration I’d worked on and how the team had managed the risks.</p><p>At the end, she asked whether I had any questions.</p><p>I asked about the team’s architecture and how technical decisions were reviewed. She gave thoughtful answers, and I left the call feeling confident enough to tell a friend that I thought an offer was coming.</p><p>Four days later, the recruiter called.</p><p>The company had chosen another candidate.</p><p>I asked for feedback, expecting something about leadership experience or system design. Instead, the recruiter said the team had liked me but believed the other candidate was a slightly better fit for the company’s current priorities.</p><p>That was all.</p><p>I stared at my laptop after the call, looking at the notes I’d taken during the interviews. There wasn’t a technical mistake I could identify or a particular question I needed to study. I’d done reasonably well, and someone else had done better.</p><p>For the first time, I wondered whether I was wasting my time trying to improve every interview.</p><h3>My Bank Account Was Becoming Part of the Interview</h3><p>By the sixth week, I was checking my finances more often than I wanted to admit. I had enough savings to keep looking, but each passing week made the search feel less like a professional decision and more like a problem that needed an immediate solution.</p><p>I started applying to positions I would have ignored earlier. Some offered less compensation than I wanted, while others involved technology I hadn’t used extensively. I told myself I was being flexible, although I knew the real reason was that I was getting nervous.</p><p>A recruiter contacted me about a Senior Backend Engineer role at a company that provided infrastructure for online businesses. The salary range was reasonable, the technology matched my experience, and the job description mentioned ownership of production services.</p><p>I scheduled the first interview.</p><p>The Engineering Manager was named Peter. He was friendly, spoke quickly, and seemed genuinely interested in my experience with payment systems and asynchronous processing. He explained that the company had grown faster than expected and needed engineers who could handle complex production problems without constant supervision.</p><p>I asked how the team organized its work.</p><p>He said they were a small group with considerable autonomy. Engineers were encouraged to take ownership, make decisions, and move quickly when customers needed something.</p><p>That sounded attractive.</p><p>I had spent enough time working in organizations where every small change required several meetings, and the idea of a team that trusted experienced engineers was appealing.</p><p>Peter asked about a production incident I’d handled. This time, I told the story directly. I explained what had failed, what evidence we’d gathered, which assumptions had been wrong, and how we’d verified the fix.</p><p>He seemed satisfied.</p><p>The technical interview went well too.</p><h3>The System Design Interview Was Almost Enjoyable</h3><p>The Staff Engineer asked me to design a service that processed customer events and updated account balances. The system needed to handle duplicate delivery, temporary database failures, and delayed messages from upstream services.</p><p>I started by clarifying the business requirements.</p><p>We discussed which operations needed strong consistency, how events were identified, and what the system should do when a message couldn’t be processed. I suggested a relatively simple architecture built around durable operation records and explicit state transitions.</p><p>The interviewer challenged the design, but the conversation felt collaborative. When he introduced a failure scenario involving a database commit followed by a consumer crash, we discussed how the application would recover without applying the same business operation twice.</p><p>He asked whether I’d introduce Kafka.</p><p>I said I’d consider it if the workload required its capabilities, but I wouldn’t choose it solely because the system processed events. We needed to understand throughput, retention, replay requirements, and the team’s operational experience before making that decision.</p><p>He smiled and said the company already used Kafka extensively.</p><p>I laughed and told him that was useful information, although it didn’t change the reasoning behind the design.</p><p>We finished the interview discussing monitoring and incident recovery. He said the team had been working on improving observability because engineers were spending too much time reconstructing failed workflows from logs.</p><p>I told him that sounded familiar.</p><p>The recruiter called the next day to schedule a final interview.</p><p>For the first time in weeks, I felt as though I was being evaluated on the work I’d actually done rather than my ability to remember answers from a technical interview guide.</p><h3>Nobody Wanted to Talk About On-Call</h3><p>The final interview was with Peter again, joined by another Engineering Manager. We discussed the team’s current priorities, including a migration from several older services to a more consistent platform architecture.</p><p>The conversation was productive until I asked about production support.</p><p>I wanted to know how many engineers participated in the on-call rotation, how often incidents occurred, and what happened when someone was paged outside working hours. Those questions mattered because the job description emphasized production ownership, and I’d worked in teams where that phrase meant very different things.</p><p>Peter said everyone shared responsibility for keeping the platform reliable.</p><p>I asked how frequently engineers were on call.</p><p>He said it depended on the team.</p><p>The other manager explained that they were still improving the rotation and that engineers sometimes helped outside their assigned shifts when incidents required additional expertise.</p><p>I asked whether they had a dedicated incident commander or a formal escalation process.</p><p>Peter said the team was small enough that people generally knew whom to contact.</p><p>I didn’t love that answer, but I also didn’t want to turn the final interview into an argument about incident management. I’d worked in imperfect organizations before, and the company seemed to be making an effort to improve.</p><p>We moved on to compensation.</p><p>The recruiter called two days later with the offer.</p><h3>The Engineer I Contacted Didn’t Tell Me What I Wanted to Hear</h3><p>After receiving the offer, I looked through LinkedIn and found an engineer who’d worked at the company for nearly three years. We had a mutual connection, so I sent him a short message asking whether he’d be willing to answer a few questions about the engineering culture.</p><p>He replied that evening.</p><p>His name was Michael, and he’d left the company four months earlier. He said he was happy to talk, although he warned me that his experience might not reflect every team.</p><p>We spoke the following morning.</p><p>I asked about the backend architecture, the quality of the engineering team, and whether the company invested in improving its production systems. Michael said the engineers were generally capable and that the technical problems were interesting. He’d learned a great deal during his time there.</p><p>Then I asked about on-call.</p><p>He laughed.</p><p>“Did they tell you how it works?”</p><p>I explained what Peter had said.</p><p>Michael was quiet for a moment, then told me that the rotation had been difficult during his final year. Engineers were officially on call for one week out of four, but serious incidents often required help from people who weren’t scheduled. Some services had unclear ownership, and the same engineers were repeatedly contacted because they understood particular parts of the system.</p><p>I asked how often he’d been paged.</p><p>He said it varied, but there had been periods when he was interrupted several nights a week. He’d occasionally spent the morning recovering from an incident and then joined normal project meetings because deadlines hadn’t changed.</p><p>I asked whether the company compensated engineers for on-call work.</p><p>He said there was no separate on-call payment during his time there, although the company had discussed introducing one.</p><p>I thanked him for being candid.</p><p>Before we ended the call, Michael said something that stayed with me.</p><p>“The job itself was good. I just got tired of never knowing when I was actually finished working.”</p><h3>I Asked the Hiring Manager for One More Conversation</h3><p>Peter agreed to speak the following afternoon. I told him I was interested in the position and appreciated the offer, but I wanted a clearer understanding of the production support expectations before making a decision.</p><p>He seemed surprised by how specific my questions were.</p><p>I asked how many pages the team had received during the previous month, how often engineers outside the rotation had been contacted, and whether the company had a plan to reduce recurring incidents.</p><p>Peter said he didn’t have the exact numbers available.</p><p>He explained that the team had experienced a difficult period during a recent migration, but he believed the situation was improving. He also said the company valued engineers who were willing to help when production systems needed attention.</p><p>I agreed that production ownership was part of senior engineering work. I’d responded to incidents outside normal hours before, and I understood that some problems couldn’t wait until morning. But I wanted to know whether the company treated those interruptions as exceptional events or simply accepted them as part of normal operations.</p><p>Peter said the organization was still working toward a more sustainable model.</p><p>I asked whether the company could share its current on-call policy.</p><p>He said there wasn’t a formal document that covered every team.</p><p>That answer made the decision harder.</p><p>I liked the engineering work, and I believed I could contribute. The compensation was good, the interviewers had been thoughtful, and the company was dealing with problems I knew how to solve.</p><p>But I’d spent months looking for a job, and I was about to accept a position without understanding one of its most important working conditions.</p><h3>I Asked for Two Days to Think</h3><p>The recruiter agreed to extend the offer deadline. I spent the next evening reviewing my finances, looking at the job description, and trying to separate what I knew from what I feared.</p><p>The company hadn’t lied to me. Peter had acknowledged that the on-call process needed improvement, and Michael had been careful to explain that his experience might not reflect the current situation.</p><p>Still, the lack of clear answers bothered me.</p><p>I had been so focused on passing technical interviews that I’d barely considered what I should be evaluating in return. During the first nine rejections, I treated every company as an opportunity I needed to earn. I’d studied their technology, researched their architecture, and prepared answers to questions I thought they might ask.</p><p>I rarely spent the same amount of effort understanding whether the job would be good for me.</p><p>That seemed ridiculous when I finally noticed it.</p><p>I had spent years learning how to identify risks in distributed systems. I’d challenge an architecture that relied on undocumented assumptions, unclear ownership, or recovery procedures that existed only in someone’s head.</p><p>Yet I was considering accepting a job where the on-call expectations were explained almost entirely through vague assurances.</p><p>I didn’t know whether the company would be a bad place to work.</p><p>I knew I didn’t have enough information to feel comfortable accepting the offer.</p><h3>I Declined It</h3><p>The recruiter called on Friday afternoon. I thanked her for the offer and explained that I wouldn’t be accepting because I couldn’t get comfortable with the production support expectations.</p><p>She sounded disappointed.</p><p>She asked whether compensation was the issue and said the company might have some flexibility. I told her the salary was reasonable and that increasing it wouldn’t resolve my concerns about the working environment.</p><p>She asked whether I’d reconsider if Peter could provide more information.</p><p>I said I appreciated the offer, but I’d decided to continue my search.</p><p>After the call, I sat at my desk for a while.</p><p>I’d spent fifty-four days trying to get a Senior Backend Engineer offer. I’d failed coding interviews, struggled through system design rounds, and watched recruiters disappear after promising feedback.</p><p>Now I’d rejected the first offer that felt genuinely attainable.</p><p>I wasn’t sure whether I’d made the right decision.</p><p>My bank account certainly didn’t think so.</p><h3>The Next Interview Felt Different</h3><p>Two weeks later, I interviewed with a smaller software company that maintained backend systems for business customers. The Engineering Manager explained the team’s architecture, the services I’d be responsible for, and the main technical problems they wanted to solve during the next six months.</p><p>When he asked whether I had questions, I asked about production incidents.</p><p>He told me the team had a four-person on-call rotation, shared the previous month’s incident statistics, and explained how engineers were compensated for additional work. He also described a recurring database performance issue they were trying to eliminate.</p><p>I asked whether engineers were expected to join normal meetings after spending the night handling an incident.</p><p>He said they were encouraged to take recovery time and that the manager was responsible for adjusting delivery expectations when incidents disrupted planned work.</p><p>I didn’t know whether the company always followed those practices.</p><p>But the manager had concrete answers, and he didn’t seem uncomfortable discussing the problems.</p><p>The technical interviews were challenging. I made mistakes, asked questions, and explained my reasoning without trying to sound like I’d memorized a system design textbook.</p><p>The company made an offer three weeks later.</p><p>The salary was slightly lower than the previous one.</p><p>I accepted.</p><h3>I Still Think About the Offer I Turned Down</h3><p>I don’t know whether the first company improved its on-call rotation. It might have become an excellent place to work, and I might have enjoyed the role despite the uncertainty. Michael’s experience was only one perspective, and Peter had seemed sincere about wanting to improve the engineering environment.</p><p>I also know that rejecting the offer was a risk.</p><p>I had been unemployed long enough that another month without income mattered. There was no guarantee the next company would hire me, and I couldn’t predict whether I’d regret the decision.</p><p>But the experience changed how I approached interviews.</p><p>For fifty-four days, I’d treated rejection as evidence that I needed to become a better candidate. Sometimes that was true. I’d made technical mistakes, struggled to communicate clearly, and occasionally prepared for the wrong things.</p><p>Other times, the company simply preferred someone else.</p><p>What I hadn’t considered was that passing an interview didn’t automatically mean I should accept the job.</p><p>I still prepare carefully for technical rounds. I review Java, practice system design, and think through production incidents I’ve handled. I want interviewers to understand what I can contribute, and I don’t expect companies to hire me simply because I’ve worked with their technology before.</p><p>But I also ask about the parts of engineering work that rarely appear in job descriptions.</p><p>I want to know who gets called when a service fails at midnight, how the team handles recurring incidents, and whether managers change delivery expectations when production work consumes an engineer’s week.</p><p>Those answers tell me something about the job I’m actually applying for.</p><p>I still have the spreadsheet from those fifty-four days. The first nine entries are marked <em>rejected</em>, with notes about technical questions, interview feedback, and the mistakes I wanted to avoid repeating.</p><p>The tenth entry says <em>offer declined</em>.</p><p>For a while, I considered changing it because seeing those words after so many rejections made me uncomfortable. I’d worked hard to receive an offer, and the idea of turning one down felt almost irresponsible.</p><p>I left it as it was.</p><p>The interview had gone well. The company wanted to hire me, and I’d finally demonstrated the technical experience I’d been struggling to communicate for weeks.</p><p>That part of the process had been a success.</p><p>I just didn’t want the job badly enough to ignore what I’d learned about it.</p><h3>Resources for Senior Backend Engineers</h3><p>If you’re preparing for technical interviews involving Java, Spring Boot, PostgreSQL, and real production problems, my <a href="https://devrimozcay.gumroad.com/l/epxiu">Senior Java &amp; Spring Boot Engineering OS</a> covers the engineering decisions behind reliable backend systems. For architecture interviews, the <a href="https://devrimozcay.gumroad.com/l/oordy">Senior &amp; Staff System Design Interview OS</a> focuses on distributed systems, scalability, failure handling, and explaining technical trade-offs under pressure.</p><p>I also write about production debugging, system design interviews, and engineering careers on <a href="https://substack.com/@devrimozcay1">Substack</a>. If you’re interested in practicing realistic system design scenarios, you can request access to the <a href="https://docs.google.com/forms/d/e/1FAIpQLScLD53xFU73sirxXmKFfL9-M7FGL_5mM6a8_B0qQdaYce2atA/viewform?usp=header">ProdRescue System Design Lab private beta</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5d976d930f23" width="1" height="1" alt=""><hr><p><a href="https://medium.com/engineering-playbook/i-got-rejected-from-9-software-engineer-jobs-the-worst-interview-was-the-one-i-passed-5d976d930f23">I Got Rejected From 9 Software Engineer Jobs. The Worst Interview Was the One I Passed</a> was originally published in <a href="https://medium.com/engineering-playbook">Engineering Under Pressure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>