clean-code-dotnet

安装量: 38
排名: #18561

安装

npx skills add https://github.com/thapaliyabikendra/ai-artifacts --skill clean-code-dotnet

Clean Code .NET Clean Code principles from Robert C. Martin, adapted for C#/.NET. Use as checklist during code reviews and refactoring. Naming Use Meaningful Names // ❌ Bad int d ; var dataFromDb = db . GetFromService ( ) . ToList ( ) ; // ✅ Good int daySinceModification ; var employees = _employeeService . GetEmployees ( ) . ToList ( ) ; Avoid Hungarian Notation // ❌ Bad int iCounter ; string strFullName ; public bool IsShopOpen ( string pDay , int pAmount ) { } // ✅ Good int counter ; string fullName ; public bool IsShopOpen ( string day , int amount ) { } Use Pronounceable Names // ❌ Bad public class Employee { public DateTime sWorkDate { get ; set ; } public DateTime modTime { get ; set ; } } // ✅ Good public class Employee { public DateTime StartWorkingDate { get ; set ; } public DateTime ModificationTime { get ; set ; } } Use Domain Names // ✅ Good - Use patterns developers know var singletonObject = SingleObject . GetInstance ( ) ; var factory = new PatientFactory ( ) ; var repository = new PatientRepository ( ) ; Variables Return Early, Avoid Deep Nesting // ❌ Bad - Deep nesting public bool IsShopOpen ( string day ) { if ( ! string . IsNullOrEmpty ( day ) ) { day = day . ToLower ( ) ; if ( day == "friday" ) { return true ; } else if ( day == "saturday" ) { return true ; } // ... more nesting } return false ; } // ✅ Good - Guard clauses + early return public bool IsShopOpen ( string day ) { if ( string . IsNullOrEmpty ( day ) ) return false ; var openingDays = new [ ] { "friday" , "saturday" , "sunday" } ; return openingDays . Contains ( day . ToLower ( ) ) ; } Avoid Magic Strings // ❌ Bad if ( userRole == "Admin" ) { } // ✅ Good const string AdminRole = "Admin" ; if ( userRole == AdminRole ) { } // ✅ Better - Use enum public enum UserRole { Admin , User , Guest } if ( userRole == UserRole . Admin ) { } Don't Add Unneeded Context // ❌ Bad - Redundant prefix public class Car { public string CarMake { get ; set ; } public string CarModel { get ; set ; } public string CarColor { get ; set ; } } // ✅ Good public class Car { public string Make { get ; set ; } public string Model { get ; set ; } public string Color { get ; set ; } } Use Default Arguments // ❌ Bad public void CreateMicrobrewery ( string name = null ) { var breweryName = ! string . IsNullOrEmpty ( name ) ? name : "Hipster Brew Co." ; } // ✅ Good public void CreateMicrobrewery ( string breweryName = "Hipster Brew Co." ) { // breweryName is always valid } Functions Functions Should Do One Thing // ❌ Bad - Multiple responsibilities public void SendEmailToListOfClients ( string [ ] clients ) { foreach ( var client in clients ) { var clientRecord = db . Find ( client ) ; if ( clientRecord . IsActive ( ) ) { Email ( client ) ; } } } // ✅ Good - Single responsibility public void SendEmailToActiveClients ( string [ ] clients ) { var activeClients = GetActiveClients ( clients ) ; activeClients . ForEach ( client => Email ( client ) ) ; } public List < Client

