Visual Paradigm Desktop VP Online

Mastering CRC Cards: A Comprehensive Guide to Defining Class Responsibilities Through Role-Play

Introduction

In Object-Oriented Design (OOD), one of the most challenging tasks is determining how to divide system functionality among various classes. The Class-Responsibility-Collaboration (CRC) card technique, originally developed by Kent Beck and Ward Cunningham, offers an elegant, highly interactive solution to this problem.

Rather than staring at a blank whiteboard, developers use physical index cards to simulate system behavior through role-play. This guide explores the comprehensive process of defining class responsibilities during a CRC session, outlining the rules, key concepts, and the eventual transition from high-level design to concrete code operations.

CRC Card Session for OOA and OOD


Key Concepts with Examples

Before diving into the process, it is essential to understand the core concepts that drive a CRC session.

1. The Anatomy of a CRC Card

A standard CRC card is divided into three sections:

  • Class Name: The name of the object (top).

  • Responsibilities: What the object knows or does (left side).

  • Collaborations: Other classes it interacts with to fulfill its responsibilities (right side).

Example: For a Bike class, a responsibility might be "Track current rental status," and its collaboration would be RentalSystem.

2. The "Information Expert" Principle

When deciding which class gets a responsibility, the group follows the Information Expert principle: assign the responsibility to the class that has the information necessary to fulfill it.

Example: If the system needs to "Calculate the late fee for a bike," the Bike class should hold this responsibility, not the Customer class, because the Bike knows its own rental rate and due date.

3. Macro vs. Micro Thinking

CRC cards force developers to think at a "macro" level. Responsibilities are broad obligations, not specific lines of code.

Example: Instead of writing "Get the string value of the tire pressure," a responsibility is written as "Monitor physical condition."


The Definition and Identification Process

Defining responsibilities during a role-play session is a dynamic, step-by-step process.

Step 1: Defining a Responsibility

A responsibility is formally defined as an obligation for a class to provide a specific service. This could be maintaining a record, performing a calculation, or supplying data. It is an action or a piece of knowledge the object owns.

Step 2: Enacting Scenarios (The Role-Play)

The team selects a specific use case (e.g., "A customer rents a mountain bike"). Each team member adopts the identity of a specific object (e.g., one person is the Customer, another is the Bike, another is the RentalSystem). The group "walks through" the events step-by-step, speaking in the first person ("I need to ask the Bike for its availability...").

Step 3: Identifying Tasks

As the group progresses through the scenario, they identify every individual task the system must perform to reach the goal.

  • Task: Verify the customer has a valid license.

  • Task: Check if the bike is available.

  • Task: Generate a rental receipt.

Step 4: Allocating the Responsibility

For every identified task, the group discusses and decides which object is the most suitable to handle it. Once a consensus is reached, that task is written as a responsibility on the back of that specific class's physical CRC card.


Rules and Guidelines for Responsibilities

To ensure the design remains robust, cohesive, and maintainable, strict guidelines are followed during the session.

  • Limited Capacity (The Rule of 3-4): To ensure classes remain small and have a clearly defined purpose, no class should have more than three or four responsibilities. If a class needs more, it is likely doing too much and should be split.

  • Physical Constraints: The use of small index cards (typically 10 cm x 15 cm) is highly intentional. The limited physical space forces developers to specify responsibilities at a high, macro level rather than listing numerous low-level operations. If you run out of space, your class is too complex.

  • Discovering New Classes: If a task is identified during the role-play that cannot be logically assigned to any existing objects (e.g., "Who calculates the tax?"), the group uses this as a prompt to identify and create a new class (e.g., TaxCalculator) to fill the gap.

  • Refining Interactions: The ultimate goal of defining these responsibilities is to minimize the number and complexity of messages passed between objects. A good design features high cohesion within a class and low coupling between classes.


Visualizing the Process: PlantUML Examples

To illustrate how a CRC role-play translates into structural models, below are two PlantUML diagrams based on our Bike Rental scenario.

1. Class Diagram: Transitioning Responsibilities to Operations

