Expense Policy Rule Checker with Rules Added Through an API
Company: Rippling
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
Build an expense rule checker for a company's expense policy. Employees submit expenses, and the checker evaluates every expense against the policy's rules and reports which expenses break which rules. The statement ends with a forward-looking requirement: the system must later support adding new rules through an API, so the set of rules cannot be fixed when the code is written. The round closed with a discussion of scale.
The report does not reproduce the statement's sample data or its list of rules; the illustration below is an assumption that makes the parts concrete.
```text
expenses (illustrative)
expense_id trip_id category vendor amount_usd
e1 t1 meals Cafe A 42.00
e2 t1 airfare Airline B 380.00
e3 t1 meals Restaurant C 95.00
e4 t2 entertainment Venue D 60.00
rules (illustrative)
r1 a meals expense must not exceed 75.00 USD
r2 entertainment expenses are not allowed
```
### Clarifying Questions
- Which fields does an expense carry, and which of them may a rule refer to?
- What should the checker return: for each rule the expenses that break it, for each expense the rules it breaks, or only pass or fail per expense? In what order?
- Do any rules apply to a group of expenses, such as the total of one trip, rather than to a single expense?
- How are amounts given (currency, number of decimal places), and are all amounts in one currency?
- Who calls the add-rule API, and must a newly added rule also apply to expenses that were already checked?
### Part 1 — Evaluate the rules
Given a list of expenses and a set of rules, return every violation: the rule and the expense that breaks it. On the illustration, expense e3 breaks r1 and expense e4 breaks r2.
```hint Keep the rules out of the loop
Write the evaluation loop so that it knows nothing about meals or entertainment: it should only ask each rule whether a given expense breaks it.
```
#### What This Part Should Cover
- A typed expense model with exact money handling
- A rule interface that the evaluation loop depends on, and a deterministic output order
- Correct results for expenses that no rule applies to and for an expense that breaks several rules
### Part 2 — Rules as data, added through an API
Represent each rule as data: an operand (an expense field), an operator and a value, optionally limited to the expenses that match a condition. Implement `add_rule` so that a new rule can be added at runtime, without a code change. Then compare this with writing each rule as a hardcoded evaluation function, and be ready to switch between the two: when is each the better choice?
```hint What the API can send
A rule that arrives through an API is untrusted data. Decide what must be checked before it is accepted, and what the engine must never do with the text it receives.
```
#### Clarifying Questions for this Part
- Which operators must be supported, and can the conditions in one rule be combined only with AND, or also with OR?
- Can rules be updated or deleted, or only added?
#### What This Part Should Cover
- A rule schema of operand, operator and value, with a condition that says which expenses the rule applies to
- Validation of a new rule at the API boundary
- The trade-off between data-driven rules and hardcoded evaluation functions, and a design that can hold both
### Part 3 — Scale
Discuss how the checker behaves as the number of expenses and rules grows, and how it would run as a service in which rules are added through the API while expenses keep arriving.
```hint Not every rule concerns every expense
Look at what most rules condition on, and how that could limit the rules you evaluate for one expense.
```
#### What This Part Should Cover
- The cost of evaluation as expenses times rules, and a way to skip rules that cannot apply
- Storing, versioning and distributing rules to the processes that evaluate them
- Re-checking existing expenses when a rule is added, with results that stay correct when a job is re-run
### What a Strong Answer Covers
- Settles the expense fields, the output shape and the scope of a rule before coding
- Separates rule definitions from the evaluation engine
- Exact money arithmetic and type-checked comparisons
- A validated rule format, with no evaluation of arbitrary code received through the API
- A clear view of when hardcoded rules are acceptable and when data-driven rules are required
- Tests per operator and per rule, and a scaling story that follows from the design
### Follow-up Questions
- A new rule limits the total of one trip's expenses rather than a single expense. What changes in the representation and in evaluation?
- A rule is edited after expenses were already approved under the old version. How do you record which version was applied, and do you re-check?
- Product asks for rules such as "meals over 75.00 USD unless the vendor is on an approved list". How far do you extend the rule format before it becomes a programming language?
- How do you stop one bad rule added through the API from breaking evaluation for everyone, for example a rule that names a field that does not exist?
Overview: A coding and design exercise: build an expense rule checker that evaluates employee expenses against policy rules and reports each violation, with new rules added later through an API. It tests representing rules as operand, operator and value versus hardcoded functions, validating untrusted rules, and scaling evaluation.