The Agreed Static Code Analysis Rule Set: Production vs. Non-Production
How a cross-team rule set for .NET static code analysis splits responsibilities between Microsoft's analyzers and StyleCop, and why production and non-production code get deliberately different strictness levels.
Static code analysis rules have an obvious failure mode: applied uniformly and strictly everywhere, they slow down exactly the code — tests, prototypes, throwaway tooling — where speed and readability matter more than long-term rigor. Applied too loosely, they let real problems slip into code that customers actually depend on. A rule set agreed by a cross-team Community of Practice (CoP) addresses this with one central design decision: production and non-production code are governed by explicitly different standards, on purpose.
The goal isn’t perfection — it’s consistency
The rule set exists to keep repositories consistent with each other, not to chase some theoretically ideal configuration. Three things are being balanced simultaneously: code quality and long-term maintainability, developer productivity, and practicality in tests, tooling, and experiments. Optimizing purely for the first at the expense of the other two tends to produce a rule set nobody actually follows.
Scope
The rule set applies to all new .NET source code repositories, and to existing repositories as they migrate to the modern static analysis setup. It covers rules enforced through Roslyn analyzers and .editorconfig configuration.
The guiding principle: different strictness by code category
Production code must be strict. This covers application logic, libraries and shared components, services, APIs, background jobs — anything long-living, customer-relevant, or security-critical. This is the code where rigor pays for itself.
Non-production code may be pragmatic. Unit, integration, and system tests; test utilities and mocks; prototypes, spikes, and playground code; tooling and scripts; sample or reference implementations. Here, readability, speed, and clarity of intent matter more than the full weight of production-grade rules.
This isn’t a loophole — it’s a deliberate acknowledgment that the same rule can be right in one context and actively counterproductive in another. A rule enforcing exhaustive XML documentation comments, for instance, is valuable on a public API and mostly noise on a throwaway spike.
How the analysis responsibilities are split
Code quality is enforced by Microsoft’s own first-party analyzers, covering correctness and reliability, language and runtime best practices, nullability and API usage, performance and threading guidance, and security-relevant patterns. The rationale: these analyzers are tightly integrated with the compiler and evolve in lockstep with the language itself, giving them a high signal-to-noise ratio and making them the authoritative source for fundamental code quality.
Code style is enforced separately, through the StyleCop Analyzers project, covering naming conventions, layout and formatting, documentation and XML comments, and general readability and consistency. Style is inherently more opinionated than correctness, and StyleCop provides a well-established, community-understood rule set that can be tuned to a team’s exact conventions without touching the compiler-correctness rules Microsoft’s analyzers own.
Splitting these two concerns across two analyzer sets keeps each one focused: one authoritative source for “is this code correct,” a separate, tunable source for “does this code look the way we’ve agreed it should.”
Centralizing configuration in Directory.Build.props
Analyzer incorporation and configuration live in a single Directory.Build.props file — referencing analyzer packages, enabling or disabling analyzer sets, and applying them consistently across every project in a repository.
The payoff of centralizing this in one place:
- A single source of truth for how analysis is configured
- No per-project duplication or drift between projects that are supposed to follow the same rules
- Consistent behavior across every solution in the repository
- Simple onboarding — new projects inherit the configuration automatically
- Individual project files stay lean, while rule behavior is governed transparently from one location
See the companion post on wiring up static analysis via Directory.Build.props for what that file actually looks like in practice.
The reference templates
Three files anchor the whole setup:
.editorconfig— the central configuration file consumed by analyzers, the IDE, and other tooling alike.Directory.Build.props— the MSBuild configuration that actually incorporates the analyzers..stylecop.json— handles StyleCop-specific configuration options that don’t fit.editorconfig’s INI-style format.
The takeaway
The rule set’s real innovation isn’t any individual rule — it’s the explicit, upfront acknowledgment that production and non-production code deserve different levels of strictness, paired with a clean division of labor between correctness (Microsoft analyzers) and style (StyleCop), all wired up from one centralized location instead of scattered project-by-project. That combination is what makes “consistent across many repositories” achievable instead of aspirational.