Jedes Beispiel ist eine komplette .ccr-Datei. Kopiert was ihr braucht,
passt die Schwellen oder Strings an und committet es in
.codecharter/rules/ eures Repos.
Async
Async-Methode ohne Async-Suffix
@name "Async method missing Async suffix"
@severity warn
@category "Async"
@description "Async methods should end with 'Async' so callers spot await sites"
@recommendation "Rename Foo to FooAsync when the method returns Task or ValueTask"
from m in Methods
where m.IsAsync
where !m.Name.EndsWith("Async")
select m
Public-Async ohne CancellationToken
@name "Public async method missing CancellationToken"
@severity warn
@category "Async"
@description "Public async APIs should accept a CancellationToken so callers can cancel"
@recommendation "Add CancellationToken parameter with default value"
from m in Methods
where m.IsAsync
where m.AccessModifier == "Public"
where !m.Parameters.Any(p => p.TypeShortName == "CancellationToken")
select m
Fire-and-forget Async
@name "Async call not awaited"
@severity error
@category "Async"
@description "Calling an async method without awaiting silently drops exceptions"
@recommendation "Await the result, or assign to '_ = ...' if discard is intentional"
from m in Methods
where m.SyntaxIssues.Any(i => i.Kind == "FireAndForgetAsync")
select m
Error Handling
Leerer Catch-Block
@name "Empty catch block"
@severity error
@category "ErrorHandling"
@description "Empty catch silently swallows exceptions"
@recommendation "Log and rethrow, or catch the specific exception you can recover from"
from m in Methods
where m.SyntaxIssues.Any(i => i.Kind == "EmptyCatch")
select m
Generic Exception-Catch ohne Rethrow
@name "Generic exception caught without rethrow"
@severity warn
@category "ErrorHandling"
@description "Catching Exception swallows everything, including bugs"
@recommendation "Catch the narrowest exception type the caller can recover from"
from m in Methods
where m.SyntaxIssues.Any(i => i.Kind == "GenericExceptionCatch")
select m
Design
Konstruktor mit zu vielen Parametern
@name "Constructor with too many parameters"
@severity warn
@category "Design"
@description "Constructors with 5+ parameters usually indicate too many responsibilities"
@recommendation "Split the class or use a parameter object"
from m in Methods
where m.IsConstructor
where m.NumberOfParameters > 4
select m
Klasse zu groß
@name "Class too large"
@severity warn
@category "Design"
@description "Classes over 500 lines tend to mix responsibilities"
@recommendation "Extract collaborators or split by responsibility"
from t in Types
where t.Kind == "Class"
where t.LinesOfCode > 500
select t
Static-Klasse mit nicht-Extension public Methoden
@name "Static class has public non-extension methods"
@severity warn
@category "Design"
@description "Static utility classes should host extension methods only"
@recommendation "Convert to instance methods on a real type, or mark the parameter with 'this'"
from t in Types
where t.IsStatic
where t.Kind == "Class"
where t.Methods.Any(m => m.AccessModifier == "Public" && !m.IsExtensionMethod)
select t
Naming
Boolean-Property ohne Verb-Präfix
@name "Boolean property missing verb prefix"
@severity warn
@category "Naming"
@description "Booleans should be readable as questions: Is, Has, Can, Should, Enable, Disable"
@recommendation "Prefix the property to convey the state it represents"
from p in Properties
where p.TypeShortName == "Boolean" || p.TypeShortName == "bool"
where !p.Name.StartsWith("Is") && !p.Name.StartsWith("Has")
where !p.Name.StartsWith("Can") && !p.Name.StartsWith("Should")
where !p.Name.StartsWith("Enable") && !p.Name.StartsWith("Disable")
select p
Interface ohne I-Präfix
@name "Interface missing I prefix"
@severity warn
@category "Naming"
@description "Interface names should start with I, following C# convention"
@recommendation "Rename Foo to IFoo and update implementations"
from t in Types
where t.Kind == "Interface"
where !t.Name.StartsWith("I")
select t
Klasse mit "Manager"-Suffix
@name "Class named with vague Manager suffix"
@severity warn
@category "Naming"
@description "Classes called *Manager are vague: name them after what they actually do"
@recommendation "Pick a verb-based name: OrderProcessor, EmailDispatcher, PriceCalculator"
from t in Types
where t.Kind == "Class"
where t.Name.EndsWith("Manager")
select t
Determinism
Direkte DateTime-Nutzung
@name "Direct DateTime.Now / DateTime.UtcNow usage"
@severity error
@category "Determinism"
@description "Direct DateTime access makes tests non-deterministic"
@recommendation "Inject IClock and call _clock.UtcNow instead"
from m in Methods
where m.SyntaxIssues.Any(i => i.Kind == "DateTimeDirectUsage")
select m
Konstruktor ruft new auf
@name "Constructor allocates dependency directly"
@severity warn
@category "Determinism"
@description "Allocating dependencies in a constructor bypasses DI and breaks testability"
@recommendation "Inject the dependency through the constructor"
from m in Methods
where m.IsConstructor
where m.SyntaxIssues.Any(i => i.Kind == "NewInConstructor")
select m
Architecture
Domain hängt von Infrastructure ab
@name "Domain layer references Infrastructure"
@severity error
@category "Architecture"
@description "Domain layer must not depend on infrastructure concerns"
@recommendation "Move the call behind an interface in Domain that Infrastructure implements"
from t in Types
where t.Namespace.Contains(".Domain.")
where t.UsedTypes.Any(u => u.Namespace.Contains(".Infrastructure."))
select t
Controller ruft Repository direkt
@name "Controller calls Repository directly"
@severity warn
@category "Architecture"
@description "Controllers should go through the application layer, not access data directly"
@recommendation "Introduce an application service that wraps the repository call"
from t in Types
where t.Name.EndsWith("Controller")
where t.UsedTypes.Any(u => u.Name.EndsWith("Repository"))
select t
Komplexität
Methode zu lang
@name "Method too long"
@severity info
@category "Style"
@description "Methods over 60 lines are harder to read and harder to test"
@recommendation "Extract sub-routines once a method passes ~60 lines"
from m in Methods
where m.LinesOfCode > 60
select m
Hohe zyklomatische Komplexität
@name "High cyclomatic complexity"
@severity warn
@category "Style"
@description "Methods with branching depth above 10 are hard to test and reason about"
@recommendation "Extract guard clauses, replace nested ifs with early returns, or split the method"
from m in Methods
where m.CyclomaticComplexity > 10
select m
Hohe kognitive Komplexität
@name "High cognitive complexity"
@severity warn
@category "Style"
@description "Cognitive complexity above 15 indicates the method is hard for humans to follow"
@recommendation "Flatten nesting, extract intermediate variables with meaningful names"
from m in Methods
where m.CognitiveComplexity > 15
select m
Wo geht's weiter
- Erste eigene Regel: kompletter Workflow von leer bis CI
- Prädikat-Katalog: vollständige Property-Liste
- Best Practices: was eine gute Regel ausmacht