Energy Solutions · Software Engineer
Updated · 2026-09-24

Energy Solutions Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

As a Software Engineer at Energy Solutions, you play a vital role in building and maintaining the digital infrastructure that powers large-scale clean energy programs, solar initiatives, and sustainability efforts. Your day-to-day work directly impacts how application processing, quality control systems, and renewable energy software platforms operate at scale. You will bridge the gap between complex energy data and user-facing applications, ensuring that business units can efficiently track, manage, and optimize green energy initiatives across the United States.

Most rounds test how you handle an under-specified problem more than what you recall. A wrong first approach you correct out loud is recoverable; a constraint you assumed silently and were never given is the expensive mistake.

Energy Solutions candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Keep a site operating during a network partitionReserve inventory without overselling under concurrent allocationMake every external side effect safe to retry

42 min read

Browse Software Engineer questions

See the practice prompts

16Practice promptsAcross five skill areas
3With worked solutionsIncluded in the practice prompts

As a Software Engineer at Energy Solutions, you play a vital role in building and maintaining the digital infrastructure that powers large-scale clean energy programs, solar initiatives, and sustainability efforts. Your day-to-day work directly impacts how application processing, quality control systems, and renewable energy software platforms operate at scale. You will bridge the gap between complex energy data and user-facing applications, ensuring that business units can efficiently track, manage, and optimize green energy initiatives across the United States.

This position sits at the intersection of modern software development and environmental impact, making it both technically challenging and deeply rewarding. You will collaborate closely with product managers, quality control engineers, and project leaders to design robust technical solutions. Whether you are developing Salesforce integrations, scaling backend workflows, or refining data pipelines, your contributions help drive mission-critical sustainability projects forward.

Expect a fast-paced environment where problem-solving and adaptability are paramount. While the interview process can be rigorous and demanding, the work offers a tangible way to apply your software engineering expertise to combat climate change. You will find that success here requires not just technical proficiency, but a genuine passion for the renewable energy mission and a collaborative mindset.

01

Recruiter Conversation

reported

The title covers product work, platform work, infrastructure, mobile and frontend, and those are different jobs with different loops behind them. A screening call is the cheapest place to find out which one the seat is, and asking reads as experienced rather than fussy. The questions that separate them: what the team is on call for, what the last three projects were, and whether any round happens inside an existing repository instead of a blank file. Then say which of that you have done and which you have not. Claiming the whole posting is the fastest way to be found out one round later.

What to demonstrate

  • Whether you can locate your experience inside one flavour of the role honestly instead of claiming the entire requirements list
  • Whether you name what you have not done, which an experienced screener reads as a level signal and can plan the loop around
  • Whether what you want next matches what the seat is: someone who wants greenfield work landing on a team that mostly operates an existing system is a hire that leaves within the year

How to prepare

  • Mark every line of the posting as done, adjacent or new, and write one sentence for each adjacent line naming the closest thing you actually built
  • Split your last two years into rough percentages across feature work, operating and debugging live systems, and design or review, so a question about scope gets numbers rather than adjectives
  • Bring three questions that discriminate between seats: what the team is paged for, how much of the work is changing existing code versus standing up something new, and what shipped in the last quarter
PracHub interview research ↗
02

Technical Screens

reported

Input bounds are the part of the prompt most often skimmed, and they usually contain the answer. They tell you which complexity class is admissible, which narrows the search before you have thought about the problem itself. As a rough planning figure, a compiled language does on the order of 10^8 simple operations per second and an interpreted one roughly an order of magnitude less. So n up to about twenty admits enumerating subsets, a few thousand admits a quadratic pass, and a million admits neither: you need near-linear, or linear with a log factor. If the bounds are missing, ask for them.

What to demonstrate

  • Whether the approach is justified by the stated input size rather than by whichever pattern you recognised first
  • Whether you ask about the properties that change the algorithm: whether the input arrives sorted, whether duplicates occur, whether values are bounded integers, whether it all fits in memory
  • Whether you can name the bottleneck in your own solution and what would remove it, even when you deliberately leave it in place
  • Whether a claimed speedup is real, since memoising a recursion only helps when subproblems genuinely overlap and the state can be keyed cheaply

