If you are new to Object-Oriented Design (OOD), looking at a blank screen and trying to figure out what "classes" and "objects" your software needs can feel overwhelming. How do you know what a class should do? How do you know which classes need to talk to each other?
Enter the Class-Responsibility-Collaboration (CRC) card technique. Invented by Kent Beck and Ward Cunningham, CRC is a simple, tactile, and highly visual way to design software. Instead of drawing complex diagrams right away, you use physical index cards (or digital equivalents) and act out a "play" where each person pretends to be a different object in your system.

This guide is written specifically for absolute beginners. We will walk through the exact process of using CRC cards, complete with visual examples of the cards themselves, to show you exactly how abstract ideas turn into a concrete software design.
Before we start filling out cards, let's understand the three golden rules of CRC.
A CRC card is just a small index card divided into three sections.
Top: The Class Name (The "Actor" in our play).
Left Side: Responsibilities (What this actor knows or does).
Right Side: Collaborations (Who this actor needs to talk to to get their job done).
Here is what a blank card looks like:

When you need to assign a task (a responsibility), ask yourself: "Which object naturally holds the data needed to do this?"
Beginner Example: If you need to calculate the area of a rectangle, the Rectangle object should do it, because it already knows its own width and height. Don't make a Calculator object do it, because the Calculator doesn't know the rectangle's dimensions.
CRC cards are small. You only have room for 3 or 4 responsibilities. This forces you to write what the object does, not how it does it.
Wrong (Too detailed): "Open database connection, query user table, parse JSON, return string."
Right (Perfect for CRC): "Retrieve user profile."
Let’s learn by doing. We are going to design a simple Pizza Ordering System.
The Scenario (Use Case): A customer walks into a pizza shop, orders a pepperoni pizza, and pays for it.
We have three developers in the room.
Dev 1 is holding the Customer card.
Dev 2 is holding the Order card.
Dev 3 is holding the Pizza card.
Let’s act out the scenario step-by-step and watch the cards get filled with actual data.
The Action: The customer looks at the menu and decides they want a pepperoni pizza.
The Role-Play:
Dev 1 (Customer): "I need to figure out what I want to eat. I'll write that down."
Dev 2 (Order): "I'm just listening right now. I don't need to do anything yet."
Dev 3 (Pizza): "I'm just sitting on the menu. I don't need to do anything yet."
The Card Update: Dev 1 writes on their card.

The Action: The customer tells the cashier (the system) they want a pepperoni pizza.
The Role-Play:
Dev 1 (Customer): "I need to give my order to the system. I will talk to the Order object." (Dev 1 writes Order on the right side of their card).
Dev 2 (Order): "The Customer just told me what they want. My job is to record this. I will write down 'Record customer choices'." (Dev 2 writes on their card).
The Card Update:


The Action: The system needs to tell the customer how much the pizza costs.
The Role-Play:
Dev 2 (Order): "I need to calculate the total cost. But wait... I don't know how much a pepperoni pizza costs! Who knows that?"
Dev 3 (Pizza): "I know my own base price! I'll tell the Order how much I cost."
Dev 2 (Order): "Great. I will add 'Calculate total cost' to my list, and I need to talk to Pizza to get the price." (Dev 2 updates their card).
Dev 3 (Pizza): "I need to add 'Provide base price' to my list." (Dev 3 updates their card).
The Card Update:


The Action: The customer pays for the pizza.
The Role-Play:
Dev 2 (Order): "Now I need to process the payment. I can handle the transaction." (Dev 2 adds 'Process payment' to their card).
Dev 1 (Customer): "I need to give my credit card info. I'll hand it to the Order." (Dev 1 adds Order to their collaborations, though it's already there).
Wait! A Problem Arises (Discovering New Classes):
Dev 2 (Order): "I'm supposed to process the payment, but I don't actually know how to talk to the bank's credit card API. I shouldn't be doing this! It's making my card too crowded."
The Team: "Let's create a new class! Let's grab a blank card and call it PaymentProcessor."
The Card Update: Dev 2 hands off the responsibility, and a new card is born.


After the role-play is finished, our physical cards look like this. Notice how clean and simple they are!




As you fill out your cards, follow these strict rules to ensure your design is good:
The Rule of 3 to 4: Never write more than 3 or 4 responsibilities on a single card. If you need more, your class is doing too much (like the Order class almost did with payment). Split it into two classes!
Respect the Physical Limits: If you are using real index cards and run out of physical space, stop. You are making the class too complex.
Use Verbs and Nouns: Responsibilities should be written as verb-noun pairs (e.g., "Calculate cost", "Record choice"). Collaborations should just be the name of the other class (e.g., "Pizza").
Embrace New Cards: If during the role-play you realize "nobody knows how to do this task," grab a blank card, name a new class, and assign the task to it. This is how you discover missing parts of your system!
Once your physical cards are full and the role-play is successful, you can translate them into formal UML diagrams using tools like PlantUML.
This diagram shows the final classes, their attributes (data they know), and their methods (what they do), based directly on our CRC cards.

@startuml
skinparam monochrome true
skinparam classFontSize 14
skinparam noteFontSize 12
class Customer {
- name: String
- creditCardNumber: String
+ chooseToppings(): String
+ providePaymentInfo(): String
}
class Order {
- totalCost: double
+ recordCustomerChoice(topping: String): void
+ calculateTotalCost(): double
+ processPayment(): boolean
}
class Pizza {
- basePrice: double
+ provideBasePrice(): double
}
class PaymentProcessor {
+ chargeCreditCard(amount: double, cardNum: String): boolean
}
Customer --> Order : places order
Order --> Pizza : asks for price
Order --> PaymentProcessor : processes payment
note right of Order
**Design Note:**
The Order class delegates the
actual bank communication to
PaymentProcessor, keeping
responsibilities focused.
end note
@enduml
This diagram shows the exact flow of messages during our pizza ordering scenario, proving that the objects collaborate correctly.

@startuml
skinparam monochrome true
skinparam sequenceMessageAlign center
actor User
participant "Customer" as C
participant "Order" as O
participant "Pizza" as P
participant "PaymentProcessor" as PP
User -> C: Decide on pepperoni
activate C
C -> C: chooseToppings()
C -> O: Place order for pepperoni
activate O
O -> O: recordCustomerChoice("Pepperoni")
O -> P: Provide price
activate P
P --> O: return $12.00
deactivate P
O -> O: calculateTotalCost()
O --> C: return Total: $12.00
deactivate O
C -> O: Provide credit card info
activate O
O -> PP: Charge $12.00
activate PP
PP --> O: return Success
deactivate PP
O --> User: Return Receipt
deactivate O
deactivate C
@enduml
The CRC session is just the design phase. The cards capture the intent. Once the design is finalized, you must translate the broad responsibilities on the cards into actual code (methods and attributes) in your programming language.
Here is how the text on our physical cards translates directly into code:
| CRC Card Text (Macro) | Translates to Code Attribute (State) | Translates to Code Method (Behavior) |
|---|---|---|
| Pizza: "Provide base price" | private double basePrice; |
public double provideBasePrice() |
| Order: "Record customer choice" | private List<String> toppings; |
public void recordCustomerChoice(String topping) |
| Order: "Calculate total cost" | (None needed) | public double calculateTotalCost() |
| PaymentProcessor: "Charge credit card" | (None needed) | public boolean chargeCreditCard(double amount) |
By mapping the cards directly to code, you ensure that every single method you write has a clear, justified purpose that was agreed upon by the team during the role-play.
For absolute beginners, Object-Oriented Design can feel like trying to solve a puzzle in the dark. The CRC card technique turns the lights on.
By physically acting out scenarios and writing on index cards, you stop worrying about syntax and code, and start focusing purely on how objects interact to solve a problem. You naturally discover which objects hold the data (Information Expert), you prevent your classes from becoming bloated "God objects" (Rule of 3-4), and you easily spot missing classes when a task has no logical home.
Next time you are tasked with designing a new feature or system, don't stare at a blank code editor. Grab a stack of index cards, assign roles to your team, and act out the scenario. You'll be amazed at how quickly a robust, elegant software design emerges from a simple role-play.