This diagram shows how the high-level responsibilities defined on the physical CRC cards are translated into concrete operations and attributes in the structural model.

@startuml
skinparam classAttributeIconSize 0
skinparam monochrome true

class RentalSystem {
  + findBike(type: String): Bike
  + processRental(customer: Customer, bike: Bike): Receipt
  + {responsibility} "Provide bike inventory"
  + {responsibility} "Process rental transactions"
}

class Customer {
  - licenseNumber: String
  - name: String
  + verifyLicense(): boolean
  + {responsibility} "Maintain personal record"
  + {responsibility} "Supply data for payment"
}

class Bike {
  - isAvailable: boolean
  - dailyRate: double
  + checkAvailability(): boolean
  + calculateLateFee(days: int): double
  + {responsibility} "Track rental status"
  + {responsibility} "Provide information about bikes"
}

RentalSystem --> Customer : collaborates
RentalSystem --> Bike : collaborates
Customer --> Bike : collaborates

note right of RentalSystem
  **CRC to Code Transition:**
  The responsibility "Provide bike inventory" 
  becomes the operation findBike().
end note

@enduml

2. Sequence Diagram: The Role-Play Enactment

This diagram represents the "walk-through" phase of the CRC session, showing how objects collaborate by passing messages to fulfill the responsibilities defined on their cards.

@startuml
skinparam monochrome true

actor User
participant "RentalSystem\n(Actor: Dev 1)" as RS
participant "Customer\n(Actor: Dev 2)" as C
participant "Bike\n(Actor: Dev 3)" as B

User -> RS: Request to rent a Mountain Bike
activate RS

RS -> RS: **Responsibility:** Find available bike
RS -> B: checkAvailability("Mountain")
activate B
B --> RS: return Bike_101
deactivate B

RS -> C: **Responsibility:** Verify customer eligibility
activate C
C --> RS: return isValid = true
deactivate C

RS -> B: **Responsibility:** Calculate rental cost
activate B
B --> RS: return cost = $25.00
deactivate B

RS -> RS: **Responsibility:** Process transaction
RS --> User: Return Receipt and Bike_101
deactivate RS

note over RS, B
  **Role-Play Outcome:**
  Notice how messages are minimized. 
  The RentalSystem delegates specific 
  tasks to the Information Experts (Customer, Bike).
end note

@enduml

Transition to Operations

The CRC role-play session is a design phase, not a coding phase. The physical cards capture the intent of the system. Once the high-level responsibilities are stabilized through role-play and the team is satisfied with the object interactions, the design must be formalized.

During the transition to the structural model (like UML Class Diagrams), the broad text on the CRC cards is specified in more detail as individual operations and attributes.

Examples of Transition:

  • CRC Responsibility: "Providing information about bikes"

    • Translates to Operation: findBike(String type) or getBikeDetails()

  • CRC Responsibility: "Keeping track of rental history"

    • Translates to Attribute & Operation: List<Rental> history and addRental(Rental r)

  • CRC Responsibility: "Calculating the total cost"

    • Translates to Operation: calculateTotalCost(int days, double rate)

This transition ensures that the intuitive, collaborative insights gained during the card session are accurately captured in the formal documentation and eventual codebase.


Conclusion

Defining class responsibilities through a CRC card role-play session is much more than a simple brainstorming exercise; it is a rigorous, interactive method for achieving high-quality Object-Oriented Design. By physically enacting scenarios, teams can intuitively discover the natural boundaries of objects, identify missing classes, and ensure that responsibilities are allocated to the true "information experts."

By adhering to strict guidelines—such as limiting responsibilities to 3 or 4 per card and utilizing the physical constraints of index cards—developers prevent over-engineering and maintain high cohesion. Ultimately, the CRC technique bridges the gap between abstract system requirements and concrete code operations, resulting in a robust, maintainable, and elegantly structured software architecture.

Turn every software project into a successful one.

We use cookies to offer you a better experience. By visiting our website, you agree to the use of cookies as described in our Cookie Policy.

OK