Interview guides · Baker Hughes
Baker Hughes Software Engineer Interview Guide
Baker Hughes Software Engineer interview guide: video screen, OOP, data structures, language fundamentals, STAR prompts and a 7-day prep plan.
The 60-second brief
Baker Hughes builds industrial software. Candidates describe platforms that monitor subsurface operations, track turbomachinery performance, automate drilling services and manage industrial assets. The Software Engineer role is described as spanning low-latency applications for real-time telemetry processing, cloud services for enterprise operations, and desktop or embedded tools used in the field. Engineers work with hardware designers, field engineers, product managers and cloud architects. Day to day, candidates describe feature development, code reviews, unit tests, documentation, bug fixing, tuning data processing, CI/CD pipeline upkeep and compliance with corporate cybersecurity standards. The role also involves supporting older software while applications move toward microservice or cloud-native designs.
This guide is for candidates interviewing for a Software Engineer position at Baker Hughes, from early-career applicants to experienced hires. It covers the process candidates report (a recorded video screen, live technical interviews, and managerial and HR conversations), the three technical areas they describe (object-oriented principles, data structures and algorithms, language fundamentals), four reported behavioral prompts, and the requirements listed for the role: a core language such as C++, Java, C# or JavaScript/TypeScript, relational databases such as PostgreSQL, SQL Server or MySQL, and Git. It does not tie any question to a specific round, because candidates do not report that.
Candidates report a recorded video screen (HireVue or Sova), then one or more live technical interviews over Microsoft Teams or on site, then managerial and HR conversations. Early-career or some office loops add an Assessment Day with group challenges and panel interviews.
Focus areas
- Behavioral Interviewing (STAR method)
- Engineering Fundamentals: Dynamics and Vibrations
- Problem Solving
Overview
The reported technical content is fundamentals, not puzzle-solving. Candidates describe object-oriented principles in C++, Java or a similar language, practical use of strings, arrays, linked lists and hash tables with basic search and sort, and language mechanics: memory allocation, pointers or references, threading basics and error handling. They describe algorithmic questions as essential data structures and basic logic rather than competitive-programming problems. Preparation therefore means being able to write these structures from memory in your strongest language and explain the cost of each operation.
The work itself is industrial: real-time telemetry, field tools, cloud services, and legacy code moving toward microservices. That makes reliability habits worth showing in your answers: how you test a change, how you handle failure and bad input, and how you review someone else's code. You do not need domain knowledge of drilling or turbomachinery to answer a data-structure question, but a short, accurate description of what the company's software does helps when you are asked why you want the role.
Candidates also report a resume deep dive on every language, database and project you list. Build a table before the loop: each technology, one design trade-off you made, one thing that went wrong. For the behavioral side, the four reported prompts cover a hard project challenge, competing stakeholder priorities, workload and precision under deadlines, and a mistake you corrected. Candidates describe ownership, adaptability and ethical decision-making as themes, so every story needs the action you personally took and a result you can state.
Where to focus your preparation
Candidates describe a staged process rather than a list of named rounds, so this guide treats it as one preparation focus: the video screen, the live technical conversations and the final managerial and HR discussions.
Preparation focus
Candidates report that screening starts with an automated video assessment through a platform such as HireVue or Sova, where you answer pre-recorded prompts within set preparation and response times. Successful candidates then move to one or more live technical interviews, held remotely over Microsoft Teams or in person, and finish with managerial and HR discussions. For early-career roles or certain offices, an Assessment Day or Selection Event is reported, combining group problem-solving, technical assessments and panel interviews under timed conditions. Ask your recruiter which of these applies to you, and whether you will write code live. Prepare in three layers: spoken STAR answers for the video prompts, working fundamentals in your main language for the technical conversations, and a resume audit for questions on your listed projects.
What to demonstrate
- Command of your primary language, object-oriented principles and core data structures
- Reasoning aloud about trade-offs, edge cases and complexity before and while you code
- Depth on every project, database and technology listed on your resume
- Structured, concise communication of past work using the STAR method
How to prepare
- Outline and rehearse a spoken STAR answer for each of the four reported behavioral prompts, using scratch-paper bullets rather than a script
- Write a small class hierarchy in C++ or Java and be ready to point to abstraction, encapsulation, inheritance and polymorphism in it
- Code from memory: linked-list reversal, a hash-map frequency count, binary search, merge sort and a string manipulation task, stating time and space cost for each
- Audit your resume: for each technology, write one trade-off, one failure and one thing you would change
Where candidates lose points
Listing a language or database you cannot explain below the surface
Candidates report questions on every item on the resume. For each technology, prepare how it manages memory or storage, one design trade-off you made, and one bug you hit. Remove anything you could not discuss for five minutes, such as a C++ project when you cannot explain virtual dispatch or destructor order, or SQL Server listed with no view on indexes.
Reciting abstraction, encapsulation, inheritance and polymorphism as four definitions with no code
Tie each pillar to a line in a hierarchy you wrote: a base interface, private state behind a validating setter, a derived class overriding a method, and a collection of base references calling the overrides. In C++ mention that dynamic dispatch needs virtual functions and a virtual destructor. Also prepare when composition is better than inheritance.
Typing a solution on the linked-list, array or string question without stating the approach, edge cases or complexity
Say the plan first, then the cost: for example, reversing a list iteratively is O(n) time and O(1) space. Name the edge cases out loud before coding: empty input, a single node, duplicates, null references, an off-by-one in a binary search bound. After coding, trace one small example by hand.
Telling a behavioral story in the first person plural with no result, or blaming others in the mistake prompt
Fix the structure: a Situation and Task in two sentences, most of the time on the Action you personally took, then a Result with a number (defects found, latency, hours saved). For the mistake story, state what you got wrong, how you found it, how you corrected it and what check you added so it cannot recur.
Treating the recorded video screen like a live chat and rambling past the response limit
Candidates report set preparation and response times, with a 2 to 3 minute limit per prompt in some cases. Use the preparation time to write three or four bullets, record yourself at home against a timer, and practice ending on the result. Check your microphone, lighting and background before starting.
Questions & practice
Data Structures & Algorithms – Practical implementation of strings, arrays, linked lists, hash tables, and fun
Medium · Core Programming & Object-Oriented Softw
Data Structures & Algorithms – Practical implementation of strings, arrays, linked lists, hash tables, and fundamental search/sort algorithms.
Approach
- Strings and arrays: for two-sum, a hash map from value to index gives O(n) time and O(n) space. Sorting first and then walking two pointers takes O(n log n) time and O(1) extra space, but you lose the original indices. For anagram checks, compare frequency counts in O(n). In Java, build strings with a StringBuilder, because += in a loop copies the string each time and goes quadratic.
- Linked lists: reverse in place with prev, curr and next pointers in O(n) time and O(1) space. Find a cycle with Floyd's slow and fast pointers. A dummy head node removes the special case of deleting or inserting at the head. Say the edge cases out loud: an empty list, a single node, and k larger than the length.
- Hash tables: insert and lookup average O(1) and degrade to O(n) when keys collide heavily. Collisions are handled by chaining or open addressing, and the table resizes once a load factor is crossed (0.75 by default in Java's HashMap), which keeps inserts amortised O(1). Keys need consistent equals() and hashCode(), and must not be mutated while they are in the map.
- Searching: binary search on sorted input is O(log n). Compute mid as lo + (hi - lo) / 2 so it cannot overflow, and pick one interval convention (closed or half-open) and keep to it, which avoids off-by-one loops. Know the variant that returns the first index whose value is at least the target.
- Sorting: merge sort is O(n log n) in every case, stable, and uses O(n) extra memory. Quicksort averages O(n log n) and sorts in place, but hits O(n^2) on bad pivots, so use a random pivot or introsort. Insertion sort wins on small or nearly sorted input. C++ std::sort is not stable, but std::stable_sort is. Java's Arrays.sort uses dual-pivot quicksort for primitives and stable TimSort for objects.
Follow-up
- Implement a hash map with chaining from scratch. What happens to the existing entries when it resizes?
- After Floyd's algorithm finds a cycle, how do you locate the node where the cycle starts, and why does that work?
- When would you choose merge sort over quicksort, for example for linked lists or when stability matters?
Language Fundamentals – Memory allocation, pointer arithmetic or reference management, multi-threading basics,
Medium · Core Programming & Object-Oriented Softw
Language Fundamentals – Memory allocation, pointer arithmetic or reference management, multi-threading basics, and error handling mechanics.
Approach
- Memory allocation: stack objects die when their scope ends, and heap objects live until they are freed or collected. In C++, use RAII so that std::unique_ptr (sole owner, move-only) or std::shared_ptr (reference-counted) frees the object. A cycle of shared_ptr never frees; break it with weak_ptr. Java's garbage collector reclaims anything unreachable, including cycles, but still leaks through references kept too long, such as static collections or listeners never removed.
- Pointers and references: p + n advances by n * sizeof(T) bytes, and it is only valid inside the same array or one past its end. Dereferencing that one-past-the-end position, a dangling pointer after delete, or a pointer freed twice is undefined behaviour. A C++ reference cannot be null or reseated. Java passes object references by value, so reassigning a parameter does not change the caller's variable.
- Threading basics: a data race is unsynchronised access to shared data where at least one access is a write. count++ is a read-modify-write and loses updates across threads. Fix it with a mutex (std::lock_guard, or synchronized in Java) or an atomic type (std::atomic, AtomicInteger). Java volatile gives visibility but not atomicity, and C++ volatile is not a threading tool at all.
- Deadlock comes from two threads taking the same locks in opposite orders. Prevent it with one global lock order, by locking several mutexes together with std::scoped_lock, or with tryLock and a timeout. Keep critical sections short, and never call unknown code while you hold a lock.
- Error handling: C++ exceptions unwind the stack and run destructors, so RAII guarantees cleanup. Destructors should not throw, and they are implicitly noexcept since C++11. Name the basic, strong and nothrow exception-safety guarantees. In Java, separate checked and unchecked exceptions, and use try-with-resources for AutoCloseable resources instead of hand-written finally blocks.
Follow-up
- Two shared_ptr objects point at each other. Is the memory ever freed, and how would you change the design?
- A service hangs under load and you suspect a deadlock. How do you confirm it, for example with a jstack thread dump or a gdb backtrace of every thread?
- When would you return an error code or an optional value instead of throwing an exception?
Identify the heaviest tenants in a five-minute window under memory pressure
Medium · top-k · heavy hitters · streaming
The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.
Approach
- Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
- Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
- State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
- Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.
Follow-up
- The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
- Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?
Write the update path that detects a concurrent edit
Medium · optimistic concurrency · transactional outbox · audit history
resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.
Approach
- One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
- Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
- State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
- Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.
Follow-up
- A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
- Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?
Explain why the owner filter ignores the listing index
Medium · composite index · query plans · sort elimination
The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.
Approach
- Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
- For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
- Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
- Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.
Follow-up
- 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
- A dashboard runs this for 40 owners in one page load. What changes about the design?
Object-Oriented Programming (OOP) Principles – Understanding abstraction, encapsulation, inheritance, and poly
Medium · Core Programming & Object-Oriented Softw
Object-Oriented Programming (OOP) Principles – Understanding abstraction, encapsulation, inheritance, and polymorphism in C++, Java, or modern object-oriented languages.
Approach
- Define each principle with one concrete class rather than a textbook line. Encapsulation: an Account with a private balance that changes only through deposit() and withdraw(), and both reject negative amounts, so the invariant holds. Abstraction: callers depend on a Shape interface with area() and never see how each subclass computes it.
- Inheritance models an is-a relationship and lets you reuse code, but it couples the subclass to the base class's internals. Bring up the Liskov substitution problem: a Square that extends Rectangle breaks callers that set the width and height independently. Then say when you would use composition instead, for example a Strategy object injected through the constructor.
- Separate the two kinds of polymorphism. Runtime polymorphism is dynamic dispatch through a base reference: in C++ only methods marked virtual dispatch dynamically, while in Java every instance method does unless it is static, final or private. Compile-time polymorphism is overloading, plus templates in C++ or generics in Java.
- Name the C++ pitfalls. A polymorphic base class needs a virtual destructor, because deleting a derived object through a base pointer without one is undefined behaviour. Passing a derived object by value as its base type slices off the derived part, so pass by reference or pointer.
- Contrast Java abstract classes with interfaces. An abstract class can hold state and constructors, but a class can extend only one. A class can implement many interfaces, and since Java 8 an interface can carry default methods. Pick by whether you are sharing state or only a contract.
Follow-up
- Why does deleting a derived object through a base-class pointer misbehave without a virtual destructor, and how do you fix it?
- What is the difference between overloading and overriding, and which one is resolved at compile time?
- Give a design where you replaced inheritance with composition. What did that make easier to test or change?
Shard by tenant when one tenant outgrows a single shard
Hard · sharding · hot partition · routing
One primary holds resource, resource_revision, outbox_event and idempotency_key for every tenant and is at its write ceiling at 1.2k writes/second. tenant_id leads every index. Shard across eight primaries. One tenant holds 22% of all rows and by itself exceeds a single shard's write capacity. Design the routing, the split of that tenant, and the online move of a tenant between shards with writes continuing. State what breaks for queries that are tenant-scoped today, and exactly what a write must do when it arrives at the old shard after the cutover.
Approach
- Route on a unit smaller than a tenant from the start. Make the routing key (tenant_id, bucket) with a fixed bucket count - 64 over eight shards - and keep a directory mapping each (tenant_id, bucket) to a shard, carrying a version and cached in every service. An ordinary tenant has all 64 buckets pointing at one shard and behaves exactly as it does today; only the hot tenant has its buckets spread. Hashing tenant_id alone spreads tenants evenly, gives you no way to move one, and has no answer at all for a tenant larger than a node. The bucket count is the part you cannot change later without rehashing rows, so pick it well above the shard count and rebalance by moving buckets, not by re-bucketing.
- For the tenant that exceeds one node, its buckets must land on different shards - that is the whole point of bucketing it, and buckets confined to its own shard would rename the rows while leaving every write on the node whose ceiling it already exceeds. Size it from measured numbers rather than from its row share: 22% of rows says nothing about write rate. The current primary tops out near 1.2k writes/second on this hardware and workload, so a tenant peaking at W writes/second needs its buckets spread over at least ceil(W / headroom-per-shard) shards, where the divisor is the share of each shard's ceiling you are willing to give it while that shard still serves other tenants - not the full 1.2k. Size on its peak, not its mean.
- Fix the co-location invariant at the right grain. What must commit in one transaction is a resource, its resource_revision row and its outbox_event row, so the bucket is a property of the resource: derive it once at creation and stamp it into resource_id, and every later revision and event routes with its parent for free. Per-tenant co-location was never the requirement, and mistaking it for one is what makes a tenant look unsplittable. What genuinely breaks is an invariant spanning two resources of one tenant - a per-tenant counter, uniqueness across its resources - which now needs either a home-shard table or two-phase commit, and 2PC at this write rate is not a serious option.
- Keep the idempotency constraint arbitrating, because it is now enforced per shard. PRIMARY KEY (tenant_id, idempotency_key) only continues to reject a retry if the same key always lands on the same shard, so derive the create-path bucket from hash(tenant_id, idempotency_key) and mint the new resource_id inside that bucket, which also puts the key row and the resource it guards in one transaction. A bucket chosen from anything that differs between a request and its retry - a timestamp, the worker id, a client-supplied resource id - splits one key across two shards, both inserts succeed, and the write endpoint's retry safety is silently gone.
Follow-up
- The fence lasts 90 seconds instead of 4 because the final delta keeps growing. What is happening, and what do you do while the tenant is fenced?
- Two tenants must merge into one account. What does that cost under this scheme, and which step is not reversible?
Exports duplicate a row range about once a week
Hard · leases · clock skew · idempotency
Roughly once a week an export writes a file containing a duplicated range of rows. The affected job_run rows show attempt = 1, status = succeeded, one started_at, and a lease_owner naming a different host from the one whose logs show the job starting. Leases last 30 seconds and are heartbeated every 10 from inside the handler; lease_expires_at is computed on the worker and compared against the database's now(). Find the mechanism, and give a fix that holds even if you cannot fix the clocks.
Approach
- Start from the fact that eliminates the obvious answer. attempt = 1 means no retry was recorded, so this is not a re-run after failure; two workers ran the same row concurrently and the takeover path never touched the counter. lease_owner naming a host other than the one that started the job is the same statement from the other side.
- Enumerate the mechanisms that cause a premature takeover, then find the signal that separates them. Either the lease genuinely expired because the heartbeat did not fire, which is what happens when the heartbeat runs on the handler's own thread and the handler makes a long blocking call, or it only appeared expired because two clocks disagree, since lease_expires_at is written from the worker's clock and evaluated against the database's. The discriminator is the distribution: incidents clustered on the longest exports indict the heartbeat, incidents clustered on one host indict skew. Measure both, and measure each host's offset against the database directly.
- Read the reclaim query precisely. In PostgreSQL now() is transaction start time, not statement time, so a reclaimer holding a long transaction compares against an older timestamp than expected; clock_timestamp() is the statement-time function. This is worth ruling in or out before you redesign anything, because it changes which rows look expired.
- Remove the second clock rather than trying to synchronise it. Issue and extend the lease in the database, with lease_expires_at = now() + interval '30 seconds' in both the claim and the heartbeat, so exactly one clock is ever compared and worker skew stops mattering to this predicate.
Follow-up
- The displaced worker has already streamed half the file to object storage. What makes that side effect safe to repeat?
- You now count takeovers. What alert fires on that counter, and at what threshold?
Suggested practice checklist
The plan follows the loop candidates report: confirm the format and audit your resume, then cover object-oriented principles, data structures, language fundamentals, databases and Git, behavioral stories, and a full dry run.
Day 1 — Confirm the format and audit your resume
- Email your recruiter to ask whether the video screen is HireVue or Sova, whether live rounds include coding, whether an Assessment Day applies to your location or level, and what stages follow
- List every language, database and project on your resume with one trade-off and one failure for each
- Remove or flag any item you could not discuss at the design level
Deliverable: A sent recruiter email and a resume audit sheet with a trade-off and a failure per technology.
Day 2 — Object-oriented principles in your main language
- Write a small hierarchy in C++ or Java, such as a base sensor type with two implementations that override a read method, with private state behind a validating setter
- Annotate the code to show each of abstraction, encapsulation, inheritance and polymorphism, including virtual functions and a virtual destructor in C++ or an interface in Java
- Write a short answer on composition versus inheritance and on abstract class versus interface
Deliverable: A compiling hierarchy with annotations for all four pillars, plus a written composition-versus-inheritance answer you can speak in two minutes.
Day 3 — Data structures and algorithms by hand
- Write from memory: iterative linked-list reversal, Floyd cycle detection, a hash-map frequency count, binary search, and merge sort
- Compare merge sort (stable, O(n log n), extra memory) with quicksort (O(n log n) average, O(n squared) worst case) and write when each fits
- Add unit tests with edge cases: empty input, one element, duplicates, null
Deliverable: Five working functions with unit tests, a stated time and space cost for each, and one attempt at the practice question.
Day 4 — Language fundamentals: memory, threads, errors
- Write a short note on stack versus heap, and RAII with smart pointers in C++ or references and garbage collection in Java
- Show that indexing p[i] equals *(p + i), scaled by element size, and write when a dangling or null reference arises
- Write a program where two threads increment a shared counter without synchronization, observe lost updates, then fix it with a mutex, synchronized block or atomic
- Write how you clean up resources on error: exceptions versus return codes, RAII or try-with-resources
Deliverable: A race-condition program before and after the fix, plus a one-page note on memory ownership and error handling.
Day 5 — Databases, tests and Git
- Work the practice question on an update path that detects a concurrent edit
- In a throwaway repository, create two branches that conflict, resolve the conflict, and write a pull request description
- Review your Day 3 code as if you were the reviewer and write three comments
Deliverable: A query-plan comparison, an update statement that detects concurrent edits, a resolved merge, and three code-review comments.
Day 6 — Behavioral stories and recorded answers
- Outline STAR stories for the four reported prompts: a project challenge, competing stakeholder priorities, workload and precision under deadlines, and a mistake you corrected
- Record yourself answering each in a 2 to 3 minute limit after writing only bullet points
Deliverable: Four STAR outlines, four timed recordings, and a result with a number in each story.
Day 7 — Full dry run
- Record answers to two behavioral prompts under the time limit, then explain your OOP hierarchy aloud as if to a panel
- Solve a fresh linked-list or string problem aloud, with edge cases and complexity, and defend one resume project in depth
- Write three questions about the team's stack, testing and deployment practice to ask at the end
Deliverable: Two recordings, one narrated solution with stated complexity, a resume-project walkthrough and three written questions for the team.
STAR stories for the video screen and panel
Candidates report structured behavioral assessments, first in the recorded video screen and again in later conversations, with ownership, adaptability and ethical decision-making named as themes. The role involves working with hardware, field and product colleagues, so stories that show how you resolved disagreement and checked your work travel well. Reported prompts come first below. In each story, spend most of the time on what you personally did and finish with a result you can quantify.
- Tell me about a time you faced a significant challenge on a project and how you resolved it. Show the diagnosis step, not only the fix.
- Describe a situation where you had to work with cross-functional stakeholders who had competing priorities. State what each party needed and how you reached a decision.
- How do you manage your workload and maintain technical precision under tight deadlines or high-pressure environments? Name a concrete check, such as tests or a review, that you kept under pressure.
- Give an example of a mistake you made in a previous software project, what you learned from it, and how you corrected it. Own the mistake and name the safeguard you added.
- Tell me about a time you had to explain a technical decision to a colleague outside software, such as a hardware or field engineer.
Narrate an outage you owned from page to postmortem
Hard · incident response · blast radius · postmortems
Pick an incident you personally drove, ideally one where writes were affected rather than reads. In six to eight minutes: state the symptom as it first appeared on a dashboard, the blast radius you established before you knew the cause, the mitigation you applied and when, the mechanism you eventually proved, and the follow-up that would prevent a repeat. Bring numbers: error rate, tenants affected, minutes to mitigate, minutes to resolve. If you cannot name what you measured, choose a different incident.
Approach
- Open on the signal rather than the cause: which metric at which percentile moved, on which service, at what time, so the listener follows the same evidence you had rather than a conclusion you already reached.
- Separate mitigation from diagnosis out loud. State what you did to stop the bleeding (flag off, shed traffic, drain a lease, roll back a deploy) and say plainly that you did it before the mechanism was known, because those are two jobs with different deadlines.
- Establish blast radius in countable terms: how many tenants, how many writes, and crucially whether the effect was loss or only delay. An append-only revision table or a pending outbox row means the change survived and the projection was merely behind, which is a repair rather than a data-loss incident.
- Prove the mechanism instead of asserting it. Name the trace span that grew, the plan that flipped to a sequential scan, the lease that expired, plus one alternative you ruled out and the signal that stayed flat while you ruled it out.
Follow-up
- What would you do differently in the first five minutes, given the same dashboard and no more information?
- Which follow-up action did you deliberately not take, and why was dropping it the right call?
Reverse your own decision and price the reversal
Medium · reversibility · measurement · migrations
Describe a technical decision you made and later reversed. Pick one that cost something: a service you split and merged back, a cache you added and removed, an index you created that pushed the planner onto a worse plan, a projection you rebuilt from scratch. State what you believed when you decided, the measurement that changed your mind, how long the wrong version ran in production, and what the reversal cost in migrations, dual writes, and a deprecation window for callers you did not own.
Approach
- State the original rationale without irony, in the version you would still defend given what was known then. If it is not defensible, the story is about carelessness rather than judgement, and a different example serves you better.
- Give the measurement that moved with a before and after: the p99 that did not improve, the cache hit rate that sat at 40%, the plan that flipped to a sequential scan once the table passed a size you can name.
- Cost the reversal in steps, not adjectives: expand-and-contract deploys, the dual-write window, the callers who had to be notified, the rows already written in the wrong shape that had to be backfilled or abandoned.
- Distinguish reversal from rewrite by naming what you kept. Most good reversals preserve the schema or the interface and undo one decision inside it, which is also why they were affordable.
Follow-up
- What in that decision was irreversible, and did you know it was irreversible when you made it?
- How did you tell the people who had already built on top of the original decision?
Ship under a deadline and bound the debt you chose
Medium · pagination · technical debt · tradeoffs
You have four days to ship a tenant-facing listing endpoint. The version you would defend uses keyset pagination over (tenant_id, status, updated_at DESC, resource_id DESC); the version you can finish uses LIMIT/OFFSET with no matching index. Describe a deadline call you actually made of this shape: what you shipped, what you knowingly deferred, how you bounded the damage with a mechanism rather than an intention, and the specific numeric condition that would force the follow-up. Name who you told and where you wrote it down.
Approach
- Name the deferred failure precisely instead of calling it slow. OFFSET n makes the database produce and discard n rows, so cost grows with page depth; without an index matching the sort, every matching row is read and sorted before the limit applies; and rows inserted between two page fetches shift across the boundary so items are skipped or repeated with nothing in the response to signal it.
- Bound the blast radius with something mechanical rather than a promise: cap maximum page depth, cap page size, restrict the endpoint to one internal caller, or keep it behind a flag. State which failure each cap removes and which it leaves standing.
- Attach a number to the trigger and wire it to an alarm: the first tenant crossing N resources, or the endpoint's p99 crossing its share of the 400 ms budget, so the debt announces itself instead of waiting to be remembered.
- Write it where the next engineer looks, which is the code and the ticket, not a chat message: what was deferred, why, the cap, and the trigger.
Follow-up
- At what page depth does the offset version breach your latency budget, given your page size and row counts?
- What breaks first when you switch to keyset pagination later, and what does a client holding an old page token see?