cswork / libraryOpen practice workspace

Interview guides · Peerfit

Peerfit Software Engineer Interview Guide

Peerfit Software Engineer interview guide: reported rounds, questions and how candidates describe the process.

The 60-second brief

A Software Engineer at Peerfit plays a critical role in building, scaling, and maintaining the core platform that connects employers, employees, and fitness partners. Peerfit operates in the wellness and digital health space, meaning our engineering team handles complex user ecosystems, real-time booking integrations, corporate wellness benefit calculations, and partner-facing tools. As an engineer here, your work directly impacts how seamlessly users can access wellness services, making system reliability, clean architecture, and intuitive design top priorities. The engineering team at Peerfit values high-quality, maintainable code and a highly collaborative approach to product development.

This guide is scoped to a Software Engineer candidate at Peerfit.

Focus areas

  • Software Development Life Cycle (SDLC)
  • Integration with Existing Systems
  • Maintainable Code (Code Quality)

The Peerfit interview process

Peerfit candidates report 4 rounds over 3-5 weeks. The stages below are what candidates describe, not a published process.

Initial Conversation

Discussion with a department manager about your technical background, career goals, and interest in the company.

What to demonstrate

  • Discussion with a department manager about your technical background, career goals, and interest in the company
  • Depth in Software Development Life Cycle (SDLC)

How to prepare

  • Answer aloud and timed: Implement a hand evaluator for a custom game of poker (the Poker Challenge).
  • Answer aloud and timed: Design and implement a scoring calculator for a game of Yatzy, ensuring all edge cases and scoring categories are handled.

Take-Home Assignment

Complete a practical coding assignment, such as the Poker Challenge, to demonstrate coding standards and architecture choices.

What to demonstrate

  • Complete a practical coding assignment, such as the Poker Challenge, to demonstrate coding standards and architecture choices
  • Depth in Software Development Life Cycle (SDLC)

How to prepare

  • Answer aloud and timed: How do you structure your unit tests to ensure that complex game logic is fully verified?
  • Answer aloud and timed: Describe how you would refactor a highly nested piece of conditional logic to make it more readable and maintainable.

Live Technical Discussion

Participate in a live coding session, often centered around a logic puzzle like the Yatzy Challenge.

What to demonstrate

  • Participate in a live coding session, often centered around a logic puzzle like the Yatzy Challenge
  • Depth in Software Development Life Cycle (SDLC)

How to prepare

  • Answer aloud and timed: How do you work with collaborators like copywriters, graphic designers, and project managers to bring a feature to life?
  • Answer aloud and timed: Describe a time when you had to integrate a new application with an existing, legacy system. What challenges did you face, and how did you resolve them?

Cultural Fit Assessment

Engage in deep dives with engineering peers and HR to evaluate collaboration style and fit within the team.

What to demonstrate

  • Engage in deep dives with engineering peers and HR to evaluate collaboration style and fit within the team
  • Depth in Software Development Life Cycle (SDLC)

How to prepare

  • Answer aloud and timed: How do you translate high-level business requirements from non-technical stakeholders into detailed technical specifications?
  • Answer aloud and timed: What is your process for writing and maintaining technical design documents and software instructions?

Where candidates lose points

Structure your code for readability

During the take-home and live coding assessments, prioritize clean, readable code over clever, highly compressed syntax. Use descriptive variable names and organize your logic in a way that is easy for another engineer to follow.

Emphasize your collaboration experience

Be ready to share concrete examples of how you have worked with designers, copywriters, and product managers in the past. Highlight how you handle differing opinions and align on technical solutions.

Explain your thought process out loud

During the live coding sessions, talk through your decisions, trade-offs, and assumptions. This helps interviewers understand how you approach problem-solving and how you handle unexpected challenges.

Do not skip writing tests for your technical assessments

Even if a take-home challenge seems straightforward, including a robust set of unit tests demonstrates engineering discipline and a commitment to software quality.

Questions & practice

Implement a hand evaluator for a custom game of poker (the Poker Challenge).

Medium · Coding & Game Logic Challenges

Approach

  1. Restate the input: its shape, its size, and what is guaranteed about it.
  2. Name the brute-force solution and its complexity before improving on it.
  3. Choose the data structure from the access pattern, not from familiarity.
  4. State the target complexity and say which constraint rules the naive version out.

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?

How do you structure your unit tests to ensure that complex game logic is fully verified?

Medium · Coding & Game Logic Challenges

Approach

  1. Restate the input: its shape, its size, and what is guaranteed about it.
  2. Name the brute-force solution and its complexity before improving on it.
  3. Choose the data structure from the access pattern, not from familiarity.
  4. State the target complexity and say which constraint rules the naive version out.

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?

Describe how you would refactor a highly nested piece of conditional logic to make it more readable and mainta

Medium · Coding & Game Logic Challenges

Describe how you would refactor a highly nested piece of conditional logic to make it more readable and maintainable.

Approach

  1. Restate the input: its shape, its size, and what is guaranteed about it.
  2. Name the brute-force solution and its complexity before improving on it.
  3. Choose the data structure from the access pattern, not from familiarity.
  4. State the target complexity and say which constraint rules the naive version out.

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?

