Capstone Milestone: Where Theory Becomes Architecture
In this capstone, we will not construct trivial textbook snippets. We will dissect a real-world business workflow, identify domain entities, establish state and invariants, and assemble an executable Python architecture that honors every core tenet of modern object-oriented software engineering.
01 Problem Statement & Candidate Concepts
Our e-commerce checkout engine has clear, unambiguous functional requirements:
These specifications directly map to our core domain relationships:
Order → OrderItem[] (Price Snapshot) → Product
CheckoutService → (Order, PaymentMethod, NotificationService)
02 Step-by-Step Domain Modeling & Code Construction
Let us construct each class systematically, ensuring clear demarcation of responsibilities:
class Product:
def __init__(self, product_id: int, name: str, price: float, stock: int):
self.product_id = product_id
self.name = name
self.price = price
self.stock = stock
def is_available(self, quantity: int = 1) -> bool:
return self.stock >= quantity
class CartItem:
def __init__(self, product: Product, quantity: int):
self.product = product
self.quantity = quantity
def subtotal(self) -> float:
return self.product.price * self.quantity
class Cart:
def __init__(self):
self.items: list[CartItem] = []
def add_item(self, product: Product, quantity: int = 1):
if not product.is_available(quantity):
raise ValueError(f"Insufficient stock for {product.name} (Available: {product.stock})")
self.items.append(CartItem(product, quantity))
def remove_item(self, product_id: int):
self.items = [item for item in self.items if item.product.product_id != product_id]
def calculate_total(self) -> float:
return sum(item.subtotal() for item in self.items)
def clear(self):
self.items.clear()
class Customer:
def __init__(self, customer_id: int, name: str, email: str):
self.customer_id = customer_id
self.name = name
self.email = email
self.cart = Cart() # Customer HAS-A Cart (Composition)
class OrderItem:
def __init__(self, product: Product, quantity: int):
self.product = product
self.quantity = quantity
self.unit_price = product.price # Permanent immutable snapshot of catalog price
def subtotal(self) -> float:
return self.unit_price * self.quantity
class Order:
def __init__(self, order_id: int, customer: Customer, cart_items: list[CartItem]):
self.order_id = order_id
self.customer = customer
self.items = [OrderItem(item.product, item.quantity) for item in cart_items]
self.status = "Pending"
def calculate_total(self) -> float:
return sum(item.subtotal() for item in self.items)
def mark_as_paid(self):
if self.status != "Pending":
raise ValueError(f"Invalid state transition: Cannot mark {self.status} order as Paid")
self.status = "Paid"
def complete(self):
if self.status != "Paid":
raise ValueError("Order must be Paid before it can be marked Completed")
self.status = "Completed"
def cancel(self):
if self.status == "Completed":
raise ValueError("Cannot cancel an already completed order")
self.status = "Cancelled"
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount: float) -> bool:
pass
class CardPayment(PaymentMethod):
def pay(self, amount: float) -> bool:
print(f"💳 [Card] Charged ${amount:.2f} via credit card successfully.")
return True
class MobilePayment(PaymentMethod):
def __init__(self, wallet_number: str):
self.wallet_number = wallet_number
def pay(self, amount: float) -> bool:
print(f"📱 [Mobile Wallet] Charged ${amount:.2f} from wallet {self.wallet_number}.")
return True
class NotificationService:
def send_order_confirmation(self, order: Order):
print(f"✉️ [Notification] Order #{order.order_id} confirmation dispatched to {order.customer.email}.")
class CheckoutService:
def __init__(self, notification_service: NotificationService):
# Injected dependency (Dependency Injection)
self.notification_service = notification_service
def checkout(self, customer: Customer, payment_method: PaymentMethod, order_id: int) -> Order:
if not customer.cart.items:
raise ValueError("Cannot checkout an empty cart!")
# 1. Instantiate order with snapshotted items
order = Order(order_id, customer, customer.cart.items)
total = order.calculate_total()
# 2. Polymorphic charge delegation
if not payment_method.pay(total):
raise ValueError("Payment transaction declined!")
# 3. Transition order status & flush temporary cart
order.mark_as_paid()
customer.cart.clear()
# 4. Dispatch notification receipt
self.notification_service.send_order_confirmation(order)
return order
03 System Simulation & Live Verification
Let us test the integrated pipeline end-to-end:
# 1. Instantiate Catalog Products & Customer
laptop = Product(product_id=1, name="ThinkPad Laptop", price=1200.0, stock=5)
mouse = Product(product_id=2, name="Logitech Mouse", price=25.0, stock=20)
customer = Customer(customer_id=101, name="Salim", email="salim@byteion.com")
# 2. Add merchandise to customer cart
customer.cart.add_item(laptop, quantity=1)
customer.cart.add_item(mouse, quantity=2)
print(f"🛒 Cart Total: ${customer.cart.calculate_total():.2f}")
# Output: $1250.00 (1200 + 25*2)
# 3. Assemble Checkout Engine with Injected Services
notifier = NotificationService()
checkout_engine = CheckoutService(notification_service=notifier)
mobile_pay = MobilePayment(wallet_number="+15550198")
# 4. Execute Checkout Workflow
confirmed_order = checkout_engine.checkout(customer, payment_method=mobile_pay, order_id=5001)
# 5. Verify Invariants
print(f"📦 Order Status: {confirmed_order.status}")
print(f"🛒 Remaining Cart Items: {len(customer.cart.items)}")
# 6. Complete Delivery Fulfillment
confirmed_order.complete()
print(f"🚚 Post-Delivery Status: {confirmed_order.status}")
04 Mapping the Pillars to Real Architecture
Notice how every pillar we mastered across the curriculum fell organically into place:
| OOP Concept | Implementation in Capstone | Architectural Value |
|---|---|---|
| Class & Object | Product, Cart, Order, Customer blueprints & instances | Expresses the business domain in coherent software models |
| Encapsulation | Order state transitions via mark_as_paid() & complete() |
Shields financial state against invalid or out-of-order mutations |
| Abstraction | PaymentMethod(ABC) interface |
Decouples checkout business logic from gateway payment mechanics |
| Inheritance | CardPayment and MobilePayment subclassing PaymentMethod | Guarantees adherence to the polymorphic payment contract |
| Polymorphism | payment_method.pay(total) |
Allows adding new gateways without modifying the checkout engine |
| Composition | Customer HAS-A Cart; Order HAS-A OrderItem[] | Avoids fragile inheritance trees by assembling modular components |
| Collaboration & DI | CheckoutService injecting NotificationService via constructor | Enables loose coupling and seamless mocking during unit tests |
05 Unified System Architecture Graph
A bird's-eye view of collaborating entities, component lifecycles, and message passing pathways:
Customer
│
▼ (has a)
Cart
│
▼ (contains)
CartItem[]
│
▼ (references)
Product
Customer (initiates)
│
▼
CheckoutService (Orchestrator)
│
├───────────► Order (State Machine)
│ │
│ ▼ (contains)
│ OrderItem[] (Price Snapshot)
│
├───────────► PaymentMethod <<interface>>
│ │
│ ┌─────┴─────┐
│ ▼ ▼
│ CardPayment MobilePayment
│
└───────────► NotificationService
06 The Grand Retrospective: Our Journey Across Course 04
From our very first question to the final capstone, trace your intellectual evolution:
1. In our checkout system, why does OrderItem store an explicit copy of `unit_price = product.price` instead of dynamically referencing `self.product.price`?
2. What architectural design pattern is demonstrated by passing `notification_service` into `CheckoutService.__init__()`?
Congratulations! Course 04 is Complete
You have successfully transitioned from basic language syntax to genuine Architectural Thinking. You now possess the insight to decompose messy real-world domains into elegant, maintainable object collaborations.
Course 05 — Data Structures (Visual)
Transition from domain modeling into algorithmic efficiency and memory optimization: Arrays, Linked Lists, Stacks, Queues, Hash Tables, Trees, Heaps, and Graphs—brought to life with interactive visual representations!