CodeOath
← All posts
Architecture & Patterns68 min total · 17 parts

Microservices vs. Monolith: The Trade You're Actually Making

Part 12 of 17 · ~2 min

Testing Across Service Boundaries

The monolith's integration tests ran real code across Subscriptions, Harvest, and Billing inside one process — fast, deterministic, nothing touching a network. Once they're separate deployables, actually proving two of them cooperate correctly means either bringing both up together, which is slower and needs its own test infrastructure, or building something convincing enough to stand in for the one you're not running.

Contract testing is Furrow's answer for the calls that matter most: Subscriptions, as a consumer of Harvest's reservation endpoint, defines the exact request and response shape it depends on; that contract gets checked against a mock in Subscriptions' own test suite, and separately checked against the real Harvest service in Harvest's test suite, to confirm it actually still honors that shape. A change to Harvest's response format that would silently break Subscriptions gets caught in Harvest's own CI run, without ever needing both services running together in one test environment — the cost is that the contract itself has to stay current as both sides evolve, and a stale contract that nobody updates is worse than no contract at all, because it creates false confidence.

Full end-to-end tests — placing a real order through real, running versions of all four services — still catch things contract tests structurally can't, mostly around genuine cross-service timing. But they're slow, and they're flaky in a specific new way: any one of four services having a bad five minutes fails the whole test, even when the actual thing being tested was fine. Furrow leans on a small number of these for the flows that matter most (a full box order end to end) and leaves the bulk of coverage to unit tests plus contract tests, which is the same test-pyramid shape as everything else, just with an added "which of four services is actually at fault here" layer on top when something does fail.