How do you work with collaborators like copywriters, graphic designers, and project managers to bring a featur

Medium · Technical Collaboration & System Integra

How do you work with collaborators like copywriters, graphic designers, and project managers to bring a feature to life?

Approach

  1. Restate the input: its shape, its size, and what is guaranteed about it.
  2. Name the brute-force solution and its complexity before improving on it.
  3. Choose the data structure from the access pattern, not from familiarity.
  4. State the target complexity and say which constraint rules the naive version out.

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?

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.

Approach

  1. Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
  2. Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
  3. Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
  4. State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.

Follow-up

  • A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
  • The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?

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

  1. 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.
  2. 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.
  3. 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.
  4. 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?

Design and implement a scoring calculator for a game of Yatzy, ensuring all edge cases and scoring categories

Medium · Coding & Game Logic Challenges

Design and implement a scoring calculator for a game of Yatzy, ensuring all edge cases and scoring categories are handled.

Approach

  1. Fix the scope first: who calls this, how often, and what they do when it fails.
  2. Name the read and write paths separately; they rarely have the same bottleneck.
  3. Choose a partition key and say what query it makes expensive.
  4. State the consistency you need, and where you are willing to be stale.

Follow-up

  • What breaks first when traffic grows ten times?
  • How does this behave when that dependency is down for an hour?

How do you translate high-level business requirements from non-technical stakeholders into detailed technical

Medium · Technical Collaboration & System Integra

How do you translate high-level business requirements from non-technical stakeholders into detailed technical specifications?

Approach

  1. Say who the caller is and what they do when the call fails halfway.
  2. Define the identity of a request so a retry cannot double-apply it.
  3. Separate accepted, pending, failed and confirmed; they are different facts.
  4. Design the error taxonomy before the success shape; callers branch on it.

Follow-up

  • What happens if the caller retries after a timeout?
  • How does a client discover it is on an old version of this contract?

What is your process for writing and maintaining technical design documents and software instructions?

Medium · Technical Collaboration & System Integra

Approach

  1. Say who the caller is and what they do when the call fails halfway.
  2. Define the identity of a request so a retry cannot double-apply it.
  3. Separate accepted, pending, failed and confirmed; they are different facts.
  4. Design the error taxonomy before the success shape; callers branch on it.

Follow-up

  • What happens if the caller retries after a timeout?
  • How does a client discover it is on an old version of this contract?

How do you effectively estimate project work, and what is your process when you realize a development timeline

Medium · Execution, Estimation & Best Practices

How do you effectively estimate project work, and what is your process when you realize a development timeline might be impacted?

Approach

  1. Clarify what is being asked and what a complete answer contains.
  2. State your assumptions explicitly before working the problem.
  3. Say what you would check first and why it is the highest-information step.
  4. Work from the requirement backwards to the design.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

What strategies do you use to diagnose and resolve critical production bugs quickly and efficiently?

Medium · Execution, Estimation & Best Practices

Approach

  1. Clarify what is being asked and what a complete answer contains.
  2. State your assumptions explicitly before working the problem.
  3. Say what you would check first and why it is the highest-information step.
  4. Work from the requirement backwards to the design.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

How do you actively contribute to conforming to and improving a team's software development life cycle (SDLC)?

Medium · Execution, Estimation & Best Practices

Approach

  1. Clarify what is being asked and what a complete answer contains.
  2. State your assumptions explicitly before working the problem.
  3. Say what you would check first and why it is the highest-information step.
  4. Work from the requirement backwards to the design.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

Read latency spikes on a sixty-second sawtooth

Medium · cache stampede · single-flight · ttl

The cached listing read path serves about 14k reads/second at an 85% hit rate. p99 sits at 35 ms for 57 seconds, jumps to 900 ms for 3, and repeats. During each spike the primary shows several hundred identical listing queries starting within the same millisecond, all carrying one large tenant's id. Cache entries use a 60-second TTL. Give the mechanism, the ordered checks, the fix, and the correctness hazard your fix must not introduce.

Approach

  1. Match the period to a configured number before theorising about load. A spike every 60 seconds against a 60-second TTL is an entry expiring, and you confirm it by correlating spike timestamps with the entry's write time rather than with the traffic curve. If the period had matched a cron or a GC interval instead, this is a different investigation.
  2. Establish the concurrency of the miss. Several hundred identical queries in one millisecond means the miss path has no coalescing: every request that arrives between expiry and repopulation recomputes. The herd size is that key's arrival rate times its recompute time, so at 1.2k reads/second for the hot key and a 250 ms recompute you expect about 300 concurrent misses, which matches what is observed.
  3. Add single-flight on the miss path so one caller per key recomputes under a short-lived lock while the rest wait for its result. Prefer stale-while-revalidate where the read tolerates it: return the expired value immediately and refresh asynchronously, which removes the latency spike rather than serialising it into a queue of waiters.
  4. De-synchronise the keys. Write TTLs with jitter, for example 60 seconds plus or minus 10%, so a deploy or a mass invalidation does not align every key on the same second and turn a per-key herd into a fleet-wide one.

