Software EngineeringUnit 519 min read

Architectural Design: Styles, Patterns, Trade-offs & Real Systems

Unit 5 of Software Engineering explores how to structure large software systems using architectural styles (layered, client-server, microservices), design patterns (MVC, Observer), and trade-offs (scalability vs. consistency). It covers key decisions like coupling, cohesion, and deployment models, with real-world examp

TAKEAWAYS:

  • Architectural styles (layered, client-server, microservices, event-driven) define how components interact and are deployed, each with distinct trade-offs.
  • Design patterns (MVC, Observer, Singleton) solve recurring architectural problems like separation of concerns or state management.
  • Quality attributes (scalability, availability, maintainability) drive architectural decisions—e.g., microservices prioritize scalability over tight coupling.
  • Deployment models (monolithic vs. distributed) impact performance, cost, and team organization (e.g., Daraz’s layered architecture vs. Pathao’s event-driven system).
  • Trade-offs (e.g., CAP theorem: consistency vs. availability vs. partition tolerance) must be explicitly justified in design.
  • Real-world mapping: Nepal’s eSewa uses layered architecture for security, while Khalti’s microservices enable independent scaling of payment modules.

Core Concepts: What is Architectural Design?

Architectural design is the high-level structure of a software system that defines:

  • Components: Major building blocks (e.g., modules, services).
  • Connectors: How components communicate (APIs, message queues, databases).
  • Configuration: Deployment topology (on-premise, cloud, hybrid).
  • Constraints: Non-functional requirements (NFRs) like latency, security, or cost.

Unlike detailed design (which focuses on algorithms or data structures), architectural design answers:

"How will this system be organized to meet its goals?"

Why It Matters

Poor architecture leads to:

  • Technical debt: Systems that are hard to extend (e.g., monolithic banks struggling to add new features).
  • Performance bottlenecks: Slow response times (e.g., NTC’s legacy systems during peak hours).
  • Security vulnerabilities: Centralized designs with single points of failure (e.g., Daraz’s early checkout system).

Architectural DesignComponents (Modules/Services)Connectors (APIs, DBs, Queues)Configuration (DeploymentTopology)Constraints (NFRs)
Core elements of architectural design (textbook-style layered diagram)

1. Architectural Styles: How Systems Are Structured

Architectural styles are proven templates for organizing systems. Each has strengths and weaknesses suited to specific contexts.

1.1 Layered (N-Tier) Architecture

Definition: Components are stacked in layers, where each layer has a single responsibility and communicates only with adjacent layers. Example Layers:

  1. Presentation Layer (UI): Handles user interaction (e.g., web/mobile apps).
  2. Application Layer (Business Logic): Processes requests (e.g., order validation).
  3. Data Access Layer (Persistence): Manages databases (e.g., SQL queries).
Presentation (UI)Application (Business Logic)Data Access (Database)
Standard 3-tier architecture diagram (textbook reference)

How It Works

User Request → Presentation → Application → Data Access → Database
               ← Data Access ← Application ← Presentation ← Response

Real-World Example: eSewa’s Payment System

  • Why layered?
    • Security: Sensitive payment data (e.g., card details) never touches the UI layer.
    • Maintainability: Changes to the UI (e.g., mobile app) don’t require rewriting business logic.
  • Trade-off: Adding a new feature (e.g., UPI integration) requires changes across all layers.

Worked Example: Nepal Rastra Bank’s Loan Processing

Assume a bank’s loan system has:

  • Presentation: Web portal for customers.
  • Application: Logic to calculate interest (e.g., ).
  • Data Access: SQL queries to fetch customer data.

Trace:

  1. User submits loan application via web portal (Presentation).
  2. Application layer validates inputs and calls calculateInterest().
  3. Data Access layer fetches P (principal), r (rate), and t (time) from the database.
  4. Result is returned to the user.

1.2 Client-Server Architecture

Definition: One central server provides services to multiple clients (e.g., web browsers, mobile apps). Clients request data; the server processes and returns it.

Key Components:

Component Role Example
Client Initiates requests (e.g., browser, mobile app). Daraz mobile app
Server Hosts resources (e.g., web server, API server). Daraz’s backend servers
Protocol Defines communication rules (e.g., HTTP, FTP). REST API for product catalog

Real-World Example: Daraz’s E-Commerce Platform

  • Clients: Websites, mobile apps, third-party sellers.
  • Servers:
    • Product Server: Handles catalog data.
    • Order Server: Manages transactions.
    • User Server: Authenticates logins.
  • Protocol: REST APIs for all client-server interactions.