GetActiveClients ( string [ ] clients ) { return db . Find ( clients ) . Where ( c => c . IsActive ) . ToList ( ) ; } Avoid Side Effects // ❌ Bad - Modifies global state var name = "Ryan McDermott" ; public void SplitAndEnrichFullName ( ) { var temp = name . Split ( " " ) ; name = $"First: { temp [ 0 ] } , Last: { temp [ 1 ] } " ; // Side effect! } // ✅ Good - Pure function public string SplitAndEnrichFullName ( string name ) { var temp = name . Split ( " " ) ; return $"First: { temp [ 0 ] } , Last: { temp [ 1 ] } " ; } Avoid Negative Conditionals // ❌ Bad public bool IsDOMNodeNotPresent ( string node ) { } if ( ! IsDOMNodeNotPresent ( node ) ) { } // Double negative! // ✅ Good public bool IsDOMNodePresent ( string node ) { } if ( IsDOMNodePresent ( node ) ) { } Avoid Flag Parameters // ❌ Bad - Flag indicates multiple responsibilities public void CreateFile ( string name , bool temp = false ) { if ( temp ) Touch ( "./temp/" + name ) ; else Touch ( name ) ; } // ✅ Good - Separate methods public void CreateFile ( string name ) => Touch ( name ) ; public void CreateTempFile ( string name ) => Touch ( "./temp/" + name ) ; Limit Function Arguments (2 or fewer) // ❌ Bad public void CreateMenu ( string title , string body , string buttonText , bool cancellable ) { } // ✅ Good - Use object public class MenuConfig { public string Title { get ; set ; } public string Body { get ; set ; } public string ButtonText { get ; set ; } public bool Cancellable { get ; set ; } } public void CreateMenu ( MenuConfig config ) { } Encapsulate Conditionals // ❌ Bad if ( article . state == "published" ) { } // ✅ Good if ( article . IsPublished ( ) ) { } Remove Dead Code // ❌ Bad public void OldRequestModule ( string url ) { } // Unused! public void NewRequestModule ( string url ) { } var request = NewRequestModule ( requestUrl ) ; // ✅ Good - Delete unused code public void RequestModule ( string url ) { } var request = RequestModule ( requestUrl ) ; SOLID Principles Single Responsibility (SRP) // ❌ Bad - Two responsibilities class UserSettings { public void ChangeSettings ( Settings settings ) { if ( VerifyCredentials ( ) ) { / ... / } } private bool VerifyCredentials ( ) { / ... / } // Auth responsibility } // ✅ Good - Separated class UserAuth { public bool VerifyCredentials ( ) { / ... / } } class UserSettings { private readonly UserAuth _auth ; public void ChangeSettings ( Settings settings ) { if ( _auth . VerifyCredentials ( ) ) { / ... / } } } Open/Closed (OCP) // ❌ Bad - Must modify to extend class HttpRequester { public bool Fetch ( string url ) { if ( adapterName == "ajaxAdapter" ) return MakeAjaxCall ( url ) ; else if ( adapterName == "httpNodeAdapter" ) return MakeHttpCall ( url ) ; // Must add more else-if for new adapters! } } // ✅ Good - Open for extension, closed for modification interface IAdapter { bool Request ( string url ) ; } class AjaxAdapter : IAdapter { public bool Request ( string url ) { / ... / } } class HttpRequester { private readonly IAdapter _adapter ; public bool Fetch ( string url ) => _adapter . Request ( url ) ; } Liskov Substitution (LSP) // ❌ Bad - Square breaks Rectangle behavior class Square : Rectangle { public override void SetWidth ( double width ) { Width = Height = width ; } } // ✅ Good - Use abstraction abstract class Shape { public abstract double GetArea ( ) ; } class Rectangle : Shape { / ... / } class Square : Shape { / ... / } Interface Segregation (ISP) // ❌ Bad - Robot can't eat but must implement interface IEmployee { void Work ( ) ; void Eat ( ) ; } class Robot : IEmployee { public void Work ( ) { / ... / } public void Eat ( ) { / Robot can't eat! / } } // ✅ Good - Segregated interfaces interface IWorkable { void Work ( ) ; } interface IFeedable { void Eat ( ) ; } class Human : IWorkable , IFeedable { / ... / } class Robot : IWorkable { / ... / } Dependency Inversion (DIP) // ❌ Bad - Depends on concrete types class Manager { private readonly Robot _robot ; private readonly Human _human ; } // ✅ Good - Depends on abstractions class Manager { private readonly IEnumerable < IEmployee

_employees ; public Manager ( IEnumerable < IEmployee

employees ) { _employees = employees ; } } Constructor Dependency Smell (SRP Indicator) Too many constructor dependencies indicate SRP violation: // ❌ Code Smell: 15 dependencies = too many responsibilities! public class LicensePlateAppService : ApplicationService { public LicensePlateAppService ( IRepository < LicensePlate , Guid

licensePlateRepository , IRepository < LicensePlateWithoutTag , Guid