How to prepare

  • For each algorithm you rely on, write down the largest n it handles in roughly a second, then check two of those figures by timing them in the language you will actually type in
  • For two weeks, write one line naming your target complexity and the bound that justifies it before you write any code, then compare that line with what you ended up submitting
  • Practise the conversion backwards: given a required O(n log n), list the mechanisms that get you there (sorting, a heap, an ordered map, divide and conquer) and choose by what the problem needs to query, not by what you used last
PracHub interview research ↗
03

Take-home Challenge

reported

A deadline measured in days usually covers work measured in hours, and treating the calendar as the effort budget is what produces an over-built submission. Structure out of proportion to the problem reads as poor judgement about cost: an interface with one implementation, a configuration layer for values that never vary, a dependency added for something the standard library already does. The opposite failure, one long function carrying everything, is read the same way. Aim for the least structure that lets you write the tests you want, and record the abstraction you did not build alongside the condition that would justify it.

What to demonstrate

  • Whether each layer, interface and configuration point earns its place against the problem as stated, rather than against a larger imagined version of it
  • Whether every third-party dependency is doing work you would not want to write and maintain, given that each one costs the reviewer an install and a version to trust
  • Whether the work is finished, since a narrower scope completed with tests and a README reads better than a broader one left half-wired
  • Whether the things you chose not to build are recorded, so an omission reads as a decision rather than as something you ran out of time for

How to prepare

  • Write down what done means as a list of behaviours before you open an editor, then stop at that line even when calendar time is left
  • Open a past project of yours, delete every abstraction that has exactly one implementation and one caller, and read the result; that tells you where your own proportion line actually sits
  • Before adding a dependency, write down what it saves you and what the standard library would cost instead, and keep it only when that comparison favours it
PracHub interview research ↗
04

Panel Interviews

reported

Coding rounds mostly set a floor. They decide whether you clear the bar, not where you land on the ladder. Level tends to come out of the design discussion and the ownership stories, so the question worth auditing beforehand is whether the scope you describe matches the scope of the job. Work that stops at your own service, or a story whose hard part was writing the code rather than getting several people to agree on an interface, reads a level below where you think you are interviewing, and that gap is usually resolved downwards.

What to demonstrate

  • Whether the largest thing you describe owning ran end to end — the decision, the migration path, the rollout, and what you did when it went wrong — or stopped at the change you merged
  • Whether design answers include what you would not build, what you would defer, and what you would measure before committing, rather than only what the boxes are
  • Whether a disagreement in a story was settled with something checkable — a benchmark, a prototype, a written proposal — instead of by seniority or by waiting it out
  • Whether you can say which calls you made alone and which you escalated, and why the line sat where it did

How to prepare

  • Write your largest piece of owned work as a timeline of decisions — who decided what, when, and what you did when the plan broke — then delete every sentence whose subject is "we" and see how much survives
  • Take one system you know well and drill the migration answer: how old and new paths run side by side under live traffic, how you compare their outputs, what the rollback is once writes are going to both, and which step you would not automate
  • Map each line of the ladder in the job posting to a specific thing you have done, find the line you cannot support, and prepare the closest evidence you have plus an honest account of the gap
PracHub interview research ↗

PracHub editorial advice for the preparation topics above.

01

Ordering events by arrival rather than by event time

Offline handhelds, batch partner feeds and store-and-forward gateways deliver observations out of order as a matter of course, so a pipeline that folds whatever arrived last will flap a delivered shipment back to in transit and recompute on-time performance from the wrong facts. Message-broker ordering guarantees do not rescue this: per-partition ordering only holds within a partition, so unless the producer keys by the entity being tracked, two events for one leg can land on different partitions and be processed concurrently. The defence has two halves that are often confused - deduplicate on a stable key, then fold with a monotonic status lattice ordered by occurred_at - and both are needed, because deduplication alone still lets a stale event win. Note also that occurred_at is device-reported and therefore sometimes wrong, which is why storing received_at and a measured clock offset beside it is what makes event-time logic auditable instead of merely plausible.

02

Holding a database transaction open across a physical or third-party operation

