Hi devs :)
I’ve been diving into Object Calisthenics recently, and while it seems like a great practice, I know it’s not everyone’s cup of tea. It’s a set of 9 rules aimed at improving object-oriented design, but some developers are skeptical. Despite that, I’ve found these rules really helpful in making my C# code cleaner and more maintainable.
What Are These Rules?
Object Calisthenics encourages you to follow nine rules to enhance the modularity and readability of your code. Here’s a rundown with C# examples:
- One Level of Indentation Per Method Rule: Methods should have only one level of indentation. Example: Instead of this:
public void ProcessOrder(Order order)
{
if (order.IsValid())
{
if (order.IsPaid())
{
SendConfirmation(order);
}
else
{
HandleUnpaidOrder(order);
}
}
}
Refactor to:
public void ProcessOrder(Order order)
{
if (!order.IsValid())
{
HandleInvalidOrder(order);
return;
}
if (order.IsPaid())
{
SendConfirmation(order);
}
else
{
HandleUnpaidOrder(order);
}
}
2 . Don’t Use the else
Keyword
Rule: Avoid using else
by returning early.
Example: Instead of:
public decimal CalculateDiscount(Customer customer)
{
if (customer.IsVIP())
{
return 0.2m;
}
else
{
return 0.1m;
}
}
Refactor to:
public decimal CalculateDiscount(Customer customer)
{
if (customer.IsVIP())
{
return 0.2m;
}
return 0.1m;
}
3 . Wrap All Primitives and Strings
Rule: Encapsulate primitive data types in their own classes.
Example: Instead of using raw integers for age:
public void SetAge(int age)
{
this.age = age;
}
Wrap it:
public class Age
{
public int Value { get; private set; }
public Age(int value)
{
Value = value;
}
}
public void SetAge(Age age)
{
this.age = age.Value;
}
4 . First Class Collections
Rule: Collections should be managed by their own classes.
Example: Instead of handling a list of items directly:
public class Order
{
public List<Item> Items { get; private set; } = new List<Item>();
}
Refactor to:
public class OrderItems
{
private List<Item> items = new List<Item>();
public void AddItem(Item item)
{
items.Add(item);
}
public IReadOnlyList<Item> Items => items.AsReadOnly();
}
public class Order
{
public OrderItems Items { get; } = new OrderItems();
}
5 . One Dot Per Line
Rule: Limit method chaining to one per line.
Example: Instead of:
var zipcode = order.Customer.Address.ZipCode;
Refactor to:
var customer = order.Customer;
var address = customer.Address;
var zipcode = address.ZipCode;
6 . No Abbreviations
Rule: Use full, descriptive names.
Example: Instead of CalcDisc
, use:
public decimal CalculateDiscount()
{
// Implementation
}
7 . Keep Entities Small
Rule: Classes should be small and focused.
Example: Instead of a large class with multiple responsibilities:
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
public List<Order> Orders { get; set; }
public void PlaceOrder(Order order)
{
// Implementation
}
public void UpdateAddress(string newAddress)
{
// Implementation
}
}
Refactor into smaller classes:
public class Customer
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Value { get; set; }
public void UpdateAddress(string newAddress)
{
// Implementation
}
}
public class OrderManager
{
public void PlaceOrder(Customer customer, Order order)
{
// Implementation
}
}
8 . No More Than Two Instance Variables
Rule: Limit classes to two instance variables.
Example: Instead of:
public class Order
{
public List<Item> Items { get; set; }
public Customer Customer { get; set; }
public DateTime Date { get; set; }
public string Status { get; set; }
}
Refactor to:
public class Order
{
public List<Item> Items { get; set; }
public Customer Customer { get; set; }
}
public class OrderDetails
{
public Order Order { get; set; }
public DateTime Date { get; set; }
public string Status { get; set; }
}
9 . No Getters/Setters
Rule: Avoid exposing internal state through getters and setters.
Example: Instead of:
public class Customer
{
public string Name { get; set; }
}
Refactor to:
public class Customer
{
private string name;
public void ChangeName(string newName)
{
name = newName;
}
}
Why I Think It’s Worth Trying
I understand that Object Calisthenics might not be everyone's favorite approach. Some developers might find these rules a bit rigid or impractical. However, I’ve personally found that applying these practices has led to cleaner and more maintainable code. It’s like a workout for your coding habits — challenging but rewarding.
Even if you don’t follow all the rules strictly, experimenting with some of these principles can improve your coding practices. Have you tried Object Calisthenics or have any thoughts on improving object-oriented design? I’d love to hear your experiences!
Top comments (0)