Avoiding Overloaded or Misplaced Responsibilities
When teams start drawing CRC cards, they often rush to assign too many responsibilities to a single class—like making a single role handle everything from data storage to user notifications. That’s a classic sign of a misaligned design. You’ll spot it early: the card fills up with responsibilities that seem unrelated. The symptom isn’t complexity—it’s confusion. This is where most beginners stumble.
Over time, I’ve seen how this leads to maintenance nightmares. A class that handles both user authentication and invoice processing becomes brittle. Change one, and the other breaks. The root issue? A failure in responsibility assignment.
This chapter gives you a clear, step-by-step path to detect and correct overloaded or misplaced responsibilities. You’ll learn to spot CRC pitfalls early, apply RDD heuristics, and refactor designs with confidence. You’ll leave with practical tools to keep your models clean, cohesive, and easy to evolve.
Spotting the Symptoms: Signs of Overloaded Responsibilities
Not every class with many responsibilities is problematic. But certain patterns are red flags.
- One class manages both data input and output without clear separation.
- Responsibilities include tasks like “notify customer” and “calculate tax,” which belong to different domains.
- The class name sounds like a job title (e.g., “InvoiceProcessor”) rather than a role (e.g., “BillingService”).
- Team members argue about where a particular behavior “should” live.
These aren’t just bad habits. They’re symptoms of a design flaw rooted in poor responsibility assignment.
Ask yourself: Could this class reasonably perform all these tasks without feeling stretched? If not, it’s overloaded.
Real-World Example: The Overloaded Customer Class
Consider a Customer class that handles:
- Storing personal data
- Validating email
- Processing orders
- Sending confirmation emails
- Calculating loyalty points
It’s not wrong to have a Customer class. But assigning all these duties to one class means it’s doing too much. The responsibilities belong in different domains: data, validation, order processing, communication, and rewards.
Splitting these into separate roles—like CustomerDataRepository, OrderProcessor, EmailService, and LoyaltyCalculator—improves clarity and cohesion.
Common CRC Modeling Mistakes to Avoid
Overloaded responsibilities aren’t the only pitfall. Misplaced duties are just as dangerous.
Here are the most frequent CRC modeling mistakes I’ve seen in real projects:
- Assigning behavior to the wrong class — For example, placing the logic for calculating total cost into the Product class instead of the Order class.
- Using vague verbs — “Handle,” “Manage,” or “Do something” don’t define real responsibilities.
- Mixing data and behavior — Creating classes that store state but also run logic without clear boundaries.
- Ignoring collaboration patterns — Failing to model who calls whom or what data flows between roles.
Each of these undermines the goal of responsibility-driven design: to build systems where responsibilities are clearly assigned, cohesively grouped, and logically distributed.
Checklist: Is Your Class Overloaded?
Before finalizing a CRC card, run this quick check:
- Can another class handle one of these responsibilities better?
- Are there responsibilities from different domains (e.g., security, communication, business logic) on the same card?
- Would renaming the class help clarify its role? (e.g., “BillingService” vs. “Customer”)
- Do multiple responsibilities depend on the same data?
If two or more are yes, the class is likely overloaded.
Design Error Correction: A Step-by-Step Refactor
When you detect an overloaded class, don’t panic. Refactor with purpose.
Here’s my proven approach:
- Identify cohesion clusters — Group responsibilities by theme: data access, validation, communication, computation.
- Create new classes — For each cluster, define a new class with a clear name, like
EmailNotifierorPaymentValidator. - Move responsibilities — Transfer each responsibility to the most appropriate class.
- Re-evaluate collaborations — Update CRC cards to reflect new communication paths.
- Verify — Ask: Does each class now do one thing well? Is the system easier to extend?
This isn’t about rewriting code—it’s about realigning intent.
Before and After: The Customer Class
Before: The Customer class handles data, validation, order processing, email sending, and loyalty point tracking.
After: Split into:
CustomerDataRepository– Stores and retrieves customer data.OrderProcessor– Handles order creation, status updates.EmailService– Sends notifications.LoyaltyCalculator– Manages point accrual and redemption.
The result? Each class has one focus. The system is more modular and easier to test.
Applying RDD Heuristics for Better Responsibility Assignment
Responsibility-Driven Design (RDD) provides practical rules for assigning duties. Use these heuristics to avoid common CRC pitfalls.
1. “Tell, Don’t Ask” Rule
Instead of asking a class for data and then making decisions, tell it what to do.
Bad: Customer.getOrders().sumTotal() — the caller does the work.
Good: Customer.calculateTotalOrders() — the class owns the logic.
Shift responsibility to the class that has the data and context.
2. Single Responsibility Principle (SRP) in Practice
Each class should have one reason to change. If a class handles both security and reporting, it has two reasons to change.
Ask: What would cause this class to be modified? If more than one, it’s overburdened.
3. “Knows-Who” vs. “Knows-What”
Classes should know what data they need to function, not how to get it.
For example, Order knows it needs a Customer and a Product, but it shouldn’t know how to retrieve the customer from a database.
Delegate data access to a CustomerRepository.
Key Takeaways
Overloaded or misplaced responsibilities are among the most common CRC modeling mistakes. They lead to tangled designs, poor maintainability, and team friction.
But you don’t have to avoid them—they can be caught early and corrected with simple techniques.
Use the checklist and refactor steps above to detect and fix design flaws. Apply RDD heuristics to guide responsibility assignment. Keep classes focused on one domain, one task, one purpose.
The goal isn’t perfection. It’s clarity. And clarity comes from conscious, deliberate design.
Frequently Asked Questions
What’s the difference between an overloaded and misplaced responsibility?
An overloaded responsibility means one class holds too many duties, even if they’re legitimate. A misplaced responsibility assigns a task to the wrong class—e.g., having the Product class calculate its own total cost, when the Order should.
How do I decide which class should own a responsibility?
Ask: Which class has the data needed to fulfill this task? Also consider: Will this responsibility change for the same reason as the class? If yes, it likely belongs there.
Can a class have too few responsibilities?
Yes. While rare, underloaded classes—those with no meaningful duties—often indicate a missing role. For example, if a Payment class only stores data and has no actions, it may be a data holder. But the logic to process it should live elsewhere.
How often should I review CRC cards for design error correction?
Review after each major design change. Also revisit during team retrospectives or when bugs appear in areas with complex collaborations. Regular check-ins prevent small flaws from becoming systemic issues.
What if two classes seem equally responsible for a task?
Use the “Tell, Don’t Ask” rule. The class with the most context and data should own it. If both are equal, consider a third class to mediate the interaction—like a PaymentProcessor that coordinates between Customer and Bank.
Are design errors in CRC cards always bad?
No—early models are meant to evolve. A flawed assignment isn’t a failure. It’s feedback. The real risk is ignoring the feedback. CRC cards exist to surface these issues early, before they become code.