ワンクリックで
solid-clean-code
Canonical SOLID and Clean Code rules for backend tasks. Load on every backend task.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Canonical SOLID and Clean Code rules for backend tasks. Load on every backend task.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | solid-clean-code |
| description | Canonical SOLID and Clean Code rules for backend tasks. Load on every backend task. |
| requires | ["backend-dotnet-csharp"] |
| produces | ["method-design","class-boundaries","complexity-control"] |
A typical use case flow such as validate -> create -> persist -> return is one cohesive job. Keep that flow inline when each step is straightforward.
// ✅ CORRECT — cohesive flow, readable top-to-bottom
public async Task<Result<CreateProductResponseDto>> ExecuteAsync(
CreateProductRequestDto request,
CancellationToken ct)
{
List<string> errors = Validate(request);
if (errors.Count > 0)
return Result<CreateProductResponseDto>.Failure(HttpStatusCode.BadRequest)
.WithErrors(errors);
Product product = new()
{
Id = Guid.NewGuid(),
Name = request.Name,
Price = request.Price,
CreatedAt = DateTime.UtcNow
};
await _productRepository.AddAsync(product, ct);
await _unitOfWork.CompleteAsync(ct);
return Result<CreateProductResponseDto>.Success(HttpStatusCode.Created)
.WithPayload(product.ToCreateProductResponseDto());
}
Extract only when:
// ✅ CORRECT — separate jobs
public sealed class CreateOrder : ICreateOrder { }
public sealed class SendOrderConfirmation : ISendOrderConfirmation { }
// ❌ WRONG — one use case doing unrelated work
public sealed class CreateOrder : ICreateOrder
{
public async Task<Result<CreateOrderResponseDto>> ExecuteAsync(...)
{
await _orderRepository.AddAsync(order, ct);
await _emailSender.SendAsync(order.CustomerEmail, "Order confirmed", ct);
await _invoiceGenerator.GenerateAsync(order.Id, ct);
return Result<CreateOrderResponseDto>.Success(HttpStatusCode.Created);
}
}
// ❌ WRONG — modify existing use case for unrelated scenario
if (request.IsBulkImport)
{
// bulk logic here
}
// ✅ CORRECT
public sealed class CreateProduct : ICreateProduct { }
public sealed class BulkImportProducts : IBulkImportProducts { }
NotImplementedException from repository overrides just because a base contract does not fit// ❌ WRONG — deep nesting hides the happy path
if (request != null)
{
if (request.Items.Count > 0)
{
foreach (OrderItemDto item in request.Items)
{
if (item.Quantity > 0)
{
// logic buried here
}
}
}
}
// ✅ CORRECT — flat flow
if (request is null)
return Result<OrderDto>.Failure(HttpStatusCode.BadRequest);
if (request.Items.Count == 0)
return Result<OrderDto>.Failure(HttpStatusCode.BadRequest)
.WithErrors(["Order must have items"]);
// ❌ WRONG
Task<Result<List<ProductDto>>> GetProductsAsync(bool includeInactive, CancellationToken ct);
// ✅ CORRECT
Task<Result<List<ProductDto>>> GetActiveProductsAsync(CancellationToken ct);
Task<Result<List<ProductDto>>> GetAllProductsAsync(CancellationToken ct);
// ✅ CORRECT — comment explains why, not what
// External pricing API returns -1 when rate limit is hit — treat as unavailable.
if (response.Price == -1)
return Result<ProductDto>.Failure(HttpStatusCode.ServiceUnavailable);
If a method takes many related primitive arguments, group them into a request DTO.
// ❌ God class
public sealed class OrderManager
{
public Task<Order> CreateOrder() => throw new NotImplementedException();
public Task SendConfirmationEmail() => throw new NotImplementedException();
public Task ChargeCreditCard() => throw new NotImplementedException();
}
// ❌ Swiss army knife method
public Task<Result<ProductDto>> UpsertProductAsync(
CreateProductRequestDto? createRequest,
UpdateProductRequestDto? updateRequest,
bool isCreate,
bool skipValidation,
CancellationToken ct) => throw new NotImplementedException();
Structure and rules for .NET projects using Clean Architecture with DDD. Use when the project has complex business domain, multiple use cases, need to test business logic in isolation, or when the system is enterprise, e-commerce, ERP, CRM, or any rich domain. Do not use for simple CRUDs without logic — prefer Vertical Slice in that case. For implementation details, load the required `backend/dotnet/orms/ef-core/*/SKILL.md` leaf skill(s) or your chosen data access skill.
Structure and rules for .NET projects using Hexagonal Architecture (Ports & Adapters). Use when the project has multiple input channels (API, CLI, message queue), need to test the domain in isolation, or when adapters change frequently. Do not use for simple CRUDs without logic — prefer Vertical Slice in that case. For implementation details, load the required `backend/dotnet/orms/ef-core/*/SKILL.md` leaf skill(s) or your chosen data access skill.
Structure and rules for .NET projects using Onion Architecture. Use when the project has a strong domain-centric focus with DDD, aggregate roots, and the Specification pattern. All dependencies point inward toward the domain core. Do not use for simple CRUDs without logic — prefer Vertical Slice in that case. For implementation details, load the required `backend/dotnet/orms/ef-core/*/SKILL.md` leaf skill(s) or your chosen data access skill.
Canonical DbContext setup and registration rules for EF Core. Load when creating or modifying DbContext classes or their DI wiring.
Pure LINQ standards for .NET 10 projects. Covers language operators, query composition, projection patterns, filtering, grouping, and performance best practices over IEnumerable<T> and IQueryable<T>. Load when writing or reviewing LINQ expressions in any layer. DO NOT load expecting EF Core-specific methods (ToListAsync, AsNoTracking, Include, ExecuteUpdateAsync) — those belong to `backend/dotnet/orms/ef-core/query-best-practices/SKILL.md`.
Canonical rules for using AppDbContext DIRECTLY from application code (use cases / handlers) when the project's data-access pattern is Direct DbContext — no repositories, no UnitOfWork. Load when the chosen pattern is Direct DbContext and a use case reads or writes data. This is the counterpart to repository-usage; never load both for the same task.