Advantages:

  • Scalable: Add more servers to handle traffic (e.g., during sales like "Daraz Big Billion Days").
  • Centralized data management.

Disadvantages:

  • Single point of failure: If the server crashes, all clients are affected.
  • Latency: Clients depend on network speed (e.g., slow loading in Kathmandu’s unstable internet).

1.3 Microservices Architecture

Definition: A system is broken into small, independent services, each with its own database, deployed separately.

How It Differs from Layered/Client-Server:

Feature Layered/Client-Server Microservices
Deployment Monolithic (all-in-one) Independent services
Database Shared Service-specific (e.g., Orders DB, Users DB)
Scalability Scale the whole system Scale only what’s needed
Team Structure One team owns everything Cross-functional teams per service

Real-World Example: Khalti’s Payment Gateway

  • Services:
    • Auth Service: Handles user login (OAuth2).
    • Transaction Service: Processes payments (e.g., QR codes).
    • Notification Service: Sends SMS/email alerts.
  • Why microservices?
    • Independent scaling: During Diwali, only the Transaction Service needs more resources.
    • Fault isolation: A bug in notifications doesn’t crash payments.

Trade-offs:

  • Complexity: Requires service discovery (e.g., Kubernetes), load balancers, and event-driven communication (e.g., Kafka).
  • Data consistency: Services may have conflicting data (e.g., Orders DB vs. Inventory DB).

1.4 Event-Driven Architecture (EDA)

Definition: Components communicate via events (e.g., "OrderPlaced", "PaymentFailed") rather than direct calls.

Producer (User)Event BrokerConsumer 1 (Driver)Consumer 2 (Billing)
Pathao’s event-driven flow (simplified for clarity)

Key Concepts:

  • Event Producer: Triggers an event (e.g., Pathao driver accepts a ride).
  • Event Consumer: Reacts to the event (e.g., Pathao’s billing system charges the user).
  • Event Broker: Middleware that distributes events (e.g., RabbitMQ, AWS SNS).

Real-World Example: Pathao’s Ride-Hailing System

  1. Event: RideRequested (produced by the mobile app).
  2. Consumer: Nearby drivers receive the event via Pathao’s broker.
  3. Event: DriverAccepted → Consumer: Billing system starts timer.
  4. Event: RideCompleted → Consumer: Send receipt to user.

Advantages:

  • Loose coupling: Services don’t need to know about each other.
  • Real-time processing: Ideal for time-sensitive apps (e.g., stock trading).

Disadvantages:

  • Complex debugging: Events can get lost or duplicated.
  • Ordering issues: Events may arrive out of sequence.

1.5 Comparison Table: Architectural Styles

Style Best For Scalability Fault Tolerance Complexity Example (Nepal)
Layered Small-to-medium systems Medium Low Low eSewa, bank ATMs
Client-Server Web/mobile apps with central data High Medium Medium Daraz, NTC website
Microservices Large, rapidly evolving systems Very High High Very High Khalti, F1Soft
Event-Driven Real-time systems High High High Pathao, NEPSE trading

2. Design Patterns for Architecture

Design patterns are reusable solutions to common architectural problems. Here are three critical for software engineering exams:

2.1 Model-View-Controller (MVC)

Problem: Separate user interface (UI) logic from business logic to improve maintainability. Structure:

User → View → Controller → Model → Database
       ← Model ← Controller ← View ← User

Real-World Example: Nepal Stock Exchange (NEPSE) Trading Platform

  • Model: Holds stock prices, user portfolios.
  • View: Displays charts, order books (e.g., nepse.com.np).
  • Controller: Handles buy/sell orders (e.g., validates user permissions).

Why MVC?

  • Separation of concerns: UI changes (e.g., mobile app) don’t affect trading logic.
  • Reusability: Same model can be used for web and API clients.

2.2 Observer Pattern

Problem: Notify multiple components when a state changes (e.g., stock price updates). Structure:

  • Subject (Observable): Maintains state (e.g., StockPrice).
  • Observers: React to state changes (e.g., mobile app, dashboard).

Real-World Example: Live Stock Price Updates on Your Phone

  1. Subject: NEPSE’s central server updates StockPrice for "Nabil Bank".
  2. Observers:
    • Your trading app (pushes notification).
    • A news website (updates its ticker).
    • An algorithmic trader (executes a buy/sell).