It is natural to open a transaction, lock the position, call the rating or tendering API, and commit on the response, and it works perfectly until the partner's p99 goes from 200 milliseconds to thirty seconds. At that point every request holding a lock on a hot item-node pair queues behind it, the connection pool fills with transactions that are waiting on the network rather than on the database, and an unrelated service sharing the pool fails at the same moment. In this domain the effect is amplified because demand concentrates on a few hot rows during a promotion or a seasonal peak, exactly when partner latency is also degraded. The structural fix is to keep transactions short and local - commit the state change together with an outbox row, let a relay perform the external call, and reconcile asynchronously - accepting at-least-once delivery and making the effect idempotent rather than trying to stretch a transaction over something the database cannot roll back.

03

Optimising an axis nobody named

Ask which resource is actually scarce here: wall-clock latency, throughput, memory footprint, cost per request, or engineering time. Shaving a constant factor off an in-memory step is wasted effort when the same function makes a blocking remote call inside the loop.

04

Comparing floating-point values for equality, or holding money in them

Binary floating point cannot represent 0.1 exactly, so repeated addition drifts and an equality check fails on values that are mathematically equal. Store currency as integer minor units or a decimal type, and compare floats against a tolerance you chose for a stated reason.

Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.

13 technical prompts3 include a worked solution

Find the hottest write keys under a fixed memory budget

medium
top-kheapstreaming sketches

One day of writes to inventory_movement is 200 million rows; each carries (item_id, node_id). Distinct pairs reach 60 million. Return the 200 pairs with the most writes so they can be moved behind a single writer before the next peak. First give the exact answer assuming you may hold 60 million counters, then give an answer under a 200 MB budget, and state the error guarantee that second answer carries. Both must be one pass over the day's rows unless you argue for a second.

Approach
  1. Exact version: one hash pass to build (item_id, node_id) -> int64, then a single scan of the map maintaining a min-heap of size K = 200, pushing and popping when the incoming count exceeds the heap root. O(n + d log K) with n = 2e8 and d = 6e7, versus O(d log d) if you sort all 60 million entries — a factor of roughly log d / log K, about 3.4x, for no benefit. The heap must be a min-heap: the root is the weakest survivor, so eviction is O(log K).
  2. Cost the map honestly. 60 million entries at a 16-byte key, an int64 count and per-entry overhead is 2-3 GB in most runtimes, which is the whole reason for the second version rather than a theoretical aside.
  3. Bounded version: Misra-Gries with m counters. Keep at most m keys with counts; on a key already present increment it; on a new key when fewer than m are held, insert at 1; otherwise decrement every held counter and drop those reaching zero. With m = 1,000,000 at roughly 40 bytes per counter, that is about 40 MB, comfortably inside 200 MB alongside the heap.
  4. State the guarantee as a number, not as 'approximate'. Misra-Gries returns an estimate satisfying f - n/(m+1) <= f_hat <= f, so with n = 2e8 and m = 1e6 every count is an undercount by at most 200. If the 200th hottest pair has hundreds of thousands of writes, a 200-count error cannot reorder the top of the list — and if the counts near rank 200 are within 200 of each other, the ranking there was never meaningful for the decision being made. The sketch also merges: run one per shard, combine, prune back to m, and the bound holds with n the combined length.
  5. If exactness is genuinely required, argue for two passes rather than more memory: the Misra-Gries pass yields a candidate superset of size m, and a second pass counts only those candidates exactly in O(m) memory. That is the standard way to get an exact top-K under a memory bound, and the cost is one extra read of the day's rows.
Follow-up
  • The decision downstream is which keys get a single writer. Does a rank error at position 190 change that decision, and what does the answer tell you about how much accuracy to buy?
  • Write volume on one key is bursty — a promotion concentrates it into twenty minutes. Does a daily top-K find it, and what window would?
  • How do you keep the sketch across a worker restart without replaying the day?

Size dock doors from overlapping appointment windows

mediumWorked solution
sweep lineintervalstime zones