licensePlateWithoutTagRepository , IRepository < ASN , Guid

asnRepository , IRepository < Project , Guid

projectRepository , IRepository < Tag , Guid

tagRepository , IRepository < SKU , Guid

skuRepository , IRepository < Customer , Guid

customerRepository , IRepository < LicensePlateHold , Guid

licensePlateHoldRepository , IRepository < LicensePlateLocation , Guid

licensePlateLocationRepository , IRepository < Location , Guid

locationRepository , IWarehouseAppService warehouseAppService , IWarehouseOwnerAppService warehouseOwnerAppService , IBlobContainer < BulkUpdateLPExcelFileContainer

fileContainer , LicensePlateService . LicensePlateServiceClient licensePlateServiceClient , CommonDependencies < LicensePlateAppService

commonDependencies ) { } } // ✅ Good: Split by responsibility public class LicensePlateAppService { } // CRUD only (~5 deps) public class LicensePlateBulkService { } // Bulk imports (~4 deps) public class LicensePlateEventPublisher { } // Events (~3 deps) Dependency Count Guidelines: Dependencies Status Action 1-5 ✅ Normal Acceptable 6-8 ⚠️ Warning Review for splitting opportunities 9+ ❌ Smell Refactor required - class has too many responsibilities Refactoring Strategies: Extract Service - Move related operations to a dedicated service Facade Pattern - Group related dependencies behind a facade Domain Events - Decouple via publish/subscribe instead of direct calls Mediator Pattern - Use MediatR to reduce direct dependencies Error Handling Don't Use throw ex // ❌ Bad - Loses stack trace catch ( Exception ex ) { logger . LogError ( ex ) ; throw ex ; // Stack trace lost! } // ✅ Good - Preserves stack trace catch ( Exception ex ) { logger . LogError ( ex ) ; throw ; // Rethrows with original stack } // ✅ Also Good - Wrap with inner exception catch ( Exception ex ) { throw new BusinessException ( "Operation failed" , ex ) ; } Don't Ignore Caught Errors // ❌ Bad - Silent swallow catch ( Exception ex ) { } // Never do this! // ✅ Good - Handle or propagate catch ( Exception ex ) { _logger . LogError ( ex , "Operation failed" ) ; throw ; // Or handle appropriately } Use Multiple Catch Blocks // ❌ Bad - Type checking in catch catch ( Exception ex ) { if ( ex is TaskCanceledException ) { / ... / } else if ( ex is TaskSchedulerException ) { / ... / } } // ✅ Good - Separate catch blocks catch ( TaskCanceledException ex ) { // Handle cancellation } catch ( TaskSchedulerException ex ) { // Handle scheduler error } Comments Avoid Positional Markers and Regions // ❌ Bad

region Scope Model Instantiation var model = new Model ( ) ;

endregion

region Action setup void Actions ( ) { }

endregion
// ✅ Good - Let code speak
var
model
=
new
Model
(
)
;
void
Actions
(
)
{
}
Don't Leave Commented Code
// ❌ Bad
DoStuff
(
)
;
// DoOtherStuff();
// DoSomeMoreStuff();
// ✅ Good - Use version control
DoStuff
(
)
;
Only Comment Business Logic Complexity
// ❌ Bad - Obvious comments
var
hash
=
0
;
// The hash
var
length
=
data
.
Length
;
// Length of string
// ✅ Good - Explains WHY, not WHAT
// Using djb2 hash for good speed/collision tradeoff
hash
=
(
(
hash
<<
5
)
-
hash
)
+
character
;
Quick Reference Checklist
Code Review Checklist
Naming
Meaningful, pronounceable, no Hungarian
Functions
Single responsibility, <3 args, no flags
Variables
No magic strings, early returns, no nesting >2
SOLID
Interfaces over concrete, small focused classes
Dependencies
Constructor has <8 dependencies (SRP indicator)
Error Handling
No
throw ex
, no silent catch, specific exception types
Comments
No regions, no dead code, explains WHY
References
references/solid-principles.md
Full SOLID examples
references/async-patterns.md
Async/await guidelines
references/editorconfig-template.md
.editorconfig template Source : clean-code-dotnet
返回排行榜