Code Snippet (Pseudocode):

class StockPrice {
    private List<Observer> observers = new ArrayList<>();
    private double price;

    public void addObserver(Observer o) { observers.add(o); }
    public void setPrice(double newPrice) {
        price = newPrice;
        notifyObservers();
    }
    private void notifyObservers() {
        for (Observer o : observers) o.update(price);
    }
}

interface Observer {
    void update(double price);
}

2.3 Singleton Pattern

Problem: Ensure only one instance of a critical component exists (e.g., configuration manager). Use Cases:

  • Database connection pool.
  • Logging service.
  • Caching layer.

Real-World Example: NTC’s Network Configuration Manager

  • Why Singleton?
    • Only one instance manages all network settings to avoid conflicts.
  • Implementation Risk:
    • Thread safety: In multi-threaded systems (e.g., NTC’s load balancers), lazy initialization must be synchronized.

Exam Pitfall: Overusing Singleton can lead to global state, making testing harder.


3. Quality Attributes and Trade-offs

Architectural decisions are driven by non-functional requirements (NFRs). The most critical are:

3.1 The CAP Theorem: Consistency, Availability, Partition Tolerance

Statement: In a distributed system, you can only guarantee two of the three:

  1. Consistency: All nodes see the same data (e.g., bank balance).
  2. Availability: System remains operational (e.g., Daraz during sales).
  3. Partition Tolerance: System works despite network failures (e.g., Kathmandu traffic jams).

Real-World Example: Ncell’s Charging System

  • Requirement: High availability (users must recharge anytime).
  • Trade-off: AP (Available + Partition Tolerant):
    • If a server fails, users can still recharge via another node.
    • Inconsistency risk: Your balance might briefly show incorrect data during a partition.

Comparison:

System CAP Choice Example
eSewa CP Strong consistency for payments.
Pathao AP Available during peak hours.
NEPSE Trading CA Consistency critical for orders.

3.2 Scalability vs. Maintainability

Attribute Microservices Monolithic
Scalability High (scale per service) Low (scale entire system)
Maintainability Low (many services to manage) High (single codebase)
Team Size Large (cross-functional teams) Small (one team)

Example: F1Soft’s Transition

  • Started with monolithic design → struggled to add new features.
  • Migrated to microservices → now supports multiple fintech products (e.g., eSewa, Khalti).

4. Deployment Models: Monolithic vs. Distributed

4.1 Monolithic Architecture

Definition: All components are deployed as a single unit (e.g., one JAR/WAR file). Example: Early versions of NTC’s billing system.

Pros:

  • Simple to deploy and debug.
  • Low network overhead (no inter-service calls).

Cons:

  • Scalability: Must scale the entire system (e.g., NTC’s website slows down during peak hours).
  • Risk: A bug in one module crashes the whole system.

4.2 Distributed Architecture (Microservices/Cloud-Native)

Definition: Components are deployed across multiple machines (e.g., Kubernetes pods). Example: Google’s global infrastructure (used by YouTube, Gmail).

Pros:

  • Scalability: Scale only what’s needed (e.g., YouTube’s video transcoding).
  • Fault isolation: One service failure doesn’t take down the system.

Cons:

  • Complexity: Requires orchestration (e.g., Docker, Kubernetes).
  • Latency: Network calls between services add overhead.

5. Architectural Decision Records (ADRs)

Definition: Documents why a specific architectural choice was made (e.g., "Why we chose microservices over monolithic"). Why It Matters:

  • Auditable: Future teams understand past decisions.
  • Justifiable: Explains trade-offs (e.g., "We sacrificed some consistency for availability").

Example ADR for Khalti:

Title: Adopt Microservices for Payment Gateway
Status: Accepted
Date: 2020-05-15
Context: Monolithic system struggled to scale during Diwali.
Decision: Split into Auth, Transaction, and Notification services.
Consequences:
- + Independent scaling during peak loads.
- - Increased complexity in data consistency.