For one node and one local calendar day you have up to 200,000 planned dock appointments from shipment_leg: leg_id, planned_arrive_at, planned_depart_at (both TIMESTAMPTZ), plus the node's IANA zone. A door is occupied over [arrive, depart). Return the minimum number of doors that lets every appointment start on time, and the maximal interval over which that peak is sustained. Target O(n log n). Say how you derive the day's boundaries and how you break ties between an arrival and a departure at the same instant.

Approach
  1. Name the result before computing it: with one interchangeable door type, the minimum door count equals the maximum number of simultaneously occupied intervals. That equality is not a heuristic — interval graphs are perfect, so their chromatic number equals their clique number, and greedy left-to-right assignment achieves it. Say this, because it is what licenses solving a scheduling question with a counter.
  2. Emit 2n endpoints, (t, +1) at each arrival and (t, -1) at each departure, sort by t, and at equal t order the -1 before the +1. Half-open occupancy means a trailer leaving at 10:00 frees the door for one arriving at 10:00; ordering arrivals first inflates the answer by exactly the number of back-to-back handoffs, which on a well-packed schedule is most of them.
  3. Scan once with a running counter, tracking the maximum and the endpoint index where it was first reached. The peak is attained on a half-open interval between two consecutive endpoints, [t_i, t_{i+1}), not at an instant — report it that way or the operations team cannot act on it. Extend the interval while the counter stays at the maximum.
  4. Complexity: O(n log n) dominated by the sort, O(n) space. If rows already arrive ordered by planned_arrive_at from an index, use the min-heap variant instead — push each departure, pop all departures at or before the current arrival, and the heap size is the current occupancy. Same time bound, O(peak) space rather than O(n), which matters when peak occupancy is 40 and n is 200,000.
  5. Derive the day's boundaries from the zone, not from arithmetic on instants. Convert local midnight and the next local midnight to instants in the node's IANA zone; on a transition day that span is 23 or 25 hours, so adding 86,400 seconds silently drops or duplicates an hour of appointments. Decide explicitly what a zero-length dwell means — under half-open semantics it occupies nothing — and state it.
Worked solution 25 min
  1. Write the endpoint tuple with the tie-break baked into the sort key — for example (t, kind) where departure sorts as 0 and arrival as 1 — rather than handling ties in the scan body.
  2. Implement the scan, returning both the maximum and the [t_i, t_{i+1}) span at which it holds.
  3. Build a fixture of six appointments where three are strictly back-to-back at the same minute, and hand-compute the answer before running.
  4. Add an appointment spanning the local DST transition and derive the day window from the zone, asserting the appointment count inside the window.
  5. Re-run with the input shuffled to confirm the result depends only on the set of intervals.
EXPECTED RESULTThe back-to-back fixture needs one door, not three; the reported peak is a half-open interval between two endpoints; on the transition day the local window is 23 or 25 hours and no appointment is dropped or double-counted.
Follow-up
  • Doors are typed: some break pallets, some are parcel-only. Does max-overlap still equal the door count?
  • Appointments have a tolerance — a trailer may start up to 20 minutes late without penalty. How does that change the objective, and is it still solvable by a sweep?
  • Half the appointments are actuals and half are plans. Which do you sweep for tomorrow's staffing, and which for last week's utilisation report?

Find the busiest ten-minute window per reader after deduplication

medium
sliding windowevent timededuplication

One day of observation_event from fixed readers: source_id (reader), subject_id (container), occurred_at, received_at, dedupe_key. 300 million rows, partner and device replays resend whole windows, and some events arrive six hours after they occurred. For each reader, return the 10-minute event-time window containing the most distinct containers, with the window's start. Target linear work per reader after sorting. State the window semantics you chose, and what the job does with an event that lands after its window was already reported.

