Build an Automatic Refund Decision System in a Pair-Programming Session

Read the full interview experience this question came from →

Quick Overview

A pair-programming exercise to build an automatic refund system for an online store, combining light system design with working code across several incremental steps. It tests domain modeling, pluggable eligibility rules, preventing over-refunds and duplicate payouts on retries, and explaining design choices as you code.

Build an Automatic Refund Decision System in a Pair-Programming Session

Company: Shopify

Role: Machine Learning Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

Build a small automatic refund system for an online store. Refund requests arrive against existing orders, and the system must decide, without a human in the loop, whether to refund, how much to refund and why, and then record the result so that the same money is never paid out twice. The exercise is a pair-programming session that combines a mini system design with working code. The requirements come as a written problem statement in a shared repository and are extended in several small follow-on steps; finishing every step is explicitly not the goal. The interviewer is watching how you model the domain, which edge cases you raise, and why you structure the code the way you do, so explain your design choices as you build. ```hint Keep the decision pure Separate deciding a refund from carrying it out. If the decision depends only on the order, its refund history and the request, every rule can be tested on its own before any payment call exists. ``` ```hint Expect the same request twice Ask what should happen when a client retries a request after a timeout, or when two requests for the same order arrive at almost the same moment. ``` ### Constraints and Clarifications - The session lasts 75 minutes, including setting up the shared repository and a closing discussion. - A refund request identifies an order and what the customer wants back. - The concrete eligibility rules are part of what you must clarify. This practice version fixes only two invariants that hold for any refund system: - the total refunded for an order can never exceed the amount paid for it; - a request that is submitted again (a retry) must not produce a second refund. ### Clarifying Questions - Which conditions make a request eligible for an automatic refund: the order's status (not yet shipped, delivered), the time since purchase or delivery, the requested amount, the stated reason, or the customer's refund history? What are the limits for each? - Are only full refunds supported, or partial refunds by amount or by line item? Do shipping and tax come back with the items? - When a request does not qualify automatically, is it rejected outright or queued for a person to review? - Is the refund issued immediately through a payment provider, or recorded now and executed later? What should happen if the payment call fails? - Is an in-memory implementation with a small API acceptable, or is persistence part of the task? - How is a retry recognized: by a client-supplied request identifier, or by matching the order and the amount? ### What a Strong Answer Covers - A domain model (orders, payments, refund requests, refund records, decisions) in which the over-refund invariant is enforced in exactly one place. - Eligibility rules structured so that each follow-on step adds or changes a rule without rewriting the earlier ones, with a reason attached to every decision. - Correct money handling across several partial refunds, including the numeric type used for amounts. - Idempotent handling of retried requests and a stated approach to concurrent requests for the same order. - Edge cases raised proactively and confirmed with the interviewer, backed by quick tests for each rule. - A clear explanation of design choices while keeping a working increment at every step. ### Follow-up Questions - The service now runs on several instances behind a load balancer with a shared database. How do you guarantee an order is never over-refunded when two requests for it land on different instances? - The payment provider times out after your system has decided to refund. How do you find out whether the money moved, and how do you reconcile your records? - The business wants a refund-abuse model score to influence the decision. Where does it plug into your rules, and how do you keep automatic decisions bounded and explainable? - Operations staff want to change thresholds without a deploy. How would you make the policy configurable while recording which policy version made each decision?

Overview: A pair-programming exercise to build an automatic refund system for an online store, combining light system design with working code across several incremental steps. It tests domain modeling, pluggable eligibility rules, preventing over-refunds and duplicate payouts on retries, and explaining design choices as you code.

Read the full Shopify Machine Learning Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/Shopify
Shopify logo
Shopify
Sep 9, 2026
mediumMachine Learning EngineerTechnical ScreenSoftware Engineering Fundamentals
0
0

Build a small automatic refund system for an online store. Refund requests arrive against existing orders, and the system must decide, without a human in the loop, whether to refund, how much to refund and why, and then record the result so that the same money is never paid out twice.

The exercise is a pair-programming session that combines a mini system design with working code. The requirements come as a written problem statement in a shared repository and are extended in several small follow-on steps; finishing every step is explicitly not the goal. The interviewer is watching how you model the domain, which edge cases you raise, and why you structure the code the way you do, so explain your design choices as you build.

Constraints and Clarifications

  • The session lasts 75 minutes, including setting up the shared repository and a closing discussion.
  • A refund request identifies an order and what the customer wants back.
  • The concrete eligibility rules are part of what you must clarify. This practice version fixes only two invariants that hold for any refund system:
    • the total refunded for an order can never exceed the amount paid for it;
    • a request that is submitted again (a retry) must not produce a second refund.

Clarifying Questions Guidance

  • Which conditions make a request eligible for an automatic refund: the order's status (not yet shipped, delivered), the time since purchase or delivery, the requested amount, the stated reason, or the customer's refund history? What are the limits for each?
  • Are only full refunds supported, or partial refunds by amount or by line item? Do shipping and tax come back with the items?
  • When a request does not qualify automatically, is it rejected outright or queued for a person to review?
  • Is the refund issued immediately through a payment provider, or recorded now and executed later? What should happen if the payment call fails?
  • Is an in-memory implementation with a small API acceptable, or is persistence part of the task?
  • How is a retry recognized: by a client-supplied request identifier, or by matching the order and the amount?

What a Strong Answer Covers Guidance

  • A domain model (orders, payments, refund requests, refund records, decisions) in which the over-refund invariant is enforced in exactly one place.
  • Eligibility rules structured so that each follow-on step adds or changes a rule without rewriting the earlier ones, with a reason attached to every decision.
  • Correct money handling across several partial refunds, including the numeric type used for amounts.
  • Idempotent handling of retried requests and a stated approach to concurrent requests for the same order.
  • Edge cases raised proactively and confirmed with the interviewer, backed by quick tests for each rule.
  • A clear explanation of design choices while keeping a working increment at every step.

Follow-up Questions Guidance

  • The service now runs on several instances behind a load balancer with a shared database. How do you guarantee an order is never over-refunded when two requests for it land on different instances?
  • The payment provider times out after your system has decided to refund. How do you find out whether the money moved, and how do you reconcile your records?
  • The business wants a refund-abuse model score to influence the decision. Where does it plug into your rules, and how do you keep automatic decisions bounded and explainable?
  • Operations staff want to change thresholds without a deploy. How would you make the policy configurable while recording which policy version made each decision?
Loading comments...