@pratikpsl/agent-skills 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/LICENSE +201 -201
  2. package/package.json +2 -2
  3. package/src/templates/dotnet/AgentSkills/README.md +40 -40
  4. package/src/templates/dotnet/AgentSkills/agents/README.md +11 -11
  5. package/src/templates/dotnet/AgentSkills/agents/architect.agent.md +59 -59
  6. package/src/templates/dotnet/AgentSkills/agents/developer.agent.md +88 -88
  7. package/src/templates/dotnet/AgentSkills/memory/index.md +21 -21
  8. package/src/templates/dotnet/AgentSkills/memory/lessons/api.md +3 -3
  9. package/src/templates/dotnet/AgentSkills/memory/lessons/auth.md +3 -3
  10. package/src/templates/dotnet/AgentSkills/memory/lessons/csharp.md +3 -3
  11. package/src/templates/dotnet/AgentSkills/memory/lessons/db.md +3 -3
  12. package/src/templates/dotnet/AgentSkills/memory/lessons/design.md +3 -3
  13. package/src/templates/dotnet/AgentSkills/memory/lessons/infra.md +2 -2
  14. package/src/templates/dotnet/AgentSkills/memory/lessons/mcp.md +3 -3
  15. package/src/templates/dotnet/AgentSkills/memory/lessons/testing.md +3 -3
  16. package/src/templates/dotnet/AgentSkills/memory/schema.md +26 -26
  17. package/src/templates/dotnet/AgentSkills/skills/INDEX.md +8 -8
  18. package/src/templates/dotnet/AgentSkills/skills/code-standards/SKILL.md +122 -122
  19. package/src/templates/dotnet/AgentSkills/skills/core/SKILL.md +23 -23
  20. package/src/templates/dotnet/AgentSkills/skills/csharp-xunit/SKILL.md +67 -67
  21. package/src/templates/dotnet/AgentSkills/skills/design/SKILL.md +108 -108
  22. package/src/templates/dotnet/AgentSkills/skills/dotnet-api/SKILL.md +303 -303
  23. package/src/templates/dotnet/AgentSkills/skills/dotnet-best-practices/SKILL.md +170 -170
  24. package/src/templates/dotnet/AgentSkills/skills/harness/SKILL.md +62 -62
  25. package/src/templates/dotnet/AgentSkills/skills/mcp_dotnet/SKILL.md +54 -54
  26. package/src/templates/dotnet/manifest.json +2 -2