Approach
  1. Deduplicate before windowing, on dedupe_key, and keep the two concerns separate. A replayed batch is a no-op only if the duplicate is removed first; deduplicating inside the window logic counts a resend as traffic and reports a congestion peak that never happened. Dedupe is a hash set per reader-day or a sort-unique on the key — the same sort you need anyway.
  2. Partition by source_id and sort each partition by occurred_at, never by received_at. Arrival order is an artefact of device connectivity and partner batch cadence; a reader that went offline for six hours would otherwise show its entire backlog as one impossible burst. Sorting dominates: O(p log p) per reader of size p, O(n log n) overall.
  3. Two pointers over the sorted partition with a hash multiset container -> count and a separate distinct integer. Advance the right pointer, incrementing the count and bumping distinct only on a 0-to-1 transition; advance the left pointer while occurred_at[left] <= occurred_at[right] - 600s, decrementing and lowering distinct only on a 1-to-0 transition, and erasing the key from the map so the map's size and distinct never diverge. Each element enters and leaves once: O(p) amortised after the sort, O(window occupancy) space.
  4. Justify the candidate set rather than scanning every possible start. With half-open windows [t, t+600), sliding a window right until its left edge coincides with an event can only add events and never removes one, so the maximum is attained at some event's occurred_at; checking the p windows anchored at events is sufficient and exhaustive. State the half-open convention explicitly — an event exactly at t+600 belongs to the next window, and flip-flopping on that produces off-by-one disagreements between this job and whatever reads its output.
  5. Handle lateness by choosing a policy, not by hoping. Either run over a closed event-time batch with a stated lateness allowance — the day plus six hours, so the six-hour tail is inside the batch and the day-late tail is not — or emit under a watermark and restate the affected windows when a late event lands. Both are defensible; what is not defensible is silently dropping the late event, because that is how the busiest window quietly becomes the one with the best connectivity.
Follow-up
  • Two events for one container arrive from two readers a second apart. Is that congestion, a misread, or one container passing two portals?
  • You need this continuously rather than as a daily batch. What changes, and where does the memory go?
  • A device's clock is three hours fast. What does that do to this result, and how would you detect it from clock_offset_ms?

For someone fluent in a dynamic language who has shipped real work but has never had to say what the runtime is doing underneath. The week is built on measuring and deliberately breaking things, because the questions that expose this background are the ones where the interviewer asks why a second time.

Small steps. Visible outcomes.0 / 7 completed
ONE WEEK · YOUR PACE

Prepare, practise & reflect

One practical outcome each day. Spend longer where you need it.

0 / 7 done
01Measure before reasoning
  • Take a slow piece of your own code, write down in advance where you believe the time goes, then profile it and record how wrong the guess was. The cost is usually an allocation you did not notice or an accidental quadratic membership test.
  • Replace one list membership test inside a loop with a set and measure at a thousand, ten thousand and a hundred thousand elements, confirming the shape of the curve rather than only that it got faster.
  • Write down the three quantities you can now measure instead of assert: wall time, peak memory, and call count for the function you suspected.

Deliverable: A before-and-after profile of real code plus a written note on the size of the gap between the guess and the measurement.

Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗
02References, copies, and the bugs they produce
  • Write the function with a mutable default argument, call it three times, and explain the accumulating result: the default is evaluated once when the function is defined, so every call shares one object.
  • Build a nested structure, take a shallow copy, mutate an inner element, and show that both views changed, because a shallow copy duplicates the container and not the elements. Then fix it with a deep copy and state the cost you just accepted.
  • Write two functions, one mutating its argument in place and one rebinding the local name, and predict the caller's view of each before running it. That single distinction produces most of the bugs that pass their tests.

Deliverable: Three small programs whose output you predicted correctly before running, each with a one-line statement of the rule underneath.

Practice prompt ↗Practice prompt ↗Practice prompt ↗
03Types, once, in a language that checks them
  • Port one module you have already written, roughly a hundred lines, into a statically typed language, and record every place the compiler demanded an answer your original had left implicit: a value that can be absent, a numeric width, a case never handled.
  • Write the same signature in both languages and state what the static one guarantees before the program runs and what it does not, since it will not save you from a wrong algorithm or an index out of range.
  • Write the difference between an interface satisfied by declaration and one satisfied structurally, with one case each where the other approach would miss the mistake.

Deliverable: One module in two languages plus a list of the questions the type checker forced you to answer.

