Skip to content

Alle eingebauten Regeln

Komplette Liste der mitgelieferten Regeln, gruppiert nach Kategorie. Beim Build aus samples/rules/*.cgr erzeugt, die Seite niemals direkt bearbeiten.

CodeCharter liefert 125 Regeln in 4 Kategorien aus. Jede Regel ist als eigene .cgr-Datei unter samples/rules/ deklariert und kann von eurem eigenen Regelpaket überschrieben oder deaktiviert werden.

Die Tabelle wird beim Build automatisch aus den deklarierten Direktiven (@name, @severity, @category, @description, @recommendation) erzeugt. Wenn die Liste hier von dem abweicht, was im CLI ankommt, ist das ein Bug, bitte melden.

Hinweis: Die Kurzbeschreibungen der eingebauten Regeln werden bewusst auf Englisch gepflegt. Sie stammen unverändert aus den @description-Direktiven der Regeldateien und werden nicht übersetzt, damit die Tabelle bei jeder Neugenerierung mit der Ausgabe der CLI übereinstimmt.

Allgemein

Regel Severity Kurzbeschreibung
Abstract class not suffixed with Base info Naming consistency: an abstract class signals its role as a base type through its name. When that signal is absent, callers cannot distinguish a design contract from a concrete implementation at a glance, making the hierarchy harder to navigate and extend.
Abstract class without abstract members warn Abstraction without a contract: an abstract class that declares no abstract methods or properties defines nothing that subclasses must implement, making the abstraction hollow. Subclasses inherit shared behavior but are given no template — the class acts as a concrete base that happens to be un-instantiable, which misleads readers about its design intent.
Async method missing Async suffix warn The TAP naming convention requires every asynchronous method — whether declared with the async keyword or returning Task/ValueTask directly — to end with the Async suffix. Without it, callers cannot distinguish blocking from non-blocking methods by name alone, which leads to accidental synchronous use and broken composition in async call chains.
Async method without CancellationToken warn Cooperative cancellation: every public or protected async method, and every method returning Task or ValueTask, should accept a CancellationToken so callers can propagate cancellation through the entire call chain. Omitting it forces callers to abandon rather than cancel the operation, wasting resources and delaying shutdown.
Async void method error Swallowed failures: an async void method cannot be awaited, so any exception it throws escapes to the thread-pool's unhandled-exception handler and typically crashes the process or is silently lost — the caller has no way to observe completion or failure.
Async-suffixed method does not return an awaitable type warn Naming convention: the 'Async' suffix is a caller contract that signals the method can be awaited. A method that carries the suffix but returns a synchronous type breaks that contract, misleads callers into omitting await, and produces silent correctness errors at the call site.
Attribute class not suffixed with Attribute warn The .NET naming convention (CA1711) requires every attribute class to end with 'Attribute' so callers can reliably predict the short-form usage name and tooling can identify attribute types by name alone. A class or record that derives from System.Attribute but omits the suffix breaks this contract and causes confusion at every usage site.
Boolean method missing verb prefix info Command-query separation requires that query methods — those returning a boolean answer about state, capability, or membership — be named so the call site reads as a question. A bool-returning method without a recognised verb prefix (Is, Has, Can, Should, Are, Was, Were, Try, Check, Validate, Contains, Exists, Equals, Enable, Disable, Allow, Use, Needs, Supports) looks like a command or a noun and obscures intent, making call sites harder to read and misuse easier.
Boolean property missing verb prefix info Readable API design requires that boolean properties communicate their boolean nature through their name. A property named Active or Deleted gives callers no grammatical signal that the value is a yes/no flag; a reader must inspect the type to understand the intent. The result is code that reads as if (order.Deleted) instead of the self-documenting if (order.IsDeleted).
Calculate/Compute method returns void warn Command-query separation: a method named Calculate or Compute signals a query — it is expected to compute and return a value. A void return type breaks that contract, hiding a side effect behind a query name and making code harder to reason about.
CancellationToken parameter missing default value warn Caller ergonomics: a public API that requires an explicit CancellationToken forces every caller to construct or pass one even when no cancellation context exists, raising the barrier to correct usage. Add '= default' so the parameter is optional without removing the ability to pass a real token.
Catching System.Exception directly warn Swallowed failures: catching System.Exception is too broad and masks bugs the code was never designed to recover from — exceptions such as StackOverflowException or ThreadAbortException indicate fatal conditions and should never be silently handled alongside ordinary application errors.
Class implements too many interfaces warn Interface Segregation and Single Responsibility: a class that simultaneously honours more than five interface contracts almost always has mixed responsibilities. Each additional contract increases the blast radius of any change — altering one responsibility risks breaking callers of the others.
Class too large info A class with more than 500 lines is a signal that it has accumulated multiple responsibilities, violating the Single Responsibility Principle. Large classes are harder to test, reason about, and change safely — a modification for one concern risks breaking another.
Concrete class in deep inheritance hierarchy warn Deep inheritance hierarchies violate the principle of low coupling: a concrete class buried six or more levels below System.Object inherits state, behavior, and invariants from every ancestor, making the type hard to reason about, test in isolation, or substitute. Each additional layer multiplies the surface area of breaking changes.
Constant not in PascalCase info Consistent naming conventions make a codebase navigable and signal intent at a glance. The .NET naming guidelines (and Roslyn CA1707) require const fields to follow PascalCase — the same convention as other static members — so UPPER_SNAKE_CASE or camelCase constants stand out as broken contracts rather than deliberate choices.
Constructor has too many parameters warn Single Responsibility: a constructor with more than four real domain dependencies is a sign the class has taken on too many responsibilities. Each additional dependency is a coupling point that makes the class harder to understand, test, and change independently.
Constructor injects concrete class instead of interface warn Dependency inversion: depending on a concrete class instead of an abstraction couples the consumer to one implementation and makes it impossible to substitute a test double or alternative without changing the consuming type.
Conversion method returns void info Command-query separation: methods named Convert, Map, Transform, or ToXxx are queries — callers expect a return value. A void return means the result is silently discarded or stored as a side effect, making the naming misleading and the call sites error-prone.
Count-prefixed method does not return int info Naming contract violation: a method named Count… signals to every caller that it returns a numeric count, so returning any other type breaks the implicit contract and forces the caller to read the implementation to understand what they receive.
Create/Build method returns void info Command-Query Separation: a method named with a 'Create' or 'Build' prefix promises to produce a new object, but returning void means the constructed result is either lost or smuggled out as a side effect — breaking the naming contract and surprising callers.
Deep inheritance hierarchy info Deep inheritance couples every subclass to the full chain of ancestors, making the hierarchy fragile to change and hard to test in isolation. More than 5 levels of inheritance (matching the CA1501 threshold) is a strong signal that behaviour should be shared via composition rather than stacking base classes.
Deep nesting info Single Responsibility: a method whose nesting depth exceeds 4 is doing too much at once — each additional level encodes another sub-decision that belongs in its own method or guard clause. The result is code that is hard to read, hard to test, and fragile to change.
Direct DateTime/DateTimeOffset usage instead of TimeProvider warn Testability through dependency inversion: hard-coding the clock via DateTime.Now/UtcNow/Today or DateTimeOffset.Now/UtcNow couples the call site to the system clock, making time-sensitive logic impossible to test deterministically. Inject System.TimeProvider as an abstraction instead. Only the static BCL members are flagged; reading Now/UtcNow/Today off an injected abstraction (e.g. an IClock field) is the recommended pattern and is not flagged.
Direct instantiation in constructor or field initializer warn Dependency inversion: hard-coding 'new ConcreteType()' inside a constructor or field initializer binds the class to one specific implementation, making it impossible to substitute a test double or an alternative without modifying the class itself.
Documented method has undocumented parameter info Incomplete API contracts erode trust in documentation: a method that carries a but omits tags for one or more parameters signals to callers that the docs cannot be relied upon. Partial documentation is often worse than none, because it creates a false sense of completeness.
Empty catch block error Swallowed failures: an empty catch turns a runtime failure into silence — a bug that should surface immediately becomes invisible data corruption or a confusing error far from its true cause.
Empty interface info Interface segregation requires that an interface define a real contract. An interface with no methods, properties, or events conveys no contract and is likely a marker interface or a design accident — consumers cannot depend on it meaningfully, and it makes intent invisible to readers.
Exception class not suffixed with Exception warn By convention (CA1710), every class in the exception hierarchy must end its name with 'Exception' so callers can instantly identify throwable types without reading the inheritance chain. A name like 'NotFound' or 'Unauthorized' is indistinguishable from an ordinary domain object until the base type is checked.
Explicit type when var is obvious info Redundant type repetition: when the right-hand side of a local variable declaration already makes the type unambiguous — a constructor call, a cast, or a type-named factory — restating the type on the left is noise that adds no information and obscures the intent of the code (IDE0007). Code clarity is served best when each piece of information appears exactly once.
Field name too long info Readability and cohesion: a field name longer than 30 characters is a signal that the name is compensating for an overly broad concept or a missing abstraction, making the surrounding code harder to scan and maintain.
Find-prefixed method returns void info Command-Query Separation: a method named Find or Search signals a query — the caller expects a result back. Returning void means any located item is silently discarded or stored as a hidden side effect, breaking the naming contract and making intent opaque to every reader.
Fire-and-forget async call error Swallowed failures: discarding a Task without awaiting it, assigning it, or returning it silently absorbs every exception the operation may throw, giving the caller no way to observe failure or guarantee ordering.
Get-prefixed method returns void warn Command-Query Separation: a method named Get... signals a query that returns a value; returning void turns it into a command, breaking the contract implied by the name and making callers look for a return value that does not exist.
God class warn The Single Responsibility Principle (SRP) requires that a class has exactly one reason to change. A class exceeding 1000 lines of code and 30 methods has clearly taken on multiple responsibilities, making it hard to understand, test, and evolve without unintended side effects.
High afferent coupling info Coupling: a type with more than 30 in-solution dependents is a high-stakes stability anchor — every signature change cascades to all consumers, and a volatile implementation here raises the cost of the entire codebase.
High cognitive complexity warn Readability and maintainability degrade sharply when a method's control flow is too tangled to follow in a single reading. Cognitive complexity (SonarSource S3776) scores methods by counting and weighting control-flow breaks, with additional weight for every level of nesting, so a deeply nested branch costs far more than a flat one. A score above 15 indicates a method that is difficult to reason about, review, and safely change.
High cyclomatic complexity warn Single Responsibility: a method with cyclomatic complexity above 15 is doing too many things — each independent branch adds a path that must be tested separately, making the method hard to understand, maintain, and cover with tests.
High efferent coupling info High efferent coupling is a sign that a type violates the Single Responsibility Principle: it knows about too many other types, which makes it hard to test in isolation and expensive to change when any of those dependencies evolve.
High response for class warn A high Response For Class (RFC) metric is a coupling and cohesion signal: the class touches too many distinct methods — its own plus every distinct external method its own methods invoke — making it hard to test in isolation and risky to change because side-effects fan out across many collaborators.
High weighted methods per class warn Low cohesion and SRP violation: when the sum of cyclomatic complexity across all methods (WMC) exceeds 50, the class has accumulated too many decision paths, making it a maintenance burden and a sign that multiple independent responsibilities have been merged into one type.
Interface not prefixed with I warn Naming consistency: the established C# convention (CA1715) requires interface names to start with 'I' so that callers can instantly distinguish a contract from a concrete type. Violating this convention breaks the widely-shared mental model of .NET codebases and makes it harder to discover which types are injectable abstractions.
Internal/Impl method should not be public warn Encapsulation: a method whose name ends with 'Internal' or 'Impl' signals an implementation detail. Exposing it as public leaks internals into the API surface and invites callers to depend on behaviour that was never meant to be contracted.
Large enum info Low cohesion: an enum with more than 25 members has grown beyond a single well-bounded concept, making it harder to reason about, document, and evolve without unintended coupling across unrelated callers.
Large void method info Single Responsibility: a void method that has grown large is accumulating unrelated side effects, because it cannot communicate results to its caller through a return value and must instead operate entirely through mutations. The longer it grows, the harder it becomes to reason about what it changed and to test each concern in isolation.
Logic class without interface info Dependency inversion: a public class with significant logic but no interface couples every consumer to the concrete type, making it impossible to substitute a test double or swap the implementation via DI. The class becomes a seam that cannot be injected abstractly.
Low maintainability index warn Low cohesion and high complexity erode maintainability: when a type accumulates too many lines, too many branches, or too many distinct operations, its maintainability index — a composite of Halstead volume, cyclomatic complexity, and lines of code — drops below the point where safe modification is realistic. A score below 40 signals that the type is difficult to understand, test, and change without introducing regressions.
Magic number literal info Unnamed constants break the readability contract: a bare numeric literal forces every reader to infer its meaning from context, and a value repeated across the codebase must be hunted down whenever the business rule changes. Extracting it into a named constant makes intent explicit at the point of use and makes changes safe. Scoped to method, constructor, property-accessor, and field-initializer literals — a magic number anywhere in the type is in scope.
Method has boolean flag parameter info Single Responsibility: a boolean flag parameter is a sign the method does two different things depending on the value, violating the principle that a method should have one job. Call sites become unreadable (e.g. Process(data, true, false)) because the meaning of the argument is invisible without looking up the signature.
Method name too long info Cohesion: a method name longer than 30 characters is usually a sign the method does more than one thing, or that several responsibilities have not been separated into focused collaborators. Long names make call sites harder to read and suggest the abstraction is missing.
Method not in PascalCase warn Consistent naming conventions are a readability contract: a method starting with a lowercase letter breaks the .NET PascalCase convention, signalling to readers that the codebase may have been ported from Java or JavaScript without adaptation. Tooling such as Roslyn naming rules and StyleCop flags the same issue at Warning level.
Method too large warn Single Responsibility Principle: a method exceeding 80 lines almost always does more than one thing, making it hard to name, test in isolation, and understand without scrolling. Long methods accumulate multiple responsibilities that each deserve their own, focused unit.
Missing guard clause / early return info Fail-fast / readability: wrapping a method's entire body in an if-statement adds an unnecessary nesting level and pushes the happy path to the right. Inverting the condition and returning early at the top (a guard clause) keeps the body flat and makes the intent — 'exit immediately when the precondition is not met' — explicit.
Mutable struct warn Immutability: structs are value types and are copied on every assignment, so mutating a field on a local copy silently leaves the original unchanged — a classic source of hard-to-trace bugs. A struct whose instance fields can be written after construction violates the immutability contract that value-type semantics imply.
Mutually dependent types warn Tight coupling through a bilateral dependency violates the single-responsibility and dependency-inversion principles: when two types each reference the other, neither can be understood, tested, or reused without pulling in the other, and any change to either ripples into both.
Namespace far from main sequence info Stable abstractions principle: a namespace should balance abstractness (ratio of abstract types) with instability (ratio of outgoing to total dependencies). A high distance from the main sequence (|Abstractness + Instability - 1| > 0.7) signals either the zone of pain (stable + concrete, hard to change) or the zone of uselessness (unstable + abstract, unused scaffolding).
Non-public unsealed class with no derived types info Encapsulation: a non-public class that is never subclassed should be sealed to signal that inheritance is not part of its contract. Without 'sealed', readers cannot tell whether the open door is intentional design or an oversight, and the JIT cannot apply devirtualization.
Non-readonly static field warn Shared mutable state: a mutable static field is readable and writable by every thread simultaneously, making it a hidden coupling point between otherwise independent code paths and a persistent source of data races and non-deterministic behaviour.
Null check uses == instead of pattern matching info Operator-overloading safety: equality operators (== / !=) can be overloaded, so '== null' and '!= null' may invoke custom logic rather than a true reference test. Pattern matching ('is null' / 'is not null') is immune to overloading and expresses the intent of a reference test unambiguously — it is the idiomatic C# 8+ form recommended by IDE0150.
Override method missing inheritdoc info Documentation inheritance: an override that carries no XML doc comment breaks the contract that callers can rely on IntelliSense-level documentation without having to navigate to the base declaration. Using fulfils that contract with one line.
Parameter not in camelCase warn Naming consistency: a parameter that starts with an uppercase letter breaks the .NET convention for locals and parameters, making it visually indistinguishable from a property or type name at the call site and degrading readability across the codebase.
Parse method returns void info Command-Query Separation: a method named ParseXxx promises to return the parsed value, but a void return type either silently discards it or stores it as a side-effect, breaking the naming contract and making the method harder to compose and test.
Primitive type in logic class constructor warn Dependency inversion requires that logic classes receive their configuration through typed abstractions, not raw primitives. A public constructor that accepts a string, int, or bool cannot be registered in a DI container without a manual factory, and it couples the class directly to configuration concerns that belong in an options object.
Private field missing underscore prefix warn Consistent field naming (IDE1006 / _camelCase convention): private instance fields that do not follow the _camelCase pattern are indistinguishable from local variables and parameters at a glance, increasing the chance of accidental shadowing and making reading intent harder in non-trivial methods.
Property not in PascalCase warn C# naming guidelines (CA1507/IDE1006) require properties to use PascalCase, so callers can immediately distinguish them from local variables and parameters at the call site. A lowercase-initial property erodes that convention and generates IDE warnings across every consumer.
Public member missing XML documentation info API contract clarity requires that every public surface carries an XML documentation comment. Without it, consumers lose IntelliSense guidance, generated API docs have gaps, and CS1591 warnings accumulate when the compiler's documentation-output switch is enabled. Fires once per undocumented public type, method, or property (not once per type), so a class with three undocumented public methods produces three findings.
Public method uses ref or out parameter warn API surface design: ref and out parameters expose implementation-level calling conventions in a public contract, coupling callers to mutation patterns that cannot be used with async/await, LINQ, or expression trees, and that complicate every call site. The idiomatic .NET alternative — returning a result record or tuple — expresses the same intent without these constraints.
Public method uses Tuple in signature warn Encapsulation: exposing a raw tuple in a public API leaks untyped structural detail — callers must know element positions or rely on fragile member names that disappear at the call site. Replace the tuple with a named record so the contract is self-documenting and refactorable.
Public mutable field warn Encapsulation: a public mutable field exposes internal state directly, so the type cannot enforce its invariants or change its storage representation without breaking every caller. Adding validation, change notification, or computed access later becomes a breaking API change.
Public nested type info Encapsulation: a public nested type leaks the internal structure of its enclosing type into the public API, making the nested type hard to discover, hard to reference, and tightly coupled to its container. Consumers must know the outer type exists before they can use the inner one.
Record has public methods info Single Responsibility: a record is a data carrier — its role is to hold and transport values, not to execute domain logic. Public methods on a record pull behaviour into the data type, coupling callers to implementation details and making the logic harder to test or reuse independently.
Record input parameter has wrong suffix info Communicative naming: a record type accepted as a method parameter should carry a role suffix (Command, Query, Request, etc.) so that the method's intent is self-documenting at the call site. A bare domain-object name like OrderData leaves readers guessing whether the operation is a mutation, a read, or something else entirely.
Record return type has wrong suffix info Communicating intent through naming: a record type returned from a public method carries no meaning about its role in the design unless its name reflects that role. Without a recognized suffix, readers cannot tell whether the type is a command outcome, a data-transfer object, an API response, or a query projection — they must read the implementation to understand it.
Rethrow loses the original stack trace error Stack trace integrity: rethrowing a caught exception by name ('throw ex;') resets the stack trace to the rethrow site, so every log entry and debugger callstack points to the wrong location and the true origin of the fault is lost.
Sealed class with protected members warn Encapsulation: protected access implies derivability, but a sealed class can never be subclassed, so every non-override protected member — method, property, or field — is permanently unreachable by any derived type. This creates a false signal that the type was designed for inheritance, misleading readers and reviewers.
Static class has public non-extension methods info Cohesion / dependency inversion: a public static class whose public methods are not extension methods is a hidden service — it couples every caller directly to the implementation with no seam for testing or substitution. Static utility behaviour that cannot be expressed as an extension method belongs behind an interface.
Static class with too many methods warn SRP: a static class with more than 15 methods has accumulated too many responsibilities. Because static classes cannot be injected or substituted, every caller is tightly coupled to the entire class, making the design hard to test and evolve.
Static readonly field not in PascalCase warn Consistent naming conventions are a readability contract: non-private static readonly fields are part of a type's public surface and must follow PascalCase, the .NET Framework Design Guidelines convention for all non-private members. A field that uses UPPER_SNAKE_CASE or camelCase signals a C or Java heritage and misleads readers about the field's accessibility and intent.
String concatenation with + operator info Allocation efficiency: each + concatenation on strings allocates a new intermediate string object, so chaining multiple + expressions in a method body produces O(n) allocations that a single interpolated string or StringBuilder avoids. In loops or hot paths this degrades throughput; even in ordinary methods it adds unnecessary GC pressure.
Too many local variables info Single Responsibility: a method with more than 10 local variables is carrying too many concerns — it mixes multiple logical steps in one body, making it hard to read, test, and refactor without unintended side-effects.
Too many overloads info A proliferating overload set is a cohesion smell: each variant usually encodes a distinct configuration concern that belongs in a dedicated type or builder, not in a growing list of signatures. More than six overloads of the same method name makes the API hard to discover and the type hard to maintain.
Too many parameters warn Single Responsibility: a method with more than five non-infrastructure parameters has typically taken on too many responsibilities, or several parameters travel together and belong in their own type. Both problems reduce readability and make call sites brittle.
Too many public methods info A large public API surface is a sign that the Single Responsibility Principle is violated: the type has accumulated too many distinct concerns, making it harder to learn, test, and evolve without breaking callers.
Try-prefixed method does not return bool warn Convention contract: the Try-prefix establishes a well-known caller contract — the method signals success or failure via a bool return, with the result in an out parameter. A Try method that returns anything else breaks that contract and surprises every caller who has to inspect the actual return type to understand what the method means.
Type name starts with lowercase warn PascalCase is the .NET naming contract for all type declarations (classes, structs, interfaces, records, enums), as codified in CA1709. A type whose name begins with a lowercase letter is visually indistinguishable from a local variable at the use site, undermining readability and signalling that the codebase was likely ported from a language with different conventions.
Type name too long info Single Responsibility Principle: a type name longer than 40 characters is a strong signal that the type carries multiple responsibilities. When a name must enumerate several concerns to stay accurate, the type itself is doing too much.
Unstable highly-coupled type info The stable-dependency principle states that a heavily used type must be stable, because every change to it ripples through all its consumers. When a type is both widely depended on (high afferent coupling) and itself depends on many others (high efferent coupling, Instability > 0.8), it becomes a high-risk coupling point: one upstream change can cascade through the entire codebase.
Untracked TODO or FIXME comment info Inline TODO, FIXME, HACK, and UNDONE markers are a form of deferred-work debt: they are invisible to project-management tooling, easy to forget, and accumulate silently over time. The result is technical debt that never appears in a backlog and is never scheduled for resolution.
Unused method parameter info Dead code in a method signature violates the principle of minimal interface: a parameter that is never read misleads callers about the method's actual dependencies, inflates the public contract, and often signals an incomplete implementation or a forgotten refactoring.
Unused using directive info Dependency clarity: every using directive is a visible claim that the file depends on that namespace. An unused directive makes the actual dependency surface ambiguous and adds noise that slows code review.
Wide type hierarchy info Cohesion and the Open/Closed Principle: a type with more than 10 total derived types (direct and indirect) has become a broad extension point — each new subtype is a reason to reason about every sibling, making the hierarchy hard to extend safely and difficult to test in isolation.

ASP.NET Core

Regel Severity Kurzbeschreibung
API controller missing [ApiController] attribute warn Convention over configuration: the [ApiController] attribute is how ASP.NET Core knows a controller is an API endpoint, enabling automatic model-state validation, binding-source inference, and ProblemDetails error responses. A controller that inherits ControllerBase without [ApiController] silently opts out of these behaviors, causing inconsistent validation and opaque 400 responses.
Controller action contains too much logic warn Single Responsibility Principle: a controller action that exceeds 20 lines is doing work that belongs in the service layer. Actions mixing business logic with HTTP concerns are harder to test, reuse, and reason about.
Controller action missing HTTP verb attribute warn Explicit contract: every public method on a controller is treated as an action endpoint unless opted out, so an unmarked public method is an implicit, ambiguously-routed action that ASP.NET Core may expose in unexpected ways or fail to route at all.
Controller class not suffixed with Controller warn Naming conventions as a discovery contract: ASP.NET Core's default routing infrastructure discovers controllers by the 'Controller' suffix, so a class that inherits from ControllerBase or Controller but omits the suffix will be silently excluded from routing and its endpoints will return 404 in production.
Controller has too many actions warn Single Responsibility: a controller with more than 10 public action methods has taken on too many concerns, making routing, testing, and maintenance progressively harder as the surface grows.
Controller missing [Route] attribute warn Explicit routing (attribute routing) decouples a controller's URL contract from its class name. Without [Route] on the class, ASP.NET Core falls back to convention-based routing, so renaming the controller silently breaks all existing URLs and bookmarks.

Verbotene Suffixe

Regel Severity Kurzbeschreibung
Avoid 'Helper' class suffix info Cohesion: a class named 'Helper' has no inherent focus, so it accumulates unrelated utility methods over time and becomes a grab-bag that violates Single Responsibility. The name signals nothing about what the class does or whom it serves.
Avoid 'Manager' class suffix info Single Responsibility: the suffix 'Manager' is too vague to communicate one clear responsibility, so these classes habitually accumulate unrelated concerns and grow into God objects. A name that cannot be described in a single focused noun is a warning sign that the type is already doing too much.
Avoid 'Processor' class suffix info Cohesion through naming: the suffix 'Processor' is too generic to convey a type's single responsibility — it gives no indication whether the class reads, transforms, writes, or orchestrates data, making the codebase harder to navigate and reason about.
Avoid 'Utils' or 'Utility' class suffix info Low cohesion: a class named 'Utils', 'Utility', or 'Utilities' is a grab-bag of unrelated helpers with no single responsibility, making the type hard to discover, test, and evolve independently.

Contracts

Regel Severity Kurzbeschreibung
Builder class missing Build method warn The Builder pattern requires a terminal Build() or BuildAsync() method that completes and returns the constructed object — without it, the class exposes an incomplete contract and callers have no way to retrieve the result. A *Builder suffix signals a clear intent; a missing Build method breaks that promise and makes the type unusable as a builder.
Class with Build method missing Builder suffix info Cohesion principle: a class whose public API includes a method named Build is advertising the Builder pattern, but a name that does not end in 'Builder' breaks the convention and makes the responsibility harder to discover. Readers scanning a namespace must open the class to understand its role.
Class with Convert method missing Converter suffix info Cohesion: a class that exposes a public Convert method signals a conversion responsibility, but a name that omits the 'Converter' suffix hides that intent — callers cannot tell from the type name alone what the class does.
Class with Execute method missing action-pattern suffix info Naming cohesion: a class that exposes a public Execute or ExecuteAsync method is fulfilling an action-pattern role, so its name should declare that role. A name like ReportProcessor or BackgroundWorker hides the intent; a name like ReportCommand or CleanupJob makes the responsibility self-evident.
Class with Format method missing Formatter suffix info Cohesion and discoverability: a concrete class that owns a public Format method has taken on a formatting responsibility, and that responsibility should be visible in its name. A class named InvoiceRenderer or OutputHelper that formats data forces callers to discover the capability by reading its members rather than its name, weakening navigability and making it harder to find all formatters in a codebase.
Class with Handle method missing Handler suffix warn Cohesion and naming consistency: a class that owns a public Handle or HandleAsync method is by definition a handler, and its name should reflect that responsibility. Mismatches between structure and name make the codebase harder to navigate and break the CQRS/MediatR convention that lets developers locate handler logic by name alone.
Class with instance Parse method missing Parser suffix info Single Responsibility: a class that exposes a public instance Parse or TryParse method has taken on a dedicated parsing responsibility, and its name should make that explicit. Without the 'Parser' suffix the responsibility is hidden, making the class harder to discover and understand.
Class with only Create methods missing Factory suffix info Cohesion: a concrete class whose entire public surface consists of Create* methods is a factory in all but name. Leaving it unnamed as such hides its responsibility and misleads readers into thinking the class has a broader remit.
Class with Resolve method missing Resolver suffix info Cohesion and discoverability: a class that exposes a public Resolve or TryResolve method declares a resolution contract, but without the 'Resolver' suffix that contract is invisible at a glance. Callers must inspect the type to discover its role, and search-by-convention ('find all resolvers') silently misses it.
Class with Serialize method missing Serializer suffix info Cohesion: a class that exposes a public Serialize, Deserialize, SerializeAsync, or DeserializeAsync method has taken on a serialization responsibility, and its name should reflect that. A type whose name does not end with 'Serializer' hides its real role, making the codebase harder to navigate and understand.
Class with Validate method missing Validator suffix info Cohesion: a class whose primary responsibility is validation should make that responsibility visible in its name. A public Validate method is a strong signal that the class is a dedicated validator; hiding that behind a generic name like InputChecker or Handler obscures intent and makes the type harder to discover, test, and replace.
Command class missing Execute method warn Command-query separation requires every concrete command object to expose a well-known execution entry point. A class named *Command that declares no public Execute, ExecuteAsync, or CanExecute method breaks the contract implicitly expected by callers and command-bus infrastructure, making the type unusable without reading its source.
Converter class missing Convert method warn Cohesion by naming contract: a class named *Converter advertises a conversion responsibility, so callers expect a discoverable entry point — Convert, Read, or Write. A class that carries the name but omits the method breaks the implicit contract, making the type's purpose opaque and forcing callers to inspect the implementation.
Factory class missing Create method warn Cohesion contract: a type named Factory signals that its sole responsibility is object construction, but without a public Create method that contract is invisible to callers. Consumers cannot use the factory polymorphically and the naming convention loses its meaning.
Formatter class missing Format method warn Cohesion/naming contract: a class named 'Formatter' promises callers a formatting capability, but without a public or internal Format, Write, or WriteAsync method that promise is hollow — consumers have no entry point to invoke.
Handler class missing Handle method warn Behavioral contract: a class named *Handler advertises a handling responsibility but exposes no callable entry point, breaking the implicit contract consumers depend on. Any caller resolving the handler by name or type cannot dispatch to it.
Method name repeats class suffix info Cohesion and information hiding: when a class name already encodes its role (e.g. PropertyValidator), repeating that role in every method name (ValidateProperty, ValidateData) adds noise without adding meaning — the enclosing type is always in scope. Callers read PropertyValidator.Validate(), not PropertyValidator.ValidateProperty(), which is redundant.
Parser class missing Parse method warn Explicit contracts — a class named *Parser must expose a public Parse, TryParse, or ParseFrom method so callers can locate the entry point without inspecting the implementation. Without a discoverable parse method the type's role is unclear, and consumers are forced to rely on implementation details rather than a declared interface.
Provider class has write methods info Single Responsibility and command-query separation: a Provider is a read-only data source, not a repository. When a Provider class exposes public write methods (Add, Set, Update, Delete, Remove, Insert) it mixes querying and mutation, making callers depend on a type that does more than its name promises.
Repository class missing CRUD methods info Contract cohesion: a class named Repository advertises a data-access role but exposes no standard CRUD surface (Get*, Find*, Add*, Create*, Update*, Delete*, Remove*). Callers cannot rely on a predictable contract, and the naming becomes misleading noise rather than intent.
Resolver class missing Resolve method warn Naming convention as contract: a class whose name ends with 'Resolver' implies a resolution contract, but without a Resolve or TryResolve method there is nothing for callers to depend on — the name is a promise the type does not keep.
Serializer class missing Serialize/SerializeAsync method warn Explicit contract: a class named *Serializer that exposes no public Serialize or SerializeAsync method breaks the implicit naming contract, forcing callers to discover the real API through documentation or source inspection rather than the type name. This erodes cohesion and makes the codebase harder to navigate.
Specific parser exposes ParseFrom methods warn Cohesion: a parser class whose name already encodes the source medium (e.g. JsonStreamTokenParser — three or more CamelCase word-segments before Parser) must not also expose ParseFrom* methods. The overly specific name and the source-routing methods duplicate the same intent, spreading responsibility across two conventions at once.
Validator class missing validation method warn Naming cohesion: a class named Validator advertises a validation contract, but without a public Validate or IsValid* method that contract is invisible to callers. Consumers cannot discover or invoke the validation logic through a predictable interface, breaking the implicit protocol the name establishes.