@@ -1,122 +1,122 @@
1
- ---
2
- name: code-standards
3
- description: >
4
- Load when writing, reviewing, or refactoring C# code.
5
- Covers naming, structure, comments, and commit hygiene.
6
- ---
7
-
8
- # Code Standards
9
-
10
- Language: C#. Every example is production code, not pseudocode.
11
-
12
- ## 1. No Magic Values
13
-
14
- ```csharp
15
- // Bad
16
- if (role == 3) { }
17
-
18
- // Good
19
- private const int AdminRoleId = 3;
20
- if (role == AdminRoleId) { }
21
- ```
22
-
23
- ## 2. Meaningful Names
24
-
25
- Names explain what a value represents and why it matters. If a comment is needed to explain a variable, rename it.
26
-
27
- ```csharp
28
- // Bad
29
- int d = 86400;
30
- bool flag = true;
31
-
32
- // Good
33
- const int SecondsPerDay = 86400;
34
- bool isUserVerified = true;
35
- ```
36
-
37
- ## 3. One Function, One Responsibility
38
-
39
- One function should do one thing. If you cannot summarize it in one sentence, split it.
40
-
41
- ## 4. Descriptive Booleans
42
-
43
- ```csharp
44
- // Bad
45
- bool check = true;
46
-
47
- // Good
48
- bool hasPermission = true;
49
- bool isSessionExpired = false;
50
- ```
51
-
52
- ## 5. DRY
53
-
54
- Keep one source of truth per piece of logic. Apply judgment: premature abstraction is also harmful.
55
-
56
- ## 6. Early Returns Over Deep Nesting
57
-
58
- ```csharp
59
- // Bad
60
- void Process(User user)
61
- {
62
- if (user != null)
63
- {
64
- if (user.IsActive)
65
- {
66
- // Main logic
67
- }
68
- }
69
- }
70
-
71
- // Good
72
- void Process(User user)
73
- {
74
- if (user is null) return;
75
- if (!user.IsActive) return;
76
-
77
- // Main logic
78
- }
79
- ```
80
-
81
- ## 7. Comment Why, Not What
82
-
83
- ```csharp
84
- // Bad
85
- // Increment counter.
86
- count++;
87
-
88
- // Good
89
- // Back off before HTTP 429; this API caps requests at 100 per minute.
90
- if (requestCount >= RateLimitBackoffThreshold) { }
91
- ```
92
-
93
- ## 8. Limit Function Arguments
94
-
95
- More than 3 arguments should usually become a config object, command object, or record.
96
-
97
- ```csharp
98
- // Bad
99
- CreateUser("Alice", "alice@example.com", true, "admin", "UTC");
100
-
101
- // Good
102
- CreateUser(new UserConfig
103
- {
104
- Name = "Alice",
105
- Email = "alice@example.com",
106
- IsVerified = true,
107
- Role = Role.Admin,
108
- Timezone = "UTC"
109
- });
110
- ```
111
-
112
- ## 9. Meaningful Commits
113
-
114
- ```text
115
- Bad:
116
- fix bug
117
- update stuff
118
-
119
- Good:
120
- fix: prevent double-submit on payment
121
- refactor: extract shared email validation
122
- ```
1
+ ---
2
+ name: code-standards
3
+ description: >
4
+ Load when writing, reviewing, or refactoring C# code.
5
+ Covers naming, structure, comments, and commit hygiene.
6
+ ---
7
+
8
+ # Code Standards
9
+
10
+ Language: C#. Every example is production code, not pseudocode.
11
+
12
+ ## 1. No Magic Values
13
+
14
+ ```csharp
15
+ // Bad
16
+ if (role == 3) { }
17
+
18
+ // Good
19
+ private const int AdminRoleId = 3;
20
+ if (role == AdminRoleId) { }
21
+ ```
22
+
23
+ ## 2. Meaningful Names
24
+
25
+ Names explain what a value represents and why it matters. If a comment is needed to explain a variable, rename it.
26
+
27
+ ```csharp
28
+ // Bad
29
+ int d = 86400;
30
+ bool flag = true;
31
+
32
+ // Good
33
+ const int SecondsPerDay = 86400;
34
+ bool isUserVerified = true;
35
+ ```
36
+
37
+ ## 3. One Function, One Responsibility
38
+
39
+ One function should do one thing. If you cannot summarize it in one sentence, split it.
40
+
41
+ ## 4. Descriptive Booleans
42
+
43
+ ```csharp
44
+ // Bad
45
+ bool check = true;
46
+
47
+ // Good
48
+ bool hasPermission = true;
49
+ bool isSessionExpired = false;
50
+ ```
51
+
52
+ ## 5. DRY
53
+
54
+ Keep one source of truth per piece of logic. Apply judgment: premature abstraction is also harmful.
55
+
56
+ ## 6. Early Returns Over Deep Nesting
57
+
58
+ ```csharp
59
+ // Bad
60
+ void Process(User user)
61
+ {
62
+ if (user != null)
63
+ {
64
+ if (user.IsActive)
65
+ {
66
+ // Main logic
67
+ }
68
+ }
69
+ }
70
+
71
+ // Good
72
+ void Process(User user)
73
+ {
74
+ if (user is null) return;
75
+ if (!user.IsActive) return;
76
+
77
+ // Main logic
78
+ }
79
+ ```
80
+
81
+ ## 7. Comment Why, Not What
82
+
83
+ ```csharp
84
+ // Bad
85
+ // Increment counter.
86
+ count++;
87
+
88
+ // Good
89
+ // Back off before HTTP 429; this API caps requests at 100 per minute.
90
+ if (requestCount >= RateLimitBackoffThreshold) { }
91
+ ```
92
+
93
+ ## 8. Limit Function Arguments
94
+
95
+ More than 3 arguments should usually become a config object, command object, or record.
96
+
97
+ ```csharp
98
+ // Bad
99
+ CreateUser("Alice", "alice@example.com", true, "admin", "UTC");
100
+
101
+ // Good
102
+ CreateUser(new UserConfig
103
+ {
104
+ Name = "Alice",
105
+ Email = "alice@example.com",
106
+ IsVerified = true,
107
+ Role = Role.Admin,
108
+ Timezone = "UTC"
109
+ });
110
+ ```
111
+
112
+ ## 9. Meaningful Commits
113
+
114
+ ```text
115
+ Bad:
116
+ fix bug
117
+ update stuff
118
+
119
+ Good:
120
+ fix: prevent double-submit on payment
121
+ refactor: extract shared email validation
122
+ ```
@@ -1,26 +1,26 @@
1
- ---
2
- name: core
3
- description: >
4
- Load on every task. Non-negotiable principles that govern
5
- all work: how to think, what to change, and how to verify.
6
- ---
7
-
8
- # Core Principles
9
-
10
- > Simplification is the ultimate sophistication.
11
- > Write code that is simple, small, easy to delete, and adds nothing unnecessary.
12
-
13
- 1. **Think Before Coding** – Understand the goal before writing a line. If requirements are ambiguous, **stop and ask** — assumptions compound. Surface tradeoffs to the caller, not just in comments.
14
- 2. **Simplicity First** - Write the minimum code that correctly solves the problem. Avoid speculative features.
15
- 3. **Surgical Changes** – Touch only what the task requires. Avoid "while I'm here" changes. Refactoring is a separate, explicit task — never bundled into a feature or fix.
16
- 4. **Goal-Driven Testing** – Define success before writing code. Tests are the contract. Cover the failure path — a test suite that only passes on happy inputs is not a contract, it's a wish.
17
- 5. **No Race Conditions** - Treat shared mutable state as dangerous. Prefer immutability.
18
- 6. **Agent Memory** – Every task is a learning loop. Read `AgentSkills/memory/index.md` at task start, then load only the domain file(s) matching your task. Before closing, check if a new lesson is warranted — if so, read `AgentSkills/memory/schema.md`, append one line to the correct domain file, and update the count in `index.md`.
19
-
20
- 7. **Fail Loudly, Recover Gracefully** – Errors are a first-class output. When something goes wrong, fail loudly with context (what, where, relevant IDs). Never swallow exceptions silently. Recovery paths must be as deliberate as the happy path.
21
-
22
- 8. **Prefer Reversible Moves** – When two approaches solve the problem equally well, choose the one that can be undone. Flag irreversible changes (schema drops, destructive migrations, hard deletes) explicitly before executing them.
23
-
1
+ ---
2
+ name: core
3
+ description: >
4
+ Load on every task. Non-negotiable principles that govern
5
+ all work: how to think, what to change, and how to verify.
6
+ ---
7
+
8
+ # Core Principles
9
+
10
+ > Simplification is the ultimate sophistication.
11
+ > Write code that is simple, small, easy to delete, and adds nothing unnecessary.
12
+
13
+ 1. **Think Before Coding** – Understand the goal before writing a line. If requirements are ambiguous, **stop and ask** — assumptions compound. Surface tradeoffs to the caller, not just in comments.
14
+ 2. **Simplicity First** - Write the minimum code that correctly solves the problem. Avoid speculative features.
15
+ 3. **Surgical Changes** – Touch only what the task requires. Avoid "while I'm here" changes. Refactoring is a separate, explicit task — never bundled into a feature or fix.
16
+ 4. **Goal-Driven Testing** – Define success before writing code. Tests are the contract. Cover the failure path — a test suite that only passes on happy inputs is not a contract, it's a wish.
17
+ 5. **No Race Conditions** - Treat shared mutable state as dangerous. Prefer immutability.
18
+ 6. **Agent Memory** – Every task is a learning loop. Read `AgentSkills/memory/index.md` at task start, then load only the domain file(s) matching your task. Before closing, check if a new lesson is warranted — if so, read `AgentSkills/memory/schema.md`, append one line to the correct domain file, and update the count in `index.md`.
19
+
20
+ 7. **Fail Loudly, Recover Gracefully** – Errors are a first-class output. When something goes wrong, fail loudly with context (what, where, relevant IDs). Never swallow exceptions silently. Recovery paths must be as deliberate as the happy path.
21
+
22
+ 8. **Prefer Reversible Moves** – When two approaches solve the problem equally well, choose the one that can be undone. Flag irreversible changes (schema drops, destructive migrations, hard deletes) explicitly before executing them.
23
+
24
24
  ## Prerequisite Gate
25
25
 
26
26
  Every task starts with the shared operating contract in
@@ -1,68 +1,68 @@
1
- ---
2
- name: csharp-xunit
3
- description: 'Get best practices for XUnit unit testing, including data-driven tests'
4
- ---
5
-
6
- # XUnit Best Practices
7
-
8
- Your goal is to help me write effective unit tests with XUnit, covering both standard and data-driven testing approaches.
9
-
10
- ## Project Setup
11
-
12
- - Use a separate test project with naming convention `[ProjectName].Tests`
13
- - Reference Microsoft.NET.Test.Sdk, xunit, and xunit.runner.visualstudio packages
14
- - Create test classes that match the classes being tested (e.g., `CalculatorTests` for `Calculator`)
15
- - Use .NET SDK test commands: `dotnet test` for running tests
16
-
17
- ## Test Structure
18
-
19
- - No test class attributes required (unlike MSTest/NUnit)
20
- - Use fact-based tests with `[Fact]` attribute for simple tests
21
- - Follow the Arrange-Act-Assert (AAA) pattern
22
- - Name tests using the pattern `MethodName_Scenario_ExpectedBehavior`
23
- - Use constructor for setup and `IDisposable.Dispose()` for teardown
24
- - Use `IClassFixture<T>` for shared context between tests in a class
25
- - Use `ICollectionFixture<T>` for shared context between multiple test classes
26
-
27
- ## Standard Tests
28
-
29
- - Keep tests focused on a single behavior
30
- - Avoid testing multiple behaviors in one test method
31
- - Use clear assertions that express intent
32
- - Include only the assertions needed to verify the test case
33
- - Make tests independent and idempotent (can run in any order)
34
- - Avoid test interdependencies
35
-
36
- ## Data-Driven Tests
37
-
38
- - Use `[Theory]` combined with data source attributes
39
- - Use `[InlineData]` for inline test data
40
- - Use `[MemberData]` for method-based test data
41
- - Use `[ClassData]` for class-based test data
42
- - Create custom data attributes by implementing `DataAttribute`
43
- - Use meaningful parameter names in data-driven tests
44
-
45
- ## Assertions
46
-
47
- - Use `Assert.Equal` for value equality
48
- - Use `Assert.Same` for reference equality
49
- - Use `Assert.True`/`Assert.False` for boolean conditions
50
- - Use `Assert.Contains`/`Assert.DoesNotContain` for collections
51
- - Use `Assert.Matches`/`Assert.DoesNotMatch` for regex pattern matching
52
- - Use `Assert.Throws<T>` or `await Assert.ThrowsAsync<T>` to test exceptions
53
- - Use fluent assertions library for more readable assertions
54
-
55
- ## Mocking and Isolation
56
-
57
- - Consider using Moq or NSubstitute alongside XUnit
58
- - Mock dependencies to isolate units under test
59
- - Use interfaces to facilitate mocking
60
- - Consider using a DI container for complex test setups
61
-
62
- ## Test Organization
63
-
64
- - Group tests by feature or component
65
- - Use `[Trait("Category", "CategoryName")]` for categorization
66
- - Use collection fixtures to group tests with shared dependencies
67
- - Consider output helpers (`ITestOutputHelper`) for test diagnostics
1
+ ---
2
+ name: csharp-xunit
3
+ description: 'Get best practices for XUnit unit testing, including data-driven tests'
4
+ ---
5
+
6
+ # XUnit Best Practices
7
+
8
+ Your goal is to help me write effective unit tests with XUnit, covering both standard and data-driven testing approaches.
9
+
10
+ ## Project Setup
11
+
12
+ - Use a separate test project with naming convention `[ProjectName].Tests`
13
+ - Reference Microsoft.NET.Test.Sdk, xunit, and xunit.runner.visualstudio packages
14
+ - Create test classes that match the classes being tested (e.g., `CalculatorTests` for `Calculator`)
15
+ - Use .NET SDK test commands: `dotnet test` for running tests
16
+
17
+ ## Test Structure
18
+
19
+ - No test class attributes required (unlike MSTest/NUnit)
20
+ - Use fact-based tests with `[Fact]` attribute for simple tests
21
+ - Follow the Arrange-Act-Assert (AAA) pattern
22
+ - Name tests using the pattern `MethodName_Scenario_ExpectedBehavior`
23
+ - Use constructor for setup and `IDisposable.Dispose()` for teardown
24
+ - Use `IClassFixture<T>` for shared context between tests in a class
25
+ - Use `ICollectionFixture<T>` for shared context between multiple test classes
26
+
27
+ ## Standard Tests
28
+
29
+ - Keep tests focused on a single behavior
30
+ - Avoid testing multiple behaviors in one test method
31
+ - Use clear assertions that express intent
32
+ - Include only the assertions needed to verify the test case
33
+ - Make tests independent and idempotent (can run in any order)
34
+ - Avoid test interdependencies
35
+
36
+ ## Data-Driven Tests
37
+
38
+ - Use `[Theory]` combined with data source attributes
39
+ - Use `[InlineData]` for inline test data
40
+ - Use `[MemberData]` for method-based test data
41
+ - Use `[ClassData]` for class-based test data
42
+ - Create custom data attributes by implementing `DataAttribute`
43
+ - Use meaningful parameter names in data-driven tests
44
+
45
+ ## Assertions
46
+
47
+ - Use `Assert.Equal` for value equality
48
+ - Use `Assert.Same` for reference equality
49
+ - Use `Assert.True`/`Assert.False` for boolean conditions
50
+ - Use `Assert.Contains`/`Assert.DoesNotContain` for collections
51
+ - Use `Assert.Matches`/`Assert.DoesNotMatch` for regex pattern matching
52
+ - Use `Assert.Throws<T>` or `await Assert.ThrowsAsync<T>` to test exceptions
53
+ - Use fluent assertions library for more readable assertions
54
+
55
+ ## Mocking and Isolation
56
+
57
+ - Consider using Moq or NSubstitute alongside XUnit
58
+ - Mock dependencies to isolate units under test
59
+ - Use interfaces to facilitate mocking
60
+ - Consider using a DI container for complex test setups
61
+
62
+ ## Test Organization
63
+
64
+ - Group tests by feature or component
65
+ - Use `[Trait("Category", "CategoryName")]` for categorization
66
+ - Use collection fixtures to group tests with shared dependencies
67
+ - Consider output helpers (`ITestOutputHelper`) for test diagnostics
68
68
  - Skip tests conditionally with `Skip = "reason"` in fact/theory attributes
@@ -1,108 +1,108 @@
1
- ---
2
- name: design
3
- description: >
4
- Load when designing, architecting, or implementing patterns in C#.
5
- Covers project folder structure (vertical slice), SOLID, KISS, YAGNI,
6
- DRY, composition, Singleton, and Factory.
7
- ---
8
-
9
- # Design Principles and Patterns
10
-
11
- ## Project Structure
12
-
13
- Organise by **feature (vertical slice)**, not by technical layer.
14
- Each feature folder owns everything needed for its use case: command, handler, DTO, validator, and endpoint.
15
- This keeps changes local, avoids cross-cutting layers, and scales without requiring global refactors.
16
-
17
- ```text
18
- src/
19
- ├── Features/
20
- │ ├── Products/
21
- │ │ ├── CreateProductCommand.cs
22
- │ │ ├── CreateProductHandler.cs
23
- │ │ ├── ProductDto.cs
24
- │ │ ├── ProductValidator.cs
25
- │ │ └── ProductEndpoints.cs
26
- │ ├── Orders/
27
- │ │ ├── CreateOrderCommand.cs
28
- │ │ ├── CreateOrderHandler.cs
29
- │ │ ├── OrderDto.cs
30
- │ │ ├── OrderValidator.cs
31
- │ │ └── OrderEndpoints.cs
32
- │ └── ...
33
- ├── Shared/
34
- │ ├── Middleware/
35
- │ └── Utilities/
36
- └── Program.cs
37
- ```
38
-
39
- **Rules:**
40
- - One folder per feature — never split a feature across `Commands/`, `Queries/`, `Controllers/` top-level layers.
41
- - When a feature grows, split it into sub-features within the same `Features/<Feature>/` directory before creating a new top-level folder.
42
- - Shared cross-cutting code (middleware, utilities, base types) lives in `Shared/`, not duplicated per feature.
43
- - `Program.cs` wires up DI, middleware, and endpoint registration only — no business logic.
44
-
45
- ## SOLID
46
-
47
- | | Principle | In Practice |
48
- |---|---|---|
49
- | S | Single Responsibility | One class, one reason to change |
50
- | O | Open / Closed | Open to extension, closed to modification |
51
- | L | Liskov Substitution | Subtypes must work wherever the base type works |
52
- | I | Interface Segregation | Small, focused interfaces over large, general ones |
53
- | D | Dependency Inversion | Depend on abstractions, not concrete implementations |
54
-
55
- ## KISS
56
-
57
- Prefer the obvious solution. If a junior engineer cannot understand it in 5 minutes, simplify it.
58
-
59
- ## YAGNI
60
-
61
- Do not build something until it is needed. Solve today's requirement, not tomorrow's guess.
62
-
63
- ```csharp
64
- // Bad: built "just in case" when only one format exists.
65
- public interface IExporter { }
66
- public class ExporterFactory { }
67
-
68
- // Good: solve what exists now.
69
- public string ExportToCsv(Report report) { }
70
- ```
71
-
72
- ## DRY
73
-
74
- Keep one source of truth per piece of knowledge: logic, configuration, and data schemas.
75
-
76
- ## Composition Over Inheritance
77
-
78
- Use inheritance only for true "is-a" relationships. Prefer interfaces and delegation.
79
-
80
- ## Pattern: Singleton
81
-
82
- Use when exactly one instance must coordinate shared state. Avoid when it creates hidden global state.
83
-
84
- ```csharp
85
- public sealed class AppConfig
86
- {
87
- private static readonly Lazy<AppConfig> InstanceHolder =
88
- new(() => new AppConfig());
89
-
90
- public static AppConfig Instance => InstanceHolder.Value;
91
-
92
- private AppConfig()
93
- {
94
- }
95
- }
96
- ```
97
-
98
- ## Pattern: Factory
99
-
100
- Use when creation is complex, varies by type, or must be decoupled from consumers.
101
-
102
- ```csharp
103
- // Bad
104
- var handler = type == "email" ? new EmailHandler() : new SmsHandler();
105
-
106
- // Good
107
- var handler = NotificationFactory.Create(type);
108
- ```
1
+ ---
2
+ name: design
3
+ description: >
4
+ Load when designing, architecting, or implementing patterns in C#.
5
+ Covers project folder structure (vertical slice), SOLID, KISS, YAGNI,
6
+ DRY, composition, Singleton, and Factory.
7
+ ---
8
+
9
+ # Design Principles and Patterns
10
+
11
+ ## Project Structure
12
+
13
+ Organise by **feature (vertical slice)**, not by technical layer.
14
+ Each feature folder owns everything needed for its use case: command, handler, DTO, validator, and endpoint.
15
+ This keeps changes local, avoids cross-cutting layers, and scales without requiring global refactors.
16
+
17
+ ```text
18
+ src/
19
+ ├── Features/
20
+ │ ├── Products/
21
+ │ │ ├── CreateProductCommand.cs
22
+ │ │ ├── CreateProductHandler.cs
23
+ │ │ ├── ProductDto.cs
24
+ │ │ ├── ProductValidator.cs
25
+ │ │ └── ProductEndpoints.cs
26
+ │ ├── Orders/
27
+ │ │ ├── CreateOrderCommand.cs
28
+ │ │ ├── CreateOrderHandler.cs
29
+ │ │ ├── OrderDto.cs
30
+ │ │ ├── OrderValidator.cs
31
+ │ │ └── OrderEndpoints.cs
32
+ │ └── ...
33
+ ├── Shared/
34
+ │ ├── Middleware/
35
+ │ └── Utilities/
36
+ └── Program.cs
37
+ ```
38
+
39
+ **Rules:**
40
+ - One folder per feature — never split a feature across `Commands/`, `Queries/`, `Controllers/` top-level layers.
41
+ - When a feature grows, split it into sub-features within the same `Features/<Feature>/` directory before creating a new top-level folder.
42
+ - Shared cross-cutting code (middleware, utilities, base types) lives in `Shared/`, not duplicated per feature.
43
+ - `Program.cs` wires up DI, middleware, and endpoint registration only — no business logic.
44
+
45
+ ## SOLID
46
+
47
+ | | Principle | In Practice |
48
+ |---|---|---|
49
+ | S | Single Responsibility | One class, one reason to change |
50
+ | O | Open / Closed | Open to extension, closed to modification |
51
+ | L | Liskov Substitution | Subtypes must work wherever the base type works |
52
+ | I | Interface Segregation | Small, focused interfaces over large, general ones |
53
+ | D | Dependency Inversion | Depend on abstractions, not concrete implementations |
54
+
55
+ ## KISS
56
+
57
+ Prefer the obvious solution. If a junior engineer cannot understand it in 5 minutes, simplify it.
58
+
59
+ ## YAGNI
60
+
61
+ Do not build something until it is needed. Solve today's requirement, not tomorrow's guess.
62
+
63
+ ```csharp
64
+ // Bad: built "just in case" when only one format exists.
65
+ public interface IExporter { }
66
+ public class ExporterFactory { }
67
+
68
+ // Good: solve what exists now.
69
+ public string ExportToCsv(Report report) { }
70
+ ```
71
+
72
+ ## DRY
73
+
74
+ Keep one source of truth per piece of knowledge: logic, configuration, and data schemas.
75
+
76
+ ## Composition Over Inheritance
77
+
78
+ Use inheritance only for true "is-a" relationships. Prefer interfaces and delegation.
79
+
80
+ ## Pattern: Singleton
81
+
82
+ Use when exactly one instance must coordinate shared state. Avoid when it creates hidden global state.
83
+
84
+ ```csharp
85
+ public sealed class AppConfig
86
+ {
87
+ private static readonly Lazy<AppConfig> InstanceHolder =
88
+ new(() => new AppConfig());
89
+
90
+ public static AppConfig Instance => InstanceHolder.Value;
91
+
92
+ private AppConfig()
93
+ {
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## Pattern: Factory
99
+
100
+ Use when creation is complex, varies by type, or must be decoupled from consumers.
101
+
102
+ ```csharp
103
+ // Bad
104
+ var handler = type == "email" ? new EmailHandler() : new SmsHandler();
105
+
106
+ // Good
107
+ var handler = NotificationFactory.Create(type);
108
+ ```