Practice prompt ↗Practice prompt ↗
04Concurrency, starting with what actually runs at the same time
  • Run the same CPU-bound function across four threads and four processes and measure both. Under the default CPython build the threaded version will not speed up, because only one thread executes bytecode at a time; the process version will. Check which build you are on first, since free-threaded builds remove that lock and change the result.
  • Then run a blocking I/O workload across four threads and measure it speeding up, because the interpreter releases that lock around blocking calls, which is why treating threads as useless is wrong as a general claim.
  • Build the lost update: two threads each incrementing a shared counter a hundred thousand times, and show a final value below the expected sum, because an increment is a load, an add and a store and the thread can be suspended between them. Fix it with a lock and then measure what the lock costs.

Deliverable: Three measurements, threads against processes on CPU work, threads on I/O work, and a demonstrated lost update, each with the mechanism written underneath.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05Debugging as a procedure rather than an instinct
  • Work one real failure as a bisection: find a revision or an input size where it is good and one where it is bad, halve repeatedly, and state the two assumptions bisection needs, that the property changes exactly once across the range and that the test is reliable.
  • Minimise one failing input to the smallest version that still fails, and record how many rounds it took.
  • Keep a hypothesis log for one bug in three columns, what I believe, what would disprove it, what I observed, and stop yourself the first time you are about to change two things at once.

Deliverable: One bug worked to root cause with a written hypothesis log and a minimised reproducing input.

Practice prompt ↗Practice prompt ↗
06Tests that catch the bug you are about to write
  • Implement an LRU cache with a capacity bound, then write the three test cases that would catch an off-by-one in eviction: insert exactly capacity items and assert nothing was evicted, insert one more and assert the least recently used key is the one gone, and read an old key just before that insert so the eviction victim changes.
  • Add a property test comparing your implementation against a deliberately slow reference, an ordered list scanned linearly, over a few thousand random operation sequences, because a slow reference finds the cases you would not have thought to write.
  • Write one numeric test that fails under exact equality and passes with a tolerance, and state why the tolerance has to be relative rather than absolute once the magnitudes grow.

Deliverable: An LRU implementation with three boundary tests, one property test against a slow reference, and one tolerance-based numeric test.

Practice prompt ↗Practice prompt ↗
07Debug something broken, out loud
  • Have someone plant three defects in a two-hundred-line program, an off-by-one, a shared mutable state bug, and a wrong error-handling path, then find them while narrating, under a fixed rule: state the hypothesis before touching anything.
  • Time each one and record which tool found it, reading, a printed value, a debugger, or a test, because the question asked in interviews is how you would find it rather than what it was.
  • Write the sentence you will use when you do not yet know the cause, one that names the next measurement instead of offering a guess.

Deliverable: A recorded debugging session with time-to-find per defect and the method that found each.

Practice prompt ↗Practice prompt ↗Worked solution ↗

Expand any day for tasks and deliverables. Your progress is saved on this device.

Engineers over-index on what they repaired. A stronger answer covers something you knowingly left broken: the alert you tuned down, the data inconsistency you documented instead of chasing, the cleanup you deferred past two quarters. Give the reasoning and the condition that would have reopened it, so it reads as a decision and not as neglect.

How do you handle changing project requirements under tight deadlines?

medium
behavioural and engineering judgement

How do you handle changing project requirements under tight deadlines?

Approach
  1. State the situation in two sentences and spend the rest on the reasoning.
  2. Name the disagreement and how you resolved it with evidence.
  3. Give the blast radius: what could have broken, and what you measured.
Follow-up
  • How did you know your change caused the improvement?
  • What would you do differently if you ran that again?

What is your experience with core technologies and development process…

medium
behavioural and engineering judgement

What is your experience with core technologies and development processes relevant to this role?

Approach
  1. Pick a story where you made the decision, not one where you watched it.
  2. State the situation in two sentences and spend the rest on the reasoning.
  3. Give the blast radius: what could have broken, and what you measured.
Follow-up
  • How did you know your change caused the improvement?
  • What did you decide not to do, and why?

Own an outage that double-tendered loads to a carrier

medium
incident responseidempotencyblast radiuscarrier integration

