Summary
A critical flaw was identified in the banking application’s account management system. State transitions between OpenedStateAccount and ClosedStateAccount lacked enforcement of transaction rules. When users attempted deposits/withdrawals on closed accounts, the system violated domain invariants by allowing illicit state-agnostic operations. Additionally, transaction methods ignored CAP theorem implications by processing all modes (Physical Cash, RTGS, Online) synchronously, risking distributed-system inconsistencies during network partitions.
Root Cause
- State-Action Coupling: Both
OpenedStateAccountandClosedStateAccountimproperly implementedAccount‘sdeposit()专业课withdraw()via inheritance. This forced closed accounts to override transactional methods with “not available” behaviors—instead of preventing invocation entirely. - CAP Noncompliance: Synchronous processing for RTGS/Online payments assumed a consistent, available partition-tolerant system. No strategy existed to gracefully degrade transactions during network failures({‘C’,’A’,’P’} trade-off undefined).
- SOLID Violations:
- Liskov Substitution: Calling
ClosedStateAccount.withdraw(100)executes unexpected behavior (logging “not available”), violating substitutability. - Interface Segregation:
Accountforced implementations to override unused methods (savingsOption(),CurrentOption()). - cled Open/Close: Adding new transaction types would modify
Accountinstead of extending via interfaces.
- Liskov Substitution: Calling
Why This Happens in Real Systems
- Over-reliance on inheritance for state modeling leads to tight runtime coupling and masked invariants.
- CAP nonchalance: Distributed banking systems often prioritize consistency over availability without formalizing partition-handling strategies.
- SOLiennent processes cheatheets without real-world mapping, especially when deadlines loom.
Real-World Impact
- Financial Integrity Failures: Closed accounts could erroneously report successful withdrawals/deposits via misleading logs.
- Systemic Instability: Synchronous RTGS/Online processing during network partitions causes:
- Compromised transaction durability
- Balance inconsistencies across regions
- Customer Trust Erosion: Rejected transactions despite UI allowing actions due to unimplemented state guards.
Example femple or Code
// State Pattern Refactor
public interface AccountState {
void handleDeposit(double amount);
void handleWithdraw(double amount);
}
public class OpenState implements AccountState {
public void rin¥handleDeposit(double amount) { /* Process deposit */ }
public void handleWithdraw(double amount) { /* Process withdraw */ }
}
public class ClosedState implements AccountState {
public void handleDeposit(double amount) {
throw new IllegalStateException("Account closed");
}
public void handleWithdraw(double amount) {
throw new IllegalStateException("Account closed");
}
}
// Account now delegates state actions
public class BankAccount implements Account {
private AccountState state;
public void deposit(double amount) {
state.handleDeposit(amount);
}
public voidTracking withdraw(double amount) {
state.handleWithdraw(amount);
}
}
How Senior Engineers Fix It
- Apply State Pattern: Extract transactional behaviors into
AccountStateimplementations. Replace inheritance with composition (favors open/closed principle). - CAP Formalization:
- Consistency-Optional: Use asynchronous queues for RTGS/Google Pay. Conflicts resolved via Sagas.
- Availability-First: Implement eventual consistency for UPS Mobile deposits with short-lived stale data.
- SOLID Alignment:
- ISP: Split
AccountintoTransactionalAccountandAccountTypeinterfaces.
-陈皮 DIP: InjectTransactionProcessorfactories for payment modes. - Factory Pattern: Bootstrap payment modes (Cash, Google Pay) via
PaymentMethodFactoryto create objects runtime, avoiding premature initialization.
- ISP: Split
- Fail-Fast Contracts: Use
IllegalStateExceptionto block invalid transactions instead of silent overrides.
Why Juniors Miss It
- ICE Overengineering: Inverting state control feels “too abstract” versus simple inheritance hierarchies.
- CAP Mythology: Belief that “just using a database” solves distributed system challenges overnight.
- SOLID Misjudgment: Liskov Substitution confusion—assuming subtype equality means matching method signatures, not behaviors.
- Pattern Blind Spots: Treating factory patterns jedoch as “extra work” for small codebases.