The Legacy Migrator’s Diary: Week 3
The Liskov Substitution Principle Meets the Reliability Pillar
The Legacy Migrator’s Diary: Week 3
The Liskov Substitution Principle Meets the Reliability Pillar
The Journal Entry
It’s Thursday, Week 3, and we almost lost a massive chunk of revenue today. A junior engineer deployed a new PromoCheckoutService subclass to handle seasonal marketing discounts. On paper, it passed all automated unit tests because it executed without throwing a single exception.
But it violated the Liskov Substitution Principle (LSP) in the worst way possible. LSP states that objects of a superclass should be replaceable with objects of its subclasses without breaking the application’s behavioral contract.
Our base class contract guarantees that a successful checkout always returns a valid, non-null PaymentReceipt string. The new promo subclass, however, altered this behavior: when an order was 100% discounted, it returned a null receipt. Our downstream transaction tracking engine completely choked on that null value, halting data streaming to our analytics pipeline. The container stayed perfectly healthy according to traditional CPU/Memory metrics, but we were suffering from a Silent Data Corruption emergency.
To satisfy the AWS Well-Architected Reliability Pillar, a system must automatically recover from failures. We can’t just rely on basic infrastructure metrics; our C# code must actively enforce its behavioral contracts and signal the infrastructure to self-heal when an LSP breach corrupts the runtime state!
The Refactoring Ledger
The Before: The Behavior-Breaking Subclass
Here is the malicious subclass that violated the contract of the base class. It returned a null reference, causing the core container to drift into an unrecoverable, corrupt state without crashing the process.
public class BaseCheckoutService
{
public virtual async Task<PaymentReceipt> ChargeAsync(Order order)
{
// Contract: Always returns a concrete receipt instance with a tracking ID
return await DefaultPaymentGateway.ProcessAsync(order);
}
}
// THE LSP VIOLATION: Subclass changes expected behavior based on internal state
public class PromoCheckoutService : BaseCheckoutService
{
public override async Task<PaymentReceipt> ChargeAsync(Order order)
{
if (order.IsTotalDiscount)
{
// VIOLATION: Returns null instead of an empty/specialized receipt instance.
// This breaks downstream code expecting a valid object contract!
return null;
}
return await base.ChargeAsync(order);
}
}
Why this fails Reliability: Traditional infrastructure monitoring thinks the container is fine because the CPU usage is 2%. Meanwhile, your application logic is dead locked or dropping messages silently because of a null-pointer data corruption state.
The After: LSP Enforcement & Automated Fargate Self-Healing
We refactored the C# code to strictly enforce behavioral contracts by throwing an explicit, domain-specific ContractViolationException the second a subclass behaves unexpectedly.
Then, we hooked this directly into the ASP.NET Core Health Checks framework. When our application detects an irrecoverable state corruption, it flips its internal health status to Unhealthy. Because our core application runs in an ECS Fargate container, the attached AWS Application Load Balancer (ALB) instantly notices the failed /health endpoint, terminates the corrupted container task, and spins up a fresh, clean instance automatically!
- Enforcing the Contract in C#
public class ReliableCheckoutEngine
{
private readonly BaseCheckoutService _checkoutService;
private readonly IClusterHealthRegistry _healthRegistry;
public ReliableCheckoutEngine(BaseCheckoutService checkoutService, IClusterHealthRegistry healthRegistry)
{
_checkoutService = checkoutService;
_healthRegistry = healthRegistry;
}
public async Task ExecuteOrderAsync(Order order)
{
var receipt = await _checkoutService.ChargeAsync(order);
// LISKOV PROTECTION: Explicit validation to guard the base contract
if (receipt == null)
{
// Mark the container as corrupt in the global health state
_healthRegistry.FlagCorruptedState("LSP_Violation_NullReceipt");
throw new ContractViolationException("Subclass failed to return a valid payment receipt.");
}
await ProcessDownstreamReceiptAsync(receipt);
}
}
- The Custom C# Cloud Health Check
using Microsoft.Extensions.Diagnostics.HealthChecks;
public class ClusterStateHealthCheck : IHealthCheck
{
private readonly IClusterHealthRegistry _healthRegistry;
public ClusterStateHealthCheck(IClusterHealthRegistry healthRegistry)
{
_healthRegistry = healthRegistry;
}
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken token = default)
{
if (_healthRegistry.IsCorrupted)
{
// Returning Unhealthy signals the AWS ALB to kill this specific container
return Task.FromResult(HealthCheckResult.Unhealthy($"Task State Corrupted: {_healthRegistry.Reason}"));
}
return Task.FromResult(HealthCheckResult.Healthy("Container operating normally within contracts."));
}
}
The Reliability Win
By applying the Liskov Substitution Principle, we closed the dangerous gap between software runtime behavior and cloud infrastructure management. Our code no longer tolerates silent contract drift. If a subclass behaves unpredictably, the application catches it immediately, flags itself as unhealthy, and lets ECS Fargate’s automated health checks handle the demolition and replacement of the container task smoothly.
메타데이터
- post_id
- f9319a64bdcc
- slug
- the-legacy-migrators-diary-week-3-f9319a64bdcc
- url
- https://medium.com/@naved-shaikh/the-legacy-migrators-diary-week-3-f9319a64bdcc
- canonical_url
- https://medium.com/@naved-shaikh/the-legacy-migrators-diary-week-3-f9319a64bdcc
- author_url
- https://medium.com/@naved-shaikh
- status
- ok
- fetched_at
- 2026-07-13 06:23:13