Follow-up

  • The same sawtooth appears on a key that is invalidated on write rather than expired. Is that the same bug?
  • How does your answer change if the recompute takes 4 seconds instead of 250 ms?

Suggested practice checklist

Built from the rounds and topics Peerfit candidates report.

Day 1 — Map the Peerfit loop

  • Write out the reported sequence: Initial Conversation, Take-Home Assignment, Live Technical Discussion, Cultural Fit Assessment.
  • For each round, write one sentence on what it is judging, from the description above, and mark the one you are least ready for.

Deliverable: A one-page map of the 4 reported rounds, with the weakest marked.

Day 2 — Work Software Development Life Cycle (SDLC)

  • Spend the session on Software Development Life Cycle (SDLC), which Peerfit candidates report being tested on.
  • Write one worked example in Software Development Life Cycle (SDLC) and time yourself on it.

Deliverable: One timed worked example in Software Development Life Cycle (SDLC).

Day 3 — Work Integration with Existing Systems

  • Spend the session on Integration with Existing Systems, which Peerfit candidates report being tested on.
  • Write one worked example in Integration with Existing Systems and time yourself on it.

Deliverable: One timed worked example in Integration with Existing Systems.

Day 4 — Work Maintainable Code (Code Quality)

  • Spend the session on Maintainable Code (Code Quality), which Peerfit candidates report being tested on.
  • Write one worked example in Maintainable Code (Code Quality) and time yourself on it.

Deliverable: One timed worked example in Maintainable Code (Code Quality).

Day 5 — Answer out loud: Coding & Game Logic Challenges

  • Answer aloud, timed: Implement a hand evaluator for a custom game of poker (the Poker Challenge).
  • Answer aloud, timed: Design and implement a scoring calculator for a game of Yatzy, ensuring all edge cases and scoring categories are handled.

Deliverable: Spoken answers to 2 reported Coding & Game Logic Challenges question(s), under time.

Day 6 — Answer out loud: Technical Collaboration & System Integration

  • Answer aloud, timed: How do you work with collaborators like copywriters, graphic designers, and project managers to bring a feature to life?
  • Answer aloud, timed: Describe a time when you had to integrate a new application with an existing, legacy system. What challenges did you face, and how did you resolve them?

Deliverable: Spoken answers to 2 reported Technical Collaboration & System Integration question(s), under time.

Day 7 — Answer out loud: Execution, Estimation & Best Practices

  • Answer aloud, timed: How do you effectively estimate project work, and what is your process when you realize a development timeline might be impacted?
  • Answer aloud, timed: Describe your approach to giving and receiving thoughtful feedback during code reviews.

Deliverable: Spoken answers to 2 reported Execution, Estimation & Best Practices question(s), under time.

Behavioural preparation

Behavioural rounds judge the decision you made and what it cost.

Describe a time when you had to integrate a new application with an existing, legacy system. What challenges d

Medium · Technical Collaboration & System Integra

Describe a time when you had to integrate a new application with an existing, legacy system. What challenges did you face, and how did you resolve them?

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.
  4. Name the disagreement and how you resolved it with evidence.

Follow-up

  • What would you do differently if you ran that again?
  • How did you know your change caused the improvement?

Describe your approach to giving and receiving thoughtful feedback during code reviews.

Medium · Execution, Estimation & Best Practices

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.
  4. Name the disagreement and how you resolved it with evidence.

Follow-up

  • What would you do differently if you ran that again?
  • How did you know your change caused the improvement?

Unblock an engineer without taking the keyboard

Easy · mentoring · leases · at-least-once

A teammate has spent two days on a job handler that occasionally writes duplicate rows. They are certain the queue is delivering twice by mistake. You suspect a lease expiring under a slow handler, so the job is running concurrently with itself. Describe how you have unblocked someone in this position: what you asked before offering a hypothesis, what you showed them rather than told them, and what you left them owning. Then say what you would do if their theory turned out to be the right one.

Approach

  1. Ask before diagnosing, and ask for things answerable from data they already have: the attempt count on the job rows that produced duplicates, the handler's observed duration against its lease expiry, and whether the duplicate rows share a natural key that a unique constraint could have caught.
  2. Teach the shape rather than the answer. A lease cannot distinguish a dead worker from a slow one, so a handler that outruns its lease is running twice by design, and deploys deliver the other half by killing handlers mid-run on every rollout. Both of their candidate theories produce identical duplicate rows, which is why the evidence has to come from timings rather than from argument.
  3. Hand over a checklist they execute: a natural key on every write the handler performs so the second copy collides rather than appends, the record of intent written before any external effect, a lease heartbeat while running, and the metric that shows it working.
  4. Keep ownership with them deliberately. Pair on the first write, then step back; if you finish it yourself you have closed one ticket and left the same person stuck on the next redelivery.

Follow-up

  • How would you distinguish a genuine double-delivery from a lease expiry using only the data already stored?
  • Their handler calls an external endpoint before recording that it did. What do you tell them to change first?