Separation of Concerns: Decoupling SDK Details from Business Logic
The article illustrates Separation of Concerns beyond AOP by refactoring a reconciliation service that mixes WeChat Pay and Alipay SDK calls with business logic, introducing a wrapper layer with custom types to isolate SDK-specific parsing from core matching rules, enabling independent evolution of each concern.
Direct SDK Usage in Business Code
The article opens with a typical reconciliation service that downloads bills from WeChat Pay and Alipay, parses them, and matches orders by transaction ID and amount. The initial implementation directly calls SDK types:
WxPayBillResult wxBill = wxPayService.downloadBill(date, "ALL");
List<AlipayBillDetail> aliBills = alipayBillService.queryBill(date, "trade");
for (WxPayBillDetail wx : wxBill.getDetails()) {
aliBills.stream().filter(a -> a.getTradeNo().equals(wx.getTransactionId()))
.forEach(a -> checkAmount(wx.getTotalFee(), a.getAmount()));
}This code works but has problems: SDK types ( WxPayBillResult, WxPayBillDetail, AlipayBillDetail) appear directly in the business method. WeChat returns a gzip-compressed CSV stream; Alipay returns JSON. All format-handling details are tangled with the reconciliation logic, making it hard to distinguish business rules from SDK plumbing. Moreover, any SDK upgrade that changes return types or method signatures forces changes to the reconciliation code even though the business rules haven't changed.
Viewing the Problem Through Separation of Concerns
The author identifies two distinct concerns:
Concern 1: How to fetch reconciliation data from payment channels. This involves calling SDKs, decompressing gzip streams, parsing CSV or JSON into structured data — purely technical implementation details.
Concern 2: How to perform reconciliation once data is obtained. This involves matching by order number, comparing amounts, flagging discrepancies — pure business logic.
The two concerns change for completely different reasons. SDK upgrades, channel switches, or format changes affect Concern 1. Rule adjustments or new verification dimensions affect Concern 2. Mixing them means a change in one forces a change in the other. For example, adding a UnionPay channel would require both new SDK call code and new branches in the reconciliation logic, even though the matching logic itself doesn't care about the data source.
Separating the Two Concerns
The solution introduces a wrapper layer between SDKs and business code, defining two custom types: ReconciliationRecord — a unified data structure carrying order number, channel, transaction amount, transaction time. ChannelBillFetcher — an interface with a single method to fetch a list of ReconciliationRecord for a given date.
WeChat and Alipay each implement ChannelBillFetcher. The implementation classes handle SDK calls and format conversion internally, exposing only ReconciliationRecord objects. The reconciliation service no longer touches any SDK types; it depends solely on these two abstractions.
After refactoring, the reconciliation code becomes:
List<ReconciliationRecord> records = fetchers.stream()
.flatMap(f -> f.fetch(date).stream()).toList();
matchByOrderAndCheckAmount(records);This code shows no trace of WeChat Pay or Alipay. A reader sees only: fetch records from all channels, then match by order and check amounts.
When an SDK upgrades, only the corresponding fetcher implementation changes; the reconciliation service remains untouched. When reconciliation rules change (e.g., adding fee verification), only matchByOrderAndCheckAmount is modified; channel implementations are unaffected. The two concerns now evolve independently without interfering with each other.
Summary
Separation of Concerns applies at multiple levels with different techniques. AOP handles cross-cutting concerns like logging and transactions. This article demonstrates another level: isolating third-party SDK implementation details from business logic. The wrapper layer is not gratuitous code; its purpose is to let each concern evolve independently, free from mutual interference.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
