Skip to content

Commit 28f264a

Browse files
SebastienDegodezcodemillmattCopilot
authored
Add Object Calisthenics instruction file (#118)
* add Object Calisthenics instruction file This instruction enforces the 9 original Object Calisthenics rules for business domain code (C#, TypeScript, Java). It provides clear guidelines and examples for maintainable, robust, and clean backend code. DTOs and infrastructure code are exempted. References to original sources included. Signed-off-by: SebastienDegodez <[email protected]> * Update instructions/object-calisthenics.instructions.md Co-authored-by: Copilot <[email protected]> * Update instructions/object-calisthenics.instructions.md Co-authored-by: Copilot <[email protected]> --------- Signed-off-by: SebastienDegodez <[email protected]> Co-authored-by: Matt Soucoup <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent bb64aa6 commit 28f264a

File tree

2 files changed

+303
-0
lines changed

2 files changed

+303
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for
5353
| [Next.js + Tailwind Development Instructions](instructions/nextjs-tailwind.instructions.md) | Next.js + Tailwind development standards and instructions | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnextjs-tailwind.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnextjs-tailwind.instructions.md) |
5454
| [Next.js Best Practices for LLMs (2025)](instructions/nextjs.instructions.md) | (2025) specific coding standards and best practices | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnextjs.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnextjs.instructions.md) |
5555
| [Code Generation Guidelines](instructions/nodejs-javascript-vitest.instructions.md) | Guidelines for writing Node.js and JavaScript code with Vitest testing | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnodejs-javascript-vitest.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fnodejs-javascript-vitest.instructions.md) |
56+
| [Object Calisthenics Rules](instructions/object-calisthenics.instructions.md) | Enforces Object Calisthenics principles for business domain code to ensure clean, maintainable, and robust code | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md) |
5657
| [Performance Optimization Best Practices](instructions/performance-optimization.instructions.md) | The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks. Covers frontend, backend, and database best practices with actionable guidance, scenario-based checklists, troubleshooting, and pro tips. | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md) |
5758
| [Playwright Typescript](instructions/playwright-typescript.instructions.md) | Playwright test generation instructions | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fplaywright-typescript.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fplaywright-typescript.instructions.md) |
5859
| [Power Platform Connectors Schema Development Instructions](instructions/power-platform-connector.instructions.md) | Comprehensive development guidelines for Power Platform Custom Connectors using JSON Schema definitions. Covers API definitions (Swagger 2.0), API properties, and settings configuration with Microsoft extensions. | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpower-platform-connector.instructions.md) [![Install in VS Code](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpower-platform-connector.instructions.md) |
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
---
2+
applyTo: '**/*.{cs,ts,java}'
3+
description: Enforces Object Calisthenics principles for business domain code to ensure clean, maintainable, and robust code
4+
---
5+
# Object Calisthenics Rules
6+
7+
> ⚠️ **Warning:** This file contains the 9 original Object Calisthenics rules. No additional rules must be added, and none of these rules should be replaced or removed.
8+
> Examples may be added later if needed.
9+
10+
## Objective
11+
This rule enforces the principles of Object Calisthenics to ensure clean, maintainable, and robust code in the backend, **primarily for business domain code**.
12+
13+
## Scope and Application
14+
- **Primary focus**: Business domain classes (aggregates, entities, value objects, domain services)
15+
- **Secondary focus**: Application layer services and use case handlers
16+
- **Exemptions**:
17+
- DTOs (Data Transfer Objects)
18+
- API models/contracts
19+
- Configuration classes
20+
- Simple data containers without business logic
21+
- Infrastructure code where flexibility is needed
22+
23+
## Key Principles
24+
25+
26+
1. **One Level of Indentation per Method**:
27+
- Ensure methods are simple and do not exceed one level of indentation.
28+
29+
```csharp
30+
// Bad Example - this method has multiple levels of indentation
31+
public void SendNewsletter() {
32+
foreach (var user in users) {
33+
if (user.IsActive) {
34+
// Do something
35+
mailer.Send(user.Email);
36+
}
37+
}
38+
}
39+
// Good Example - Extracted method to reduce indentation
40+
public void SendNewsletter() {
41+
foreach (var user in users) {
42+
SendEmail(user);
43+
}
44+
}
45+
private void SendEmail(User user) {
46+
if (user.IsActive) {
47+
mailer.Send(user.Email);
48+
}
49+
}
50+
51+
// Good Example - Filtering users before sending emails
52+
public void SendNewsletter() {
53+
var activeUsers = users.Where(user => user.IsActive);
54+
55+
foreach (var user in activeUsers) {
56+
mailer.Send(user.Email);
57+
}
58+
}
59+
```
60+
2. **Don't Use the ELSE Keyword**:
61+
62+
- Avoid using the `else` keyword to reduce complexity and improve readability.
63+
- Use early returns to handle conditions instead.
64+
- Use Fail Fast principle
65+
- Use Guard Clauses to validate inputs and conditions at the beginning of methods.
66+
67+
```csharp
68+
// Bad Example - Using else
69+
public void ProcessOrder(Order order) {
70+
if (order.IsValid) {
71+
// Process order
72+
} else {
73+
// Handle invalid order
74+
}
75+
}
76+
// Good Example - Avoiding else
77+
public void ProcessOrder(Order order) {
78+
if (!order.IsValid) return;
79+
// Process order
80+
}
81+
```
82+
83+
Sample Fail fast principle:
84+
```csharp
85+
public void ProcessOrder(Order order) {
86+
if (order == null) throw new ArgumentNullException(nameof(order));
87+
if (!order.IsValid) throw new InvalidOperationException("Invalid order");
88+
// Process order
89+
}
90+
```
91+
92+
3. **Wrapping All Primitives and Strings**:
93+
- Avoid using primitive types directly in your code.
94+
- Wrap them in classes to provide meaningful context and behavior.
95+
96+
```csharp
97+
// Bad Example - Using primitive types directly
98+
public class User {
99+
public string Name { get; set; }
100+
public int Age { get; set; }
101+
}
102+
// Good Example - Wrapping primitives
103+
public class User {
104+
private string name;
105+
private Age age;
106+
public User(string name, Age age) {
107+
this.name = name;
108+
this.age = age;
109+
}
110+
}
111+
public class Age {
112+
private int value;
113+
public Age(int value) {
114+
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Age cannot be negative");
115+
this.value = value;
116+
}
117+
}
118+
```
119+
120+
4. **First Class Collections**:
121+
- Use collections to encapsulate data and behavior, rather than exposing raw data structures.
122+
First Class Collections: a class that contains an array as an attribute should not contain any other attributes
123+
124+
```csharp
125+
// Bad Example - Exposing raw collection
126+
public class Group {
127+
public int Id { get; private set; }
128+
public string Name { get; private set; }
129+
public List<User> Users { get; private set; }
130+
131+
public int GetNumberOfUsersIsActive() {
132+
return Users
133+
.Where(user => user.IsActive)
134+
.Count();
135+
}
136+
}
137+
138+
// Good Example - Encapsulating collection behavior
139+
public class Group {
140+
public int Id { get; private set; }
141+
public string Name { get; private set; }
142+
143+
public GroupUserCollection userCollection { get; private set; } // The list of users is encapsulated in a class
144+
145+
public int GetNumberOfUsersIsActive() {
146+
return userCollection
147+
.GetActiveUsers()
148+
.Count();
149+
}
150+
}
151+
```
152+
153+
5. **One Dot per Line**:
154+
- Limit the number of method calls in a single line to improve readability and maintainability.
155+
156+
```csharp
157+
// Bad Example - Multiple dots in a single line
158+
public void ProcessOrder(Order order) {
159+
var userEmail = order.User.GetEmail().ToUpper().Trim();
160+
// Do something with userEmail
161+
}
162+
// Good Example - One dot per line
163+
public void ProcessOrder(Order order) {
164+
var user = order.User;
165+
var email = user.GetEmail();
166+
var userEmail = email.ToUpper().Trim();
167+
// Do something with userEmail
168+
}
169+
```
170+
171+
6. **Don't abbreviate**:
172+
- Use meaningful names for classes, methods, and variables.
173+
- Avoid abbreviations that can lead to confusion.
174+
175+
```csharp
176+
// Bad Example - Abbreviated names
177+
public class U {
178+
public string N { get; set; }
179+
}
180+
// Good Example - Meaningful names
181+
public class User {
182+
public string Name { get; set; }
183+
}
184+
```
185+
186+
7. **Keep entities small (Class, method, namespace or package)**:
187+
- Limit the size of classes and methods to improve code readability and maintainability.
188+
- Each class should have a single responsibility and be as small as possible.
189+
190+
Constraints:
191+
- Maximum 10 methods per class
192+
- Maximum 50 lines per class
193+
- Maximum 10 classes per package or namespace
194+
195+
```csharp
196+
// Bad Example - Large class with multiple responsibilities
197+
public class UserManager {
198+
public void CreateUser(string name) { /*...*/ }
199+
public void DeleteUser(int id) { /*...*/ }
200+
public void SendEmail(string email) { /*...*/ }
201+
}
202+
203+
// Good Example - Small classes with single responsibility
204+
public class UserCreator {
205+
public void CreateUser(string name) { /*...*/ }
206+
}
207+
public class UserDeleter {
208+
public void DeleteUser(int id) { /*...*/ }
209+
}
210+
211+
public class UserUpdater {
212+
public void UpdateUser(int id, string name) { /*...*/ }
213+
}
214+
```
215+
216+
217+
8. **No Classes with More Than Two Instance Variables**:
218+
- Encourage classes to have a single responsibility by limiting the number of instance variables.
219+
- Limit the number of instance variables to two to maintain simplicity.
220+
- Do not count ILogger or any other logger as instance variable.
221+
222+
```csharp
223+
// Bad Example - Class with multiple instance variables
224+
public class UserCreateCommandHandler {
225+
// Bad: Too many instance variables
226+
private readonly IUserRepository userRepository;
227+
private readonly IEmailService emailService;
228+
private readonly ILogger logger;
229+
private readonly ISmsService smsService;
230+
231+
public UserCreateCommandHandler(IUserRepository userRepository, IEmailService emailService, ILogger logger, ISmsService smsService) {
232+
this.userRepository = userRepository;
233+
this.emailService = emailService;
234+
this.logger = logger;
235+
this.smsService = smsService;
236+
}
237+
}
238+
239+
// Good: Class with two instance variables
240+
public class UserCreateCommandHandler {
241+
private readonly IUserRepository userRepository;
242+
private readonly INotificationService notificationService;
243+
private readonly ILogger logger; // This is not counted as instance variable
244+
245+
public UserCreateCommandHandler(IUserRepository userRepository, INotificationService notificationService, ILogger logger) {
246+
this.userRepository = userRepository;
247+
this.notificationService = notificationService;
248+
this.logger = logger;
249+
}
250+
}
251+
```
252+
253+
9. **No Getters/Setters in Domain Classes**:
254+
- Avoid exposing setters for properties in domain classes.
255+
- Use private constructors and static factory methods for object creation.
256+
- **Note**: This rule applies primarily to domain classes, not DTOs or data transfer objects.
257+
258+
```csharp
259+
// Bad Example - Domain class with public setters
260+
public class User { // Domain class
261+
public string Name { get; set; } // Avoid this in domain classes
262+
}
263+
264+
// Good Example - Domain class with encapsulation
265+
public class User { // Domain class
266+
private string name;
267+
private User(string name) { this.name = name; }
268+
public static User Create(string name) => new User(name);
269+
}
270+
271+
// Acceptable Example - DTO with public setters
272+
public class UserDto { // DTO - exemption applies
273+
public string Name { get; set; } // Acceptable for DTOs
274+
}
275+
```
276+
277+
## Implementation Guidelines
278+
- **Domain Classes**:
279+
- Use private constructors and static factory methods for creating instances.
280+
- Avoid exposing setters for properties.
281+
- Apply all 9 rules strictly for business domain code.
282+
283+
- **Application Layer**:
284+
- Apply these rules to use case handlers and application services.
285+
- Focus on maintaining single responsibility and clean abstractions.
286+
287+
- **DTOs and Data Objects**:
288+
- Rules 3 (wrapping primitives), 8 (two instance variables), and 9 (no getters/setters) may be relaxed for DTOs.
289+
- Public properties with getters/setters are acceptable for data transfer objects.
290+
291+
- **Testing**:
292+
- Ensure tests validate the behavior of objects rather than their state.
293+
- Test classes may have relaxed rules for readability and maintainability.
294+
295+
- **Code Reviews**:
296+
- Enforce these rules during code reviews for domain and application code.
297+
- Be pragmatic about infrastructure and DTO code.
298+
299+
## References
300+
- [Object Calisthenics - Original 9 Rules by Jeff Bay](https://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf)
301+
- [ThoughtWorks - Object Calisthenics](https://www.thoughtworks.com/insights/blog/object-calisthenics)
302+
- [Clean Code: A Handbook of Agile Software Craftsmanship - Robert C. Martin](https://www.oreilly.com/library/view/clean-code-a/9780136083238/)

0 commit comments

Comments
 (0)