As a Software Engineer at Credit Genie, you play a vital role in building and scaling financial technology platforms that empower everyday consumers. Your daily work directly influences core backend architectures, trust platforms, and IT systems that drive financial health products. By designing resilient services and secure data pipelines, you help millions of users navigate financial decisions with confidence.
This position demands both technical rigor and product ownership. You will collaborate closely with engineering leaders, product managers, and cross-functional teams to deliver high-impact features under high-growth conditions. Whether you are optimizing distributed backend services or hardening trust platforms, your contributions will shape the operational backbone of the company.
The environment at Credit Genie is fast-paced, collaborative, and deeply technical. You will face complex engineering challenges requiring clean design, scalable coding practices, and thoughtful problem-solving. Expect to work with modern backend stacks, engage in rigorous code reviews, and drive architectural decisions that directly impact business outcomes.
Recruiter Screening Call
reportedHalf of this call is the part candidates treat as small talk: start date, notice period, work authorisation and its timing, location and time zone, on-call, and the number. Those are what kill offers late, after several engineers have each spent a day. Surfacing a hard constraint now costs you nothing and occasionally buys you something, since a loop compressed to fit a competing deadline can usually only be arranged if it is asked for early. The common failure is deflecting the compensation question twice, then discovering at offer stage that the band never reached your number.
What to demonstrate
- Whether your hard constraints are compatible with the role before a loop gets booked: earliest start, notice period, what authorisation you hold and when it needs action, days on site, willingness to carry a pager
- Whether you give a compensation range with something behind it, such as current total compensation or a competing timeline, rather than leaving the band untested
- Whether your stated timeline is real, since a competing deadline raised now is something scheduling can sometimes work around and the same deadline raised at offer stage usually is not
How to prepare
- Write each constraint down in one line before the call and state them as facts rather than negotiating them live under a question you were not expecting
- Set your range from two or three current data points for that level and location, and name the structure you are quoting in, so the number is comparable to the one they are holding
- If another process is running, say where it stands and by when, and ask directly whether this loop can be scheduled inside that window
Online Assessment
reportedThe same problem is scored by two different mechanisms depending on the format, and preparing for one does not cover the other. With a person watching, partial progress is visible and a hint is a correction you can absorb; silence is the expensive failure, because nobody can read a half-written function. With an automated grader there is no partial credit for what you were about to do, nobody to ask, and the worked examples in the prompt are the entire specification. Read them as a contract, down to whether an empty result should be an empty list or no output at all.
What to demonstrate
- In a live session, whether your commentary tracks what your hands are doing, and whether a hint redirects you or gets defended against
- In an automated one, whether you cover the cases the examples do not show, since the hidden cases are where the score moves
- Whether you manage the clock on purpose: abandoning an approach that is not converging while there is still time to write something simpler that finishes
How to prepare
- Have someone hand you a problem and feed you one deliberately wrong hint. Practise testing it against a concrete case instead of accepting or rejecting it on authority.
- Do one timed run a week in a plain browser editor with autocomplete, linting and your own snippets switched off, which is closer to what these environments give you
- For the automated format, write the harness before the solution: a main that feeds the worked examples plus an empty and a single-element case and prints expected against actual, so a wrong submission is caught by you first
Technical Interview Loop
reportedA day like this is several different games in a row, and the expensive mistake is carrying the previous one into the next room. Coding rewards narrow precision and finishing inside a timer. Design rewards breadth, stated assumptions and naming what you are deliberately not building. Behavioural rewards specificity about people and decisions. Candidates who over-engineer a coding problem they were supposed to finish, or who start sketching class hierarchies before anyone has agreed what the system has to do, are usually still playing the last round. Between rooms, name out loud which game the next one is.
What to demonstrate
- Whether the coding round ends with something that runs and has been traced against a degenerate input, rather than an extensible design that was never finished
- Whether a design discussion opens by agreeing on traffic shape, read-to-write ratio and what is allowed to be stale, instead of proceeding from an architecture you arrived with
- Whether a behavioural answer names a person, a disagreement and what you did about it, rather than describing the system the story happened inside
- Whether the opening habits still appear late in the day: restating the problem, asking for constraints, saying the plan before typing
How to prepare
- Book three mocks of different types back to back on one afternoon and ask each interviewer afterwards which round you answered in the wrong mode
- Write a three-line opening script per round type — coding: restate, name the approach and its cost, then type; design: ask for scale, read-write mix and what must not break; behavioural: name the person, the stakes and the decision — and run it off a card so the switch is mechanical rather than remembered
- Practise coding with a timer you do not extend, stopping when it stops, so the trained reflex is to finish a correct solution rather than to keep improving one
System Design Evaluation
reportedMost of the time lost in this format is not lost to thinking. It goes to a standard-library call you half-remember, an off-by-one in a loop bound, and a debugging loop that mutates code at random until something passes. When output is wrong, stop re-reading the whole function: take the smallest input that reproduces it and walk the state through by hand, printing intermediates if the environment allows. Guessing at a fix without a failing case you understand is how a five-minute bug becomes twenty, and the clock does not pause while you do it.
What to demonstrate
- Whether you reach the right structure without a detour, and can write it from memory rather than only recall that one exists
- Whether overflow is considered where the language has fixed-width integers, since a signed 32-bit value stops at 2,147,483,647 and then wraps in Java, is undefined behaviour in C++, and does not arise in Python, whose integers grow instead
- Whether recursion depth is treated as a constraint on large inputs, given that CPython's default limit is 1000 frames and a deep recursion can exhaust the stack in any language where an iterative version would not
- Whether a failing case is isolated and explained before any edit is made to the code
How to prepare
- From an empty file and with no references open, implement the pieces you lean on most: a heap push and pop, an iterative DFS with an explicit stack, and a binary search whose midpoint is written lo + (hi - lo) / 2, which avoids the overflow that (lo + hi) / 2 can hit in a fixed-width integer type
- Time yourself on the ten library calls you look up most, such as sorting with a custom comparator, splitting and joining strings, and finding the next key at or above a value in an ordered map, until the lookup is gone
- Take a solution you know is broken and, before touching it, write one sentence naming the input, the expected value and the actual value. Repeat until you do it without deciding to.
Leadership and Culture Fit
reportedMany of these questions are about something that went wrong, and the grading sits mostly in the hours after you knew. Who found out first, whether that was you or an alert or a user, how long it took you to say it out loud, and whether the people who needed the news got it while they could still act on it. Engineers under-tell this part because it feels like confessing. The pattern it is looking for is the opposite: the quiet fix, an incident absorbed without telling anyone, after which nothing changed and the same failure is still available.
What to demonstrate
- How the problem was found, and whether that route was one you had built or one that happened to you, since a user reporting it first means your instrumentation did not cover that failure
- Whether time-to-detect and time-to-tell are separate numbers in your account and whether you know both, because a fast fix that nobody heard about until the retro is a different answer from a slow one that was announced immediately
- Whether the resolution left something durable behind, a check that fires or a default that changed, rather than depending on people remembering to be careful
- Whether you can say what the failure cost without either inflating it or waving it away
How to prepare
- Reconstruct one incident you were part of as a timeline with clock times: first bad request, first signal, first person who knew, first message outside the team, mitigation, permanent fix. The gaps between those entries are what gets asked about
- Look up the configuration of the signal that caught it, including its evaluation window and threshold. An alert defined on a five-minute aggregate cannot fire until the condition holds across that window, which puts a floor under time-to-detect that has nothing to do with how severe the failure was. Be able to say what that floor was and whether anyone had chosen it deliberately
- Prepare one story where you escalated early and the severity turned out to be smaller than you thought, including what it cost the people you pulled in. Without it, every answer you give about raising alarms is unfalsifiable
1 candidate reports. Individual accounts describe a particular role and hiring cycle.
Credit Genie Software Engineer Interview Experience — FastAPI CRUD Pairing, Rejected Over a Communication Slip
When I was preparing, I couldn't find this question on the forum — it's a startup, so that's understandable. Here's the overall process: Hiring Manager Interview Technical Pairing, Python AI/ML Technical Pairing Systems Architecture & Design (AI/ML) Motivation + Mission Alignment Executive Interview I got cut after the first round, which combined the Technical Pairing and the Hiring Manager Inter…
Read full experiencePracHub editorial advice for the preparation topics above.
Treating money as a decimal with two places
ISO 4217 exponents are 0 for currencies such as JPY and KRW, 2 for most, and 3 for BHD, KWD, JOD, OMR and TND, so a hard-coded multiply-by-100 is off by a factor of 100 or 10 depending on the currency, in opposite directions. Floating point is worse: IEEE 754 binary64 cannot represent 0.1 exactly, so repeated accrual accumulates drift that appears as a handful of minor units in the daily reconciliation and then gets 'fixed' by widening the match tolerance, which is how a genuine break becomes invisible. The only forms that survive a reconciliation are integer minor units with the exponent carried alongside the currency code, or a fixed-scale decimal type with exactly one documented rounding point.
Deriving the business date from the UTC timestamp
Posting date, value date and the processor's settlement date are three different dates, determined by cutoff times, business-day calendars and holidays rather than by midnight UTC. A movement recorded at 23:50 on one side of a cutoff belongs to the next business date, so computing business_date as created_at::date makes daily totals disagree with every statement and every settlement file. The signature is a reconciliation break that resolves itself the following day and then reopens, which reads like a flaky job and is actually a data model that is missing a column: business_date has to be stored explicitly and set from the cutoff rule, with the timestamptz kept separately for ordering.
Tests that assert on the implementation rather than the behaviour
Assert on what a caller can observe, not on the number of internal calls or the shape of a private field. A test that breaks on every refactor but still passes when the answer is wrong costs more than it protects.
Abandoning working code to chase the optimal solution
Get the straightforward version correct, state its complexity, and only then optimise, keeping the working version until the faster one passes the same cases. A correct quadratic solution with a stated path to linear beats a half-written optimal one that never ran.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
How would you refactor a legacy function to improve time complexity an…
How would you refactor a legacy function to improve time complexity and readability?
Approach
- Choose the data structure from the access pattern, not from familiarity.
- State the target complexity and say which constraint rules the naive version out.
- Walk one small example through your approach before writing the whole thing.
Follow-up
- How does this change if the input no longer fits in memory?
- What is the worst case, and how likely is it on real data?
Implement a rate limiter or caching layer from scratch using optimal d…
Implement a rate limiter or caching layer from scratch using optimal data structures.
Approach
- Walk one small example through your approach before writing the whole thing.
- Name the brute-force solution and its complexity before improving on it.
- Choose the data structure from the access pattern, not from familiarity.
Follow-up
- What is the worst case, and how likely is it on real data?
- Which test case would catch an off-by-one here?
Write a function to parse, validate, and transform deeply nested JSON …
Write a function to parse, validate, and transform deeply nested JSON payloads under strict memory constraints.
Approach
- Name the brute-force solution and its complexity before improving on it.
- State the target complexity and say which constraint rules the naive version out.
- Restate the input: its shape, its size, and what is guaranteed about it.
Follow-up
- What is the worst case, and how likely is it on real data?
- How does this change if the input no longer fits in memory?
Derive per-account balances and catch unbalanced transactions
You are given ledger_entry rows streamed in entry_id order: transaction_id, account_id, direction (debit or credit), amount_minor (a positive int64), currency, business_date. Up to 500 million rows, at most 20 million distinct (account_id, currency) pairs, and the entries of one transaction are contiguous in the stream. In a single pass with no re-reads, return the closing balance per (account_id, currency) and the transaction_id of every transaction whose entries do not sum to zero within each currency. State your time and space bounds.
Approach
- Normalise the sign at read time from
direction, not from the amount:signed = +amount_minorfor debit,-amount_minorfor credit (state which convention you picked). The schema constrainsamount_minor > 0precisely so the sign lives in exactly one place. - Hold one hash map keyed
(account_id, currency)to an int64 running total. Twenty million keys at 16 bytes of payload plus map overhead is order 1 GB in most runtimes — quote the number, and offer the fallback: partition the stream byhash(account_id) % Pand run P passes for 1/P of the memory. - Ride the zero-sum check on the same pass. Because a transaction's entries are contiguous, keep a tiny
currency -> int64map for the currenttransaction_idonly, test it against zero on the boundary and at EOF, then clear it. That is O(currencies in one transaction), typically one or two. - Bound the arithmetic explicitly. Int64 holds about 9.22e18, so overflowing one account across 500 million entries needs an average of 1.8e10 minor units per entry — safe here, but use a checked add so an adversarial file fails loudly rather than wrapping.
- Complexity: O(n) time, O(distinct account-currency pairs) space, one sequential pass, no sort. The zero-sum check adds no asymptotic cost, which is the argument for doing it here rather than in a second job.
Worked solution 20 min
- Write the sign rule down in one sentence before any code, naming which side debit is positive on, and apply it at read.
- Implement with two maps —
balances: (account_id, currency) -> int64andtxn: currency -> int64— plus the currenttransaction_id. - On a change of
transaction_id, assert every currency intxnsums to zero, record the id if not, then clear. - Feed a fixture: one 2-entry transaction that balances; one 4-entry transaction with USD and JPY legs that balances within each currency; one 3-entry transaction off by a single minor unit.
- Re-run with the entries shuffled inside each transaction to prove the result is order-independent within a transaction.
Follow-up
- Entries of a transaction are no longer contiguous. What does the zero-sum check cost now, and which is cheaper: buffering open transactions or an external sort on
transaction_id? - How would you produce the same balances as of an arbitrary
business_datewithout a second full scan? - The job is restarted after a crash halfway through the file. What makes the second run produce identical output?
Make a charge endpoint safe under concurrent duplicate retries
idempotency_key holds id, scope, key, request_fingerprint (SHA-256 over the canonicalised body), status (in_progress, completed, failed), response_status, response_body, locked_at, completed_at, expires_at, created_at. Fifty identical create-payment requests carrying the same scope and key reach four application instances inside the same 20 ms. Give the DDL constraint and the exact statements the handler runs so that exactly one payment_intent is created and all fifty callers receive the same response body. State what you return when that key arrives with a different fingerprint, and what an arrival after expires_at means.
Approach
- Put the concurrency control in the schema: UNIQUE (scope, key). A SELECT-then-INSERT cannot work because both transactions can read nothing before either commits, so the check passes twice and the constraint then surfaces as an error on a payment that succeeded.
- Claim the key with INSERT ... ON CONFLICT (scope, key) DO NOTHING RETURNING id. A conflict returns zero rows rather than the existing row, so branch on rowcount: the winner proceeds, the loser reads the stored row.
- Keep that path on READ COMMITTED deliberately. The loser's follow-up SELECT takes a fresh statement snapshot and therefore sees the winner's committed row; under REPEATABLE READ the transaction snapshot predates that commit, the row stays invisible and the loser concludes the key does not exist.
- Split the work across two transactions because the processor call cannot sit inside one: commit the in_progress row with locked_at first so losers can see a claim, perform the effect, then write payment_intent plus status=completed with response_status and response_body in a single second transaction.
- Handle the crash window explicitly: a row stuck in_progress past its lease is an unknown outcome, not a failure, so the reaper queries the processor for that key before deciding. A loser that sees in_progress returns 409 and retries rather than repeating the effect.
- Compare request_fingerprint before replaying anything. Same key with a different body is 409, never the cached response, because replaying confirms a payment the caller did not request; and set expires_at beyond the client's and the processor's maximum retry horizon, since a replay after it is a genuinely new request.
Worked solution 20 min
- Create idempotency_key with UNIQUE (scope, key) and write the claim statement as INSERT ... ON CONFLICT DO NOTHING RETURNING id, plus the fallback SELECT on zero rows.
- Drive it with 50 threads sending the identical body, and assert one payment_intent row and fifty byte-identical response bodies.
- Re-send the same key with amount_minor changed by one unit and assert 409 plus no new payment_intent row.
- Kill the process between the processor call and the second commit, restart, and show the reaper resolves the in_progress row by querying the processor rather than by re-charging.
Follow-up
- The handler dies after the processor call and before the local commit. What does the next retry with that key observe, and how does the system converge on exactly one charge?
- Does the downstream processor honour an idempotency key of its own? Who mints it, and what breaks if a fresh one is generated per attempt?
- How do you purge rows past expires_at without the delete contending with the insert path?
Version a loan schedule instead of soft-deleting posted instalments
loan_instalment is keyed by (loan_id, schedule_version, instalment_no) and carries due_date, principal_minor, interest_minor, fee_minor, paid_principal_minor, paid_interest_minor, status, days_past_due, effective_from (date) and superseded_at (timestamptz). A borrower defers two payments on 2026-03-14, and instalments 1 to 6 already have allocations posted against them. Model exactly what the deferral writes, and write the query that returns the schedule as the borrower saw it on an arbitrary date. Say why stamping the old rows with deleted_at, or updating them in place, fails an audit.
Approach
- Treat the deferral as an insert, not an edit: write a complete new schedule_version with effective_from = the deferral instant on 2026-03-14, and in the same transaction stamp superseded_at on every row of the outgoing version with that identical instant, so the two version windows are half-open and adjacent rather than overlapping. Instalments 1 to 6 are reproduced unchanged, because they are what the borrower was told and what was posted to the ledger.
- Write the as-of read as a version selection, not a row filter: WHERE loan_id = $1 AND effective_from <= $2 AND (superseded_at IS NULL OR superseded_at > $2), then assert that exactly one schedule_version comes back - COUNT(DISTINCT schedule_version) = 1, not one row - so an overlapping window raises rather than silently returning two interleaved schedules under one instalment_no.
- Fix the type mismatch before writing that predicate: effective_from is declared date and superseded_at timestamptz, so comparing them casts the date at the session TimeZone and two readers in different zones select different versions near midnight. Put both columns in one domain, timestamptz, keep the window half-open with effective_from inclusive and superseded_at exclusive, and resolve a bare as-of date to an instant once, in the loan's booking timezone, at the edge of the system.
- Say what deleted_at loses. It records that a row stopped being current but not what replaced it or from when, it leaves every downstream query obliged to remember deleted_at IS NULL, and one query that forgets double-counts the schedule. Versioning puts the same information in the primary key where it cannot be forgotten.
- Close the arithmetic: under the loan's stated day-count convention the new version must still sum to outstanding principal plus scheduled interest to the minor unit, with the per-period rounding residual placed in one named instalment, conventionally the last, rather than smeared across the tail.
- Index (loan_id, effective_from DESC) for the as-of lookup, keep superseded versions online rather than archiving them, and enforce with a trigger that no UPDATE touches a row whose paid_principal_minor or paid_interest_minor is non-zero.
Follow-up
- What does days_past_due mean for an instalment that exists in two versions with different due_dates?
- A payment arrives allocated to an instalment_no that exists only in the superseded version. What do you do with it?
- How do you prove the ledger postings made under version 1 still reconcile once version 2 exists?
How would you design a scalable trust and verification platform from t…
How would you design a scalable trust and verification platform from the ground up?
Approach
- State the consistency you need, and where you are willing to be stale.
- Choose a partition key and say what query it makes expensive.
- Name the failure you are designing for, then the recovery path.
Follow-up
- What breaks first when traffic grows ten times?
- How does this behave when that dependency is down for an hour?
What caching and data partitioning strategies would you implement for …
What caching and data partitioning strategies would you implement for a high-traffic financial transaction service?
Approach
- Name the failure you are designing for, then the recovery path.
- State the consistency you need, and where you are willing to be stale.
- Name the read and write paths separately; they rarely have the same bottleneck.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Walk through how you would monitor system health, set up alerts, and d…
Walk through how you would monitor system health, set up alerts, and debug a cascading failure in production.
Approach
- Name the failure you are designing for, then the recovery path.
- Choose a partition key and say what query it makes expensive.
- Fix the scope first: who calls this, how often, and what they do when it fails.
Follow-up
- What breaks first when traffic grows ten times?
- How does this behave when that dependency is down for an hour?
Can you explain how specific Python operating system concepts or memor…
Can you explain how specific Python operating system concepts or memory management work in practice?
Approach
- Work from the requirement backwards to the design.
- State your assumptions explicitly before working the problem.
- Say what you would check first and why it is the highest-information step.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Evolve a payment response without breaking installed clients
The live response is {id, amount: "12.50", currency: "USD", status: "captured", captured_amount: "12.50"}. Three changes are needed: amounts become integer minor units carrying the ISO 4217 exponent, status gains partially_captured and reversed, and captures become an array because one authorisation can be captured several times. The callers are 4,000 merchant integrations you cannot upgrade; many switch exhaustively on status and parse amounts as decimals. Design the versioning mechanism, the migration for each change, and the deprecation path. State exactly what an unchanged client sees on day one.
Approach
- Classify each change by whether an old client can be kept correct. Adding a field is additive. Changing amount's type in place is breaking and, worse, silent: "12.50" becomes 1250, which still parses as a number, so a two-exponent currency is off by a factor of 100 and nothing raises. A new enum value is breaking even though the schema is unchanged, because an exhaustive switch has no branch for it.
- Pick per-account pinned versions with a per-request override header, and put a transformation layer between adjacent versions rather than branching the handlers. Handlers speak only the newest representation; each version step is a small function and they compose. The cost is real: every adjacent pair needs its own fixtures, and a downgrade that loses information needs an explicit decision, because a partially_captured intent simply has no v1 status.
- Map the three changes concretely. Ship amount_minor and currency_exponent as new fields to every version immediately, while v1 keeps amount as the decimal string it always was. Add captures[] as a new field, with v1's captured_amount remaining the sum. For status, choose the v1 mapping for partially_captured deliberately: rendering it as authorised understates settled money, rendering it as captured overstates it, and you must document which lie you chose and why.
- Make the enum problem structural instead of solving it once. Document from day one that new status values may appear, ship a stable coarse field alongside it such as a small closed set of categories or an is_terminal boolean that clients can switch on safely, and specify the default branch's behaviour for an unknown value.
- Sequence the rollout on evidence rather than dates: ship the additive fields, use access logs to see who reads them, open v2 for new accounts, migrate willing accounts by pinning, then announce a sunset with per-account usage numbers. The deprecation finishes when v1 traffic is zero, not when the calendar says so.
- Guard it in CI with a contract test per live version against recorded fixtures, so a change inside a handler cannot silently alter an old representation. Without that, the transformation layer decays into the same branching it replaced.
Worked solution 40 min
- Write the v1 and v2 schemas side by side and mark each field additive, breaking-loud or breaking-silent.
- Implement v2 in the handler and write the single downgrade function v2 to v1, including the deliberate partially_captured mapping and the captured_amount sum.
- Build fixtures for six real payments (full capture, two partial captures, a reversal, a JPY payment, a KWD payment, a refund) and assert the v1 output is byte-identical to what the current production handler returns for the first four.
- Add the coarse status category field to both versions and write the client-side switch that stays correct when a seventh status is added later.
- Draft the deprecation notice with the access-log query that identifies which accounts still read the v1 amount field.
Follow-up
- A client pinned to v1 sends a v2-only field on the request. What happens, and what should the rule be?
- One integration reads amount but ignores currency and assumes two decimals. What does your migration do for their JPY and KWD payments?
- How do you retire v1 when 30 accounts still call it and two of them have not answered an email in a year?
Reconciliation breaks that close overnight and then reopen
Reconciliation opens 400 to 900 ledger_only breaks each morning, most resolve on the next run, and a subset reopens two days later. The three-way match joins on (external_reference, amount_minor, currency, business_date). ledger_entry.business_date is populated as posted_at::date, where posted_at is timestamptz. The processor closes its day at 22:00 US/Eastern. Breaks cluster on movements posted between 00:00 and 03:00 UTC. Give the ordered checklist, the cause, the fix, and what happens to the breaks already in the table.
Approach
- Test the hypothesis with data you already have rather than by reasoning about it. Bucket open breaks by hour of day on posted_at. A cutoff mismatch concentrates breaks in a fixed window every day and produces almost none outside it; a flaky job produces breaks with no time-of-day structure. One query eliminates half the candidate explanations.
- Compute the offset explicitly and note that it moves. A 22:00 US/Eastern cutoff is 03:00 UTC next day under EST and 02:00 UTC under EDT, so the processor's business date D spans UTC 03:00 on D to 03:00 on D+1, while posted_at::date assigns D to UTC 00:00 through 24:00. The disagreement window is exactly 00:00 to 03:00 UTC, narrowing to two hours during EDT, which matches the observed cluster.
- Find the second bug in the same expression. Casting a timestamptz to date in PostgreSQL applies the session TimeZone, so the identical query returns different dates for different sessions and for the same session after a SET. A business date that depends on who is asking is not a business date.
- Name the missing column rather than a better expression. business_date is a business fact determined by a cutoff rule and a business-day calendar; it is not derivable from any UTC timestamp. It must be stored and set at write time from the rule, with posted_at kept separately for ordering.
- Account for the self-resolving and reopening pattern before claiming the cause is complete. Check whether the day-spanning fuzzy fallback is resolving breaks by matching against an adjacent date, and whether two movements sharing amount, currency and merchant on adjacent dates can be crossed by it. A crossed pairing resolves today and surfaces as duplicate_match later, which is exactly the resolve-then-reopen shape and is a second reason not to widen tolerance.
- Plan the correction against the append-only rule. The trigger forbids UPDATE on a posted entry, so a business_date correction is either a deliberate, logged exception for a non-financial classification column with the trigger amended, or a separate correction table joined at read time. Pick one and get it signed off, because it decides whether prior statements change. Then re-run the matcher over corrected dates rather than bulk-resolving the open breaks; whatever survives is the genuine break population the date bug was masking.
Follow-up
- The fuzzy fallback resolved some breaks by matching an adjacent date. How do you prove it never crossed two lines?
- What does your fix do on the DST transition days themselves, when the local day is 23 or 25 hours long?
- Where does the business-day calendar live, who updates it for a newly announced holiday, and what breaks if they forget?
Roughly ninety minutes on weeknights with one longer weekend block. The plan cuts scope rather than compressing everything, on the assumption that one thing finished per night beats four half-started.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Fix the scope and take a cold baseline
- Read the role description and write the three things the loop will almost certainly test, then write an explicit not-doing list and keep it visible all week.
- Take one twenty-five-minute coding problem and one fifteen-minute design prompt cold, and write the single sentence naming what blocked each, because those two sentences decide where the remaining evenings go.
- Set the week's rule: one thing finished every night, including the night you only have forty minutes.
Deliverable: A one-page scope with a not-doing list and two cold attempts, each carrying one sentence on what blocked it.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02One pattern, written three times from blank
- Choose the single pattern most likely to appear in your loop and write it three times from an empty file rather than editing the previous attempt.
- On the third pass, write the invariant as a comment before the loop body and the complexity before the first line of code.
- Stop at ninety minutes even if the third version is imperfect, and write the one thing you would fix given another hour.
Deliverable: Three independent implementations of the same pattern plus a note on what changed between them.
Practice prompt ↗Practice prompt ↗03One design, only to the depth you can defend
- Take one system shape and go only as far as requirements, interface and data model, refusing to draw a box you could not survive a follow-up about.
- Attach one number to each non-functional requirement, deriving it rather than asserting it, and write the assumption the number rests on.
- Write the one tradeoff you are choosing against and the observation that would make you reverse it.
Deliverable: One design at interface-and-schema depth with derived numbers and one written reversible tradeoff.
Practice prompt ↗Practice prompt ↗04Only the fundamentals you will have to defend
- Write, in under two hundred words each, the answers to the two questions that follow almost any implementation: why this structure and not the obvious alternative, and what happens to this code at a hundred times the input.
- Write what an index actually costs: faster lookups on the indexed columns against a write that now maintains a second structure, plus the cases where the planner declines to use it anyway, low selectivity, or a predicate wrapping the column in a function.
- Delete any answer you cannot deliver aloud in under a minute, since an answer that needs reading is not an answer you have.
Deliverable: Three written answers, each under two hundred words and each timed aloud.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Your own work, timed
- Write a ninety-second and a four-minute version of your main project and time both aloud rather than reading them.
- Prepare the two follow-ups that always come: what you would do differently, and how you knew it worked.
- Put one number in the first sentence and be ready to say exactly where it came from and what it excludes.
Deliverable: Two timed narratives with one defensible number in the opening line.
Practice prompt ↗Practice prompt ↗06The one full rehearsal, in the weekend block
- Run a sixty-minute mock covering a coding round and a design round in one sitting with no break, because sustained attention is the thing evenings have not trained.
- Immediately afterwards, and before hearing any feedback, write the three moments you lost the thread.
- Spend the rest of the block only on those three moments, and on nothing you merely feel shaky about.
Deliverable: Mock notes naming three failure moments with a specific fix written under each.
Practice prompt ↗Practice prompt ↗07Taper
- Write the twenty-minute warm-up you will actually do on the morning: one problem you can already solve from a blank file, one design you can narrate, and nothing you have never seen.
- Re-read only your own notes from this week and open no new material.
- Write the logistics down: the editor or shared document you will be working in, whether execution and lookups are permitted, and the sentence you will use when you do not know something.
Deliverable: A one-page card holding the design structure, the project numbers, and the logistics.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Keep one story where the bad call was yours rather than a dependency's or a manager's. Name the check that would have caught it, whether you added that check afterwards, and whether it has fired since. Answers that route blame outward end the conversation early; answers that end in a guardrail someone still relies on tend to open it up.
Tell me about a complex technical problem you solved under tight deadl…
Tell me about a complex technical problem you solved under tight deadlines.
Approach
- Pick a story where you made the decision, not one where you watched it.
- State the situation in two sentences and spend the rest on the reasoning.
- 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?
What motivates you to build financial technology products in a high-gr…
What motivates you to build financial technology products in a high-growth environment?
Approach
- Close with what you would do differently, concretely.
- Name the disagreement and how you resolved it with evidence.
- Pick a story where you made the decision, not one where you watched it.
Follow-up
- What would you do differently if you ran that again?
- What did you decide not to do, and why?
Reverse a sharding decision after production contradicted it
To raise throughput past a single row's lock ceiling, you shard a hot settlement account balance into 16 sub-rows. Two weeks later the floor check has to sum all 16 under a stronger isolation level, contention has moved rather than gone, and operations cannot explain the balance to an auditor. Describe a decision you reversed. State what you believed when you made it, the measurement that changed your mind, how you unwound it without causing a second incident, and how long you waited before concluding the data was real rather than noise.
Approach
- The probe is whether you can hold a belief loosely and unwind your own work without ego. Begin with the reasoning that was correct at the time: a single balance row commits at roughly one write per lock hold, so at a 4 ms hold you get about 250 writes per second regardless of core count, and sharding is the standard answer to that ceiling.
- Name what the original reasoning missed rather than calling it a mistake in general. The floor predicate was a single-row CHECK before sharding and became a cross-row predicate after it, so every write now either sums the shards under SERIALIZABLE with a bounded retry on 40001 or locks them in a fixed order to avoid 40P01. The throughput gain is real but smaller than 16x, and the auditability cost was never priced.
- Give the measurement that decided it, with a before and an after: committed writes per second, p99 write latency, retry rate on 40001, and the time an analyst needs to reconstruct one balance. A reversal justified by feel is the generic answer.
- Describe the unwind as a migration, not a revert: shadow the consolidated balance, reconcile it against the sum of shards over a full business day including the cutoff, cut reads over first, then writes, keeping the shards readable until one full reconciliation cycle has passed clean.
- State the waiting rule you used before acting. Two weeks of a moving p99 can be a deploy or a traffic shift; a strong answer names the signal that separated a trend from noise, such as the retry rate persisting across a low-traffic weekend.
- Close with what you would keep. Some of the work is usually salvageable (the instrumentation, the lock ordering, the measured ceiling), and saying which parts survived shows the reversal was analysed rather than abandoned.
Follow-up
- You still need the throughput. What is the next thing you try, and what does it cost the floor check?
- How do you reconcile the sharded balance against the consolidated one during the migration without double counting entries posted mid-cut?
- What would you have measured before the original change that would have made the answer obvious?
- 01
Tell me about a complex technical problem you solved under tight deadlines.
- 02
What motivates you to build financial technology products in a high-growth environment?
- 03
To raise throughput past a single row's lock ceiling, you shard a hot settlement account balance into 16 sub-rows. Two weeks later the floor check has to sum all 16 under a stronger isolation level, contention has moved rather than gone, and operations cannot explain the balance to an auditor. Describe a decision you reversed. State what you believed when you made it, the measurement that changed your mind, how you unwound it without causing a second incident, and how long you waited before concluding the data was real rather than noise.
Is this an official Credit Genie interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Credit Genie. Rounds and questions reflect what candidates have reported, not a process Credit Genie 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 at Credit Genie?
The process is rigorous and thorough, featuring multiple technical rounds, live pair programming, and system design assessments. While challenging, candidates who have a strong grasp of core backend fundamentals and clean coding habits can navigate it successfully.
PracHub interview research ↗How much time should I spend preparing?
Most candidates benefit from 4 to 6 weeks of targeted preparation, focusing on data structures, system design patterns, and reviewing language-specific runtime mechanics.
PracHub interview research ↗What is the culture like during the technical interviews?
Interviews are interactive, professional, and designed to evaluate your actual engineering instincts. Interviewers appreciate direct communication, structured problem-solving, and candidates who treat the interview as a collaborative technical discussion.
PracHub interview research ↗What is the typical timeline from initial screen to offer?
The end-to-end process typically moves swiftly, often spanning two to four weeks from the initial recruiter kickoff to final executive conversations.
PracHub interview research ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24