A retry wrapper in the carrier gateway re-issued tenders whose responses had timed out, minting a fresh idempotency key on each attempt. Over 70 minutes, 212 of 1,340 legs were tendered twice and 19 became second physical pickups before dispatchers noticed. Take the on-call role and describe an outage you owned with a comparable blast radius: how it was detected, how you bounded the affected legs, what you stopped first, and how the duplicate physical work was unwound. Give a wall-clock timeline, the query that sized the damage, and the guard that would have caught it in minutes rather than an hour.

Approach
  1. Open with the invariant that broke rather than the symptom: at most one booking exists per shipment_leg, keyed by booking_idempotency_key. Stating the invariant tells the listener what is countable, which is what makes the rest of the story checkable.
  2. Size the population with a named query, not an adjective. Duplicates are visible two ways and a strong answer says which one it trusted: legs carrying more than one distinct carrier_booking_ref, and the carrier's own booking export left-joined to shipment_leg on the reference, where the unmatched rows are bookings the system does not know it owns. The second is authoritative because the partner, not you, holds the truth about what was accepted.
  3. Separate mitigation from fix and say which came first. Mitigation is blunt and cheap: disable the retry path, drop gateway concurrency, hold tendering behind a flag so the floor keeps picking while dispatch stops booking. The fix, minting and persisting the key before the call with an explicit unknown status, is not an incident-window change.
  4. Split the blast radius into tiers, because the recovery cost is not uniform: a duplicate record is a delete, a duplicate booking not yet dispatched is a cancellation call, and a duplicate that became a pickup is a physical reversal with a trailer, a driver and an invoice behind it. The 19 that moved dominate the cost and belong at the front of the account.
  5. Close with one detector and its price. A counter on bookings-per-leg with an alert above one, or a nightly reconciliation of the partner export against shipment_leg, are both defensible; naming one and saying how many false pages per week it costs beats listing five that nobody staffed.
  6. Name what you got wrong inside the response window, not only in the writeup. Interviewers weight that heavily because it is the part candidates rehearse away.
Follow-up
  • The partner has no idempotency concept on their tender endpoint. What do you do differently, and what is the residual exposure you accept?
  • How would you have detected this in five minutes instead of 70, and what would that detector have cost in noise?
  • Dispatch disputes your count of duplicate pickups. What artefact do you show them?
  • 01

    How do you handle changing project requirements under tight deadlines?

  • 02

    What is your experience with core technologies and development processes relevant to this role?

  • 03

    A retry wrapper in the carrier gateway re-issued tenders whose responses had timed out, minting a fresh idempotency key on each attempt. Over 70 minutes, 212 of 1,340 legs were tendered twice and 19 became second physical pickups before dispatchers noticed. Take the on-call role and describe an outage you owned with a comparable blast radius: how it was detected, how you bounded the affected legs, what you stopped first, and how the duplicate physical work was unwound. Give a wall-clock timeline, the query that sized the damage, and the guard that would have caught it in minutes rather than an hour.

PracHub interview preparation framework ↗
Is this an official Energy Solutions interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at Energy Solutions. Rounds and questions reflect what candidates have reported, not a process Energy Solutions has published, and they change over time. Confirm the current format and scope with your recruiter.

PracHub interview research ↗
How difficult is the interview process, and how much preparation time should I plan for?

The interview process is rigorous and can be quite lengthy, often spanning multiple weeks and several rounds. Candidates should dedicate at least two to four weeks of focused preparation, reviewing core technical concepts, system design principles, and behavioral stories.

PracHub interview research ↗
What differentiates successful candidates from those who are not selected?

Successful candidates combine strong technical fundamentals with a clear passion for the clean energy mission. They communicate their problem-solving process transparently, handle ambiguous prompts with structured thinking, and demonstrate strong collaboration skills.

PracHub interview research ↗
What is the company culture like for engineering teams?

Engineering teams operate in a collaborative and mission-driven environment with a strong emphasis on work-life balance and sustainable impact. Teams value thoughtful engineering, continuous learning, and cross-functional alignment.

PracHub interview research ↗
What is the typical timeline from initial screen to a final offer?

Because the interview loop involves multiple conversations across different teams, the process can take several weeks or even over a month from start to finish. Patience and proactive communication with your recruiter are key during this period.

PracHub interview research ↗
Sources & methodology 3 sources ↗

No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.