0
0
LLDsystem_design~7 mins

Class responsibilities and behavior in LLD - System Design Guide

Choose your learning style9 modes available
Problem Statement
When classes have unclear or mixed responsibilities, the code becomes hard to understand, maintain, and extend. This often leads to bugs and duplicated logic because behaviors are scattered or overloaded in the wrong places.
Solution
Assign each class a clear responsibility focused on a single purpose. Define behaviors (methods) that belong naturally to that responsibility. This keeps classes simple, cohesive, and easier to manage, making the system more robust and adaptable.
Architecture
User Class
───────────────
Payment Class
Payment Class

This diagram shows three classes each with focused responsibilities and behaviors: User handles login/logout, Order manages items and totals, Payment processes payments.

Trade-offs
✓ Pros
Improves code readability by grouping related data and behavior.
Makes testing easier by isolating functionality.
Facilitates future changes by limiting impact to specific classes.
Encourages reuse of well-defined behaviors.
✗ Cons
Requires upfront design effort to define clear responsibilities.
May lead to more classes, increasing the number of components to manage.
Improper responsibility assignment can still cause tight coupling.
Always use when designing object-oriented systems, especially when classes grow beyond a few methods or when multiple developers work on the codebase.
Not applicable for very small scripts or procedural code where classes are unnecessary overhead.
Real World Examples
Amazon
Separates order processing, user management, and payment handling into distinct classes to keep the system modular and maintainable.
Uber
Uses clear class responsibilities to manage drivers, riders, and trip behaviors separately, enabling rapid feature development.
Shopify
Defines classes with focused responsibilities for products, carts, and checkout to simplify complex e-commerce workflows.
Code Example
The before code mixes user data, login behavior, and order total calculation in one class, making it hard to maintain. The after code splits responsibilities: User handles login, Order manages items and totals, and UserOrders manages multiple orders. This separation improves clarity and maintainability.
LLD
### Before: Mixed responsibilities in one class
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email
        self.orders = []

    def login(self):
        print(f"{self.name} logged in")

    def add_order(self, order):
        self.orders.append(order)

    def calculate_total_spent(self):
        total = 0
        for order in self.orders:
            total += sum(item['price'] for item in order['items'])
        return total


### After: Clear responsibilities split into classes
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

    def login(self):
        print(f"{self.name} logged in")

class Order:
    def __init__(self, order_id):
        self.order_id = order_id
        self.items = []

    def add_item(self, item):
        self.items.append(item)

    def calculate_total(self):
        return sum(item['price'] for item in self.items)

class UserOrders:
    def __init__(self):
        self.orders = []

    def add_order(self, order):
        self.orders.append(order)

    def calculate_total_spent(self):
        return sum(order.calculate_total() for order in self.orders)
OutputSuccess
Alternatives
Procedural Programming
Focuses on functions and data separately without bundling behavior with data in classes.
Use when: Use when the problem is simple or performance-critical and object-oriented overhead is unnecessary.
Anemic Domain Model
Separates data and behavior, placing logic outside classes, often leading to less cohesive design.
Use when: Sometimes chosen for simple CRUD applications but generally discouraged for complex domains.
Summary
Assign each class a clear, focused responsibility to keep code simple and maintainable.
Define behaviors that naturally belong to the class’s responsibility to encapsulate logic.
Clear class responsibilities improve readability, testing, and future changes.