# When to mock Mock at **system boundaries** only: - External APIs you do not control (Jira, Stripe, email, Infisical) - Time and randomness - Databases, sometimes, though a real local test instance is better where one exists - The filesystem, sometimes Do **not** mock your own modules, internal collaborators, or anything you control. A test that mocks what you own is asserting on your own wiring rather than on behaviour, and it will break on the first refactor that changes nothing a caller can see. Before mocking any dependency, understand what it actually does. A mock built on a guess about a dependency's side effects encodes the guess into the suite. ## Designing for substitutability ### Accept dependencies, do not construct them ```typescript // Easy to substitute at the seam function processPayment(order: Order, paymentClient: PaymentClient) { return paymentClient.charge(order.total); } // Welded in: nothing can stand in for the client function processPayment(order: Order) { const client = new StripeClient(process.env.STRIPE_KEY); return client.charge(order.total); } ``` ### Prefer an SDK-shaped interface over a generic fetcher One function per external operation, rather than a single generic call with conditional logic: ```typescript // GOOD: each operation is independently substitutable const api = { getUser: (id: string) => fetch(`/users/${id}`), getOrders: (userId: string) => fetch(`/users/${userId}/orders`), createOrder: (data: NewOrder) => fetch("/orders", { method: "POST", body: data }), }; // BAD: the stand-in needs conditional logic to know what it is being asked for const api = { fetch: (endpoint: string, options: RequestInit) => fetch(endpoint, options), }; ``` The SDK shape means each stand-in returns one specific type, no branching in test setup, an obvious read of which endpoints a test exercises, and type safety per operation. ## One adapter is not a seam Introducing a port because a single test wants to substitute at it is indirection, not design. One adapter means a hypothetical seam; two means a real one, and production-plus-test counts as two. Call the Skill tool with "codebase-design" when the seam placement itself is in question.