In the Real World

  1. eSewa’s Layered Security

    • Idea: Layered architecture separates user authentication (Presentation) from payment processing (Application/Data Access).
    • How: When you pay a bill, your phone (client) sends data to eSewa’s server, which validates your credentials (Application layer) before processing the transaction (Data Access layer). This isolation prevents security breaches in one layer from affecting others.
  2. Pathao’s Event-Driven Ride Matching

    • Idea: Event-Driven Architecture (EDA) uses events like RideRequested and DriverAccepted to dynamically match riders and drivers.
    • How: When you request a ride, Pathao’s event broker publishes RideRequested to all nearby drivers. The first to accept triggers DriverAccepted, which updates your app and starts the billing timer. This avoids direct client-server calls, reducing latency.
  3. NEPSE’s CAP Trade-off

    • Idea: CAP Theorem forces NEPSE to choose between consistency and availability during trading.
    • How: During high volatility (e.g., stock splits), NEPSE prioritizes consistency (CP) to ensure all traders see the same price. This means the system might briefly become unavailable (e.g., "Server busy" errors) but avoids incorrect trades.
  4. Daraz’s Monolithic-to-Microservices Migration

    • Idea: Microservices enabled Daraz to scale independently for different features.
    • How: Initially, Daraz used a monolithic design, which slowed down during sales. By splitting into services like ProductCatalog, OrderProcessing, and UserManagement, Daraz could scale OrderProcessing during Black Friday without overloading other services.

Exam Tip

What Examiners Look For

  1. Definitions with Examples:

    • Don’t just say "layered architecture." Explain it with a real Nepalese example (e.g., eSewa) and draw a layered diagram.
    • For CAP theorem, always pick a local example (e.g., Ncell’s AP choice) and justify it.
  2. Trade-off Analysis:

    • Questions often ask: "Why would a company choose microservices over monolithic?"
    • Structure your answer:
      • Context: "For a high-traffic system like Khalti..."
      • Pros: "Independent scaling during Diwali..."
      • Cons: "But adds complexity in data consistency..."
      • Conclusion: "Thus, Khalti chose microservices for [reason]."
  3. Diagrams Are Mandatory:

    • Layered/Client-Server: Draw the stack with arrows for data flow.
    • Microservices: Show independent services with databases.
    • Event-Driven: Use a sequence diagram (see below) to show event flow.
  4. Common Pitfalls:

    • Overgeneralizing: Not all systems need microservices (e.g., a small bank’s ATM system can use layered).
    • Ignoring NFRs: Always tie architecture to quality attributes (e.g., "This design prioritizes availability for Pathao’s riders").

sequenceDiagram
    participant User as Rider (Mobile App)
    participant Broker as Pathao Event Broker
    participant Driver1 as Driver 1
    participant Driver2 as Driver 2
    participant Billing as Billing System

    User->>Broker: RideRequested (Location: Kathmandu, Thapathali)
    Broker->>Driver1: Event: RideRequested
    Broker->>Driver2: Event: RideRequested
    Driver1->>Broker: DriverAccepted
    Broker->>User: RideAssigned (Driver: Ram)
    Broker->>Billing: Event: RideStarted
    User->>Broker: RideCompleted
    Broker->>Billing: Event: RideCompleted
    Billing->>User: Send Receipt

Sample Exam Question and Answer

Question: "Explain the architectural style used by Khalti’s payment gateway. Discuss two trade-offs of this style and justify why Khalti might still prefer it over a monolithic design."

Model Answer: Khalti uses a microservices architecture, where the system is divided into independent services such as:

  1. Authentication Service: Handles user login via OAuth2.
  2. Transaction Service: Processes payments (e.g., QR codes, bank transfers).
  3. Notification Service: Sends SMS/email alerts.

Trade-offs:

  1. Complexity vs. Scalability:

    • Trade-off: Microservices introduce complexity in service discovery, load balancing, and event-driven communication (e.g., using Kafka).
    • Justification: Khalti prioritizes scalability during peak times (e.g., Diwali). Independent scaling of the Transaction Service ensures smooth operations without overloading other services.
  2. Data Consistency vs. Independence:

    • Trade-off: Services have their own databases, risking inconsistent data (e.g., Orders DB vs. Inventory DB).
    • Justification: Khalti uses eventual consistency (via event sourcing) to reconcile data asynchronously. The trade-off is acceptable because availability and partition tolerance (AP) are critical for real-time payments.

Why Microservices?

  • Business Agility: Khalti can deploy new features (e.g., UPI integration) without redeploying the entire system.
  • Fault Isolation: A bug in the Notification Service won’t crash payments, unlike a monolithic design where one failure affects everything.

Diagram:

OAuth2 TokenPaymentSuccess EventDataDataAuthServiceTransactionServiceNotificationServiceUsers DBTransactions DB
Khalti’s microservices architecture with data flows (real system example)

Based on the PU BE Computer (PU) syllabus for Software Engineering (CMP348), unit 5.

Discussion

Loading…