Shopify 自從 2022 大幅收緊 University Recruiting 後,2026 cycle 又把校招與 Early Career 通道重新開放——但 OA 也從過去的「一道 LC Medium」變成了一套業務導向極強的實戰題。本文基於一畝三分地、Reddit r/cscareerquestionsCAD 與 Glassdoor 上 2026-03 到 2026-05 的最新回饋,把 Shopify OA 的平台、題型、評分邏輯、Onsite 銜接講清楚。
Shopify OA 概覽
| 維度 | 細節 |
|---|---|
| 平台 | CodeSubmit(Backend 主流)/ HackerRank(Full-Stack 偶爾) |
| 時長 | 90-120 分鐘(Backend 90 / Full-Stack 120) |
| 題量 | 1-2 道開放式程式題(不是 LC 風格) |
| 難度 | LC Medium 演算法 + 業務建模 + 測試覆蓋 |
| 通過線 | 全部 hidden test 過 + 程式碼 review 評分 ≥ 7/10 |
| 回饋週期 | 5-14 天 |
| 二面 | Life Story 行為面 + Technical Pair Programming |
Shopify 獨特之處:OA 不是純演算法題,而是模擬真實業務——你交付的程式碼會被 Senior Engineer 像 PR review 一樣打分:可讀性、錯誤處理、測試組織都計分。Lambda 一行流不會加分,反而扣分。
真題一:Cart Inventory State Machine(購物車庫存狀態機)
題目描述
實作一個最小化 Cart 類別,支援以下方法:
add_item(product_id, qty):加入商品;若該 product 庫存不足回傳"OUT_OF_STOCK",否則回傳當前購物車總價remove_item(product_id, qty):移除商品;若購物車不存在該 product 回傳"NOT_FOUND"apply_discount(code):套用折扣碼;折扣碼與購物車狀態有關——總價 ≥ $100 才能用SAVE10checkout():原子性地扣減庫存並清空購物車;若任一商品在 checkout 時已不足,全部回滾並回傳"INVENTORY_CHANGED"
庫存與單價以建構子注入:Cart(inventory: dict, prices: dict)。
解題思路
這道題不是演算法題,是軟體工程題。Shopify 評分維度:
- 狀態機清晰:購物車有「待結算 / 結算中 / 已完成」三態,checkout 之前不要扣庫存
- 錯誤碼 vs 例外:題目要求回傳字串 → 不要 raise
- 原子性:checkout 失敗必須回滾——乾淨的寫法是先校驗再提交,不是「先扣再補」
- 可測性:庫存與價格透過 DI 注入,方便 mock
Python 解法
from collections import defaultdict
class Cart:
def __init__(self, inventory: dict, prices: dict):
self.inventory = dict(inventory)
self.prices = dict(prices)
self.items = defaultdict(int)
self.discount = 0.0
def _subtotal(self) -> float:
return sum(self.prices[p] * q for p, q in self.items.items())
def add_item(self, product_id, qty):
if self.inventory.get(product_id, 0) < self.items[product_id] + qty:
return "OUT_OF_STOCK"
self.items[product_id] += qty
return round(self._subtotal() * (1 - self.discount), 2)
def remove_item(self, product_id, qty):
if product_id not in self.items:
return "NOT_FOUND"
self.items[product_id] -= qty
if self.items[product_id] <= 0:
del self.items[product_id]
return round(self._subtotal() * (1 - self.discount), 2)
def apply_discount(self, code):
if code == "SAVE10" and self._subtotal() >= 100:
self.discount = 0.10
return "OK"
return "INVALID"
def checkout(self):
# 先全量校驗,再提交——避免部分扣減
for p, q in self.items.items():
if self.inventory.get(p, 0) < q:
return "INVENTORY_CHANGED"
for p, q in self.items.items():
self.inventory[p] -= q
total = round(self._subtotal() * (1 - self.discount), 2)
self.items.clear()
self.discount = 0.0
return total
時間複雜度:每次操作 O(k),k = 購物車 SKU 數
評分關鍵:checkout 的兩階段(驗證 + 提交)幾乎是必拿分點。先扣後補的解法即使 hidden test 全過,code review 分也會被扣 2 分以上。
真題二:GraphQL Webhook Idempotency(訂單 webhook 去重)
題目描述
Shopify 給商家推送訂單 webhook(POST 請求),但同一事件可能因為重試重複發送 2-5 次。每個 webhook payload 包含:
{ "event_id": "evt_abc", "order_id": 1001, "amount": 250.0, "ts": 1715000000 }
實作 WebhookHandler:
handle(payload) -> str:第一次處理某event_id回傳"PROCESSED",重複回傳"DUPLICATE"revenue_total() -> float:累計真實訂單金額(去重後)- 額外要求:記憶體只允許保留最近 24 小時的 event_id,超過的可以被遺忘
解題思路
經典「冪等性 + 滑動視窗」組合:
- 用
set存活躍 event_id;用deque按時間視窗滑動淘汰 revenue_total必須只統計未重複過的 event- 不要用
dict[event_id] = ts然後每次掃整個 dict 清理——O(n) per call 會在大資料量 hidden test 超時
Python 解法
from collections import deque
WINDOW = 24 * 60 * 60 # 24 hours in seconds
class WebhookHandler:
def __init__(self):
self.seen = set()
self.queue = deque() # (ts, event_id)
self.total = 0.0
def _evict(self, now):
while self.queue and self.queue[0][0] < now - WINDOW:
_, eid = self.queue.popleft()
self.seen.discard(eid)
def handle(self, payload):
eid = payload["event_id"]
ts = payload["ts"]
self._evict(ts)
if eid in self.seen:
return "DUPLICATE"
self.seen.add(eid)
self.queue.append((ts, eid))
self.total += payload["amount"]
return "PROCESSED"
def revenue_total(self):
return round(self.total, 2)
時間複雜度:handle 均攤 O(1)(每個 event_id 最多被 push/pop 一次)
陷阱:_evict 一定要用當前 payload 的 ts,而不是 time.time()——hidden test 會發送亂序時間戳來檢查這一點。
真題三:Product Tag Search(前綴 + 模糊比對)
題目描述
實作一個產品檢索服務,store 端會註冊大量商品標籤(如 ["organic", "vegan", "gluten-free"]),並支援:
index(product_id, tags: list[str])search(query: str) -> list[int]:回傳所有標籤包含 query 作為前綴的 product_id(按 product_id 升序)top_tags(k: int) -> list[str]:回傳出現次數 top-k 的 tag(出現次數相同按字典序)
解題思路
- 前綴檢索 → Trie(不要直接 substring 遍歷,hidden test 10w 商品會 TLE)
- top-k →
collections.Counter+heapq.nsmallest
Python 解法
from collections import Counter, defaultdict
import heapq
class TagSearch:
def __init__(self):
self.children = defaultdict(dict)
self.tag_to_products = defaultdict(set)
self.tag_count = Counter()
def _insert(self, tag, pid):
node = self.children
for ch in tag:
if ch not in node:
node[ch] = {}
node = node[ch]
node.setdefault("$products", set()).add(pid)
def _collect(self, node, out):
if "$products" in node:
out.update(node["$products"])
for k, v in node.items():
if k != "$products":
self._collect(v, out)
def index(self, pid, tags):
for t in tags:
self.tag_count[t] += 1
self.tag_to_products[t].add(pid)
self._insert(t, pid)
def search(self, query):
node = self.children
for ch in query:
if ch not in node:
return []
node = node[ch]
result = set()
self._collect(node, result)
return sorted(result)
def top_tags(self, k):
return [t for t, _ in heapq.nsmallest(
k, self.tag_count.items(), key=lambda x: (-x[1], x[0]))]
時間複雜度:index O(L),search O(L + R),L = 標籤長度,R = 命中商品數
備考策略
| 優先級 | 重點 | 推薦題號 / 資源 |
|---|---|---|
| ⭐⭐⭐ | 設計 / 狀態機 | LC 146、LC 460、LC 1396、LC 355 |
| ⭐⭐⭐ | Trie / 前綴樹 | LC 208、LC 211、LC 642 |
| ⭐⭐ | 滑動視窗 / 雙端佇列 | LC 239、LC 1438、LC 1004 |
| ⭐⭐ | OOP / 測試組織 | 自練:寫測試覆蓋率 ≥ 80% 的 mini-cart |
| ⭐ | GraphQL 基礎 | Shopify dev docs - GraphQL Admin API |
時間分配:90 分鐘 = 讀題 5 + 類別設計 10 + 寫第一版 35 + 寫測試 20 + debug 20。寫測試不是可選項——Shopify 的評分明確包含「test coverage」。
FAQ
Q1:Shopify OA 平台到底是 CodeSubmit 還是 HackerRank?
2026 Backend 職缺主要走 CodeSubmit——這是一個讓你下載 repo、本地寫、git push 提交的平台,更像真實專案。Full-Stack 與 Front-End 偶爾走 HackerRank,但比例不到 20%。CodeSubmit 沒有 hidden test 進度條,提交後 5-14 天才出結果。
Q2:Shopify OA 沒有 hidden test 進度條,怎麼知道自己寫對了?
寫自己的單元測試。CodeSubmit 提交後的 README 通常會要求 npm test 或 pytest 能跑通。評分官會先看你的測試覆蓋率——這是 Shopify 工程文化的體現。建議至少覆蓋:normal path、edge case(空輸入)、error path(無效 ID)、並發或時序(如適用)。
Q3:Shopify 後端用 Ruby on Rails,OA 必須用 Ruby 嗎?
不需要。CodeSubmit 倉庫通常給出 Ruby / Python / JS / Go / Java 多個 starter,選你最熟的就行。Senior Engineer review 的是程式碼組織而不是語言慣用法。不過如果你的履歷上寫「精通 Ruby」,又選其他語言,建議 Onsite 時準備解釋一下。
Q4:Shopify OA 通過後多久 onsite?
通常 2-3 週進入 Recruiter Call → Life Story 行為面(45 min)→ Technical Pair Programming(60 min)→ Hiring Manager。Life Story 是 Shopify 的招牌環節,從你的整個職業生涯順著講一遍,每段經歷追問「為什麼離開 / 加入 / 轉向」——準備至少 3 個職業轉折點的清晰敘事。
Q5:Shopify 2026 Early Career 在加拿大和美國職缺有什麼區別?
加拿大(Ottawa / Toronto / Remote-CA)名額較多,遠端 OK。美國職缺近兩年招聘極少,遠端美國常被拒絕——除非已有 work authorization。薪資:CAD New Grad 約 100-115K + RSU,US 等級折算後實際略高。
Q6:Shopify OA 第一次沒過,多久能重投?
12 個月窗口期。建議在第二次投遞前主動準備一份「工程改進筆記」:列出第一次 OA 你認為沒做好的點(測試、錯誤處理、命名)。Shopify recruiter 偶爾會讓你解釋這段反思——他們更看重「成長性」。
聯絡方式
正在準備 Shopify、Square、Stripe 這類業務導向 OA 的 candidate,最缺的不是演算法題,而是怎麼組織程式碼 + 寫出 PR 級別的測試。我們整理了 2025-2026 cycle 的 Shopify CodeSubmit 真題包(含完整可執行的多語言 starter + 評分標尺),歡迎聯絡交流。
立即加入微信 Coding0201,獲取 Shopify OA 真題與程式碼組織模板。
- Email:[email protected]
- Telegram:@OAVOProxy