| name | core-principles |
| description | Apply fundamental coding principles (SOLID, DRY, KISS) and structure projects for maintainability with clean architecture and separation of concerns. Use when refactoring, reviewing patterns, setting up project structure, or organizing modules. |
| metadata | {"author":"AgentX","version":"2.0.0","created":"2025-01-15","updated":"2026-02-27"} |
| compatibility | {"languages":["csharp"]} |
Core Principles & Code Organization
Purpose: Fundamental principles guiding production code development and project structure.
Focus: SOLID, DRY, KISS, design patterns, project organization.
When to Use This Skill
- Reviewing code for SOLID principle compliance
- Refactoring code for maintainability
- Choosing appropriate design patterns
- Teaching or evaluating engineering standards
- Setting up a new project structure
- Refactoring monolithic codebases
- Implementing dependency injection
- Organizing modules for team collaboration
- Choosing between architectural patterns
Prerequisites
- Basic OOP programming knowledge
Decision Tree
Architecture or code quality concern?
+-- New project setup? -> Apply Clean Architecture layers (Api/Core/Infrastructure)
+-- Class doing too much? -> Apply SRP - split by responsibility
+-- Need to extend behavior? -> Apply OCP - use interfaces, not if/else chains
+-- Deep inheritance tree? -> Favor composition over inheritance
+-- Hard to test? -> Apply DIP - inject abstractions, not concretions
+-- Code duplicated? -> Extract shared logic (DRY), but avoid premature abstraction
+-- Complex solution? -> Simplify (KISS) - can a junior dev understand it?
+-- Building speculative features? -> Stop (YAGNI) - build only what is needed now
SOLID Principles
Single Responsibility (SRP)
Each class has one reason to change.
public class User
{
public string Name { get; set; }
public void SaveToDatabase() { }
public void SendEmail() { }
}
public class User
{
public string Name { get; set; }
}
public class UserRepository
{
public void Save(User user) { }
}
public class EmailService
{
public void SendEmail(User user) { }
}
Open/Closed (OCP)
Open for extension, closed for modification.
public interface IPaymentProcessor
{
Task<PaymentResult> ProcessAsync(decimal amount);
}
public class CreditCardProcessor : IPaymentProcessor { }
public class PayPalProcessor : IPaymentProcessor { }
public class PaymentService
{
public async Task ProcessPaymentAsync(IPaymentProcessor processor, decimal amount)
{
return await processor.ProcessAsync(amount);
}
}
Liskov Substitution (LSP)
Subtypes must be substitutable for base types.
public abstract class Bird
{
public abstract void Move();
}
public class Sparrow : Bird
{
public override void Move() => Fly();
}
public class Penguin : Bird
{
public override void Move() => Walk();
}
Interface Segregation (ISP)
Many specific interfaces > one general interface.
public interface IWorker
{
void Work();
void Eat();
void Sleep();
}
public interface IWorkable { void Work(); }
public interface IFeedable { void Eat(); }
public interface IRestable { void Sleep(); }
Dependency Inversion (DIP)
Depend on abstractions, not concretions.
public class OrderService
{
private readonly IOrderRepository _repository;
public OrderService(IOrderRepository repository)
{
_repository = repository;
}
}
DRY (Don't Repeat Yourself)
public class UserService
{
public User GetUser(int id)
{
var conn = new SqlConnection(connectionString);
conn.Open();
}
public Order GetOrder(int id)
{
var conn = new SqlConnection(connectionString);
conn.Open();
}
}
public abstract class BaseRepository
{
protected SqlConnection GetConnection()
{
var conn = new SqlConnection(connectionString);
conn.Open();
return conn;
}
}
KISS (Keep It Simple, Stupid)
public class UserValidator
{
public bool Validate(User user)
{
var strategy = ValidatorStrategyFactory
.CreateStrategy(user.UserType)
.GetValidationChain()
.Execute(new ValidationContext(user));
return strategy.IsValid;
}
}
public class UserValidator
{
public bool Validate(User user)
{
return !string.IsNullOrEmpty(user.Email) &&
user.Email.Contains("@") &&
user.Age >= 13;
}
}
YAGNI (You Aren't Gonna Need It)
Don't build features "just in case". Build what's needed now.
Core Rules
[PASS] DO
- Follow SOLID - Especially SRP and DIP
- Keep functions small - One thing, well
- Use meaningful names - Self-documenting code
- Favor composition - Over inheritance
- Write tests - Design for testability
- Refactor regularly - Improve as you go
- Document complex logic - Why, not what
[FAIL] DON'T
- Violate SOLID - Leads to rigid, fragile code
- Duplicate code - Extract to methods/classes
- Overcomplicate - Simple solutions first
- Build unused features - YAGNI
- Skip code reviews - Catch issues early
- Ignore tech debt - Pay it down regularly
Code Organization
Merged from code-organization skill. Structure projects for clarity, maintainability, and scalability.
Organization Decision Tree
Code organization concern?
+- Starting new project? -> Use standard project structure template
+- File getting too long? -> Extract classes per Single Responsibility
+- Unclear naming? -> Apply naming conventions (PascalCase types, camelCase locals, _prefix privates)
+- Deep nesting? -> Flatten with early returns, extract methods
+- Hard to find code? -> Reorganize by namespace/feature grouping
- Circular dependencies? -> Apply Dependency Inversion, introduce interfaces
C# Project Structure
src/
+-- MyApp.Api/ # Entry point, controllers, middleware
+-- MyApp.Core/ # Domain models, interfaces, business logic
+-- MyApp.Infrastructure/ # Data access, external services
+-- MyApp.Shared/ # Cross-cutting concerns, utilities
tests/
+-- MyApp.Api.Tests/
+-- MyApp.Core.Tests/
+-- MyApp.Infrastructure.Tests/
Single Responsibility Examples
public class UserService
{
public User CreateUser(string email) { }
public void SendWelcomeEmail(User user) { }
public string GenerateReport() { }
}
public class UserService
{
public User CreateUser(string email) { }
}
public class NotificationService
{
public void SendWelcomeEmail(User user) { }
}
public class UserReportService
{
public string GenerateReport() { }
}
Naming Conventions
| Element | Convention | Example |
|---|
| Class | PascalCase | OrderService |
| Interface | I + PascalCase | IOrderRepository |
| Method | PascalCase | GetOrderById() |
| Property | PascalCase | OrderDate |
| Local variable | camelCase | orderCount |
| Private field | _camelCase | _orderRepository |
| Constant | PascalCase | MaxRetryCount |
Code Organization Troubleshooting
| Issue | Solution |
|---|
| File over 500 lines | Split into partial classes or extract helper classes |
| Too many constructor parameters | Apply facade pattern or restructure dependencies |
| Feature code scattered | Reorganize by feature folders instead of technical layers |
See Also: Testing
Last Updated: February 27, 2026
Anti-Patterns
- God Class: One class handles persistence, validation, and notifications -> Split into focused classes per SRP
- Speculative Generality: Building abstract factories and plugin systems for one implementation -> Start concrete, abstract when a second case appears (YAGNI)
- Premature DRY: Merging two vaguely similar functions into one with flag parameters -> Tolerate minor duplication until the pattern is clear
- Deep Inheritance: 4+ level inheritance hierarchies -> Flatten with composition and interfaces
- Service Locator: Resolving dependencies at runtime from a global container -> Use constructor injection (DIP)
- Copy-Paste Architecture: Duplicating entire classes instead of extracting shared behavior -> Extract base class or shared utility
Troubleshooting
| Issue | Solution |
|---|
| Over-engineering with patterns | Apply YAGNI - only use patterns when complexity warrants them |
| DRY violation detected | Extract shared logic into a utility method or base class |
References