{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"},{"name":"Jendrik Brack","url":"https://daily-devops.net/authors/jendrik/"}],"description":"Recent content in Visual Studio IDE and Extensions on Daily DevOps \u0026 .NET","favicon":"https://daily-devops.net/images/logo_hu_6465d873dfa490cf.png","feed_url":"https://daily-devops.net/tags/visualstudio/feed.json","home_page_url":"https://daily-devops.net/tags/visualstudio/","icon":"https://daily-devops.net/images/logo_hu_5926de77762241ba.png","items":[{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eCode metrics have become a standard feature in modern development environments, yet their implementation and interpretation often leave much to be desired. While Visual Studio and .NET provide comprehensive code metrics analysis, the way these metrics are configured, presented, and (more critically) acted upon reveals a fundamental disconnect between measurement and meaningful improvement.\u003c/p\u003e\n\u003cp\u003eWhat code metrics actually measure, how to configure them properly, and (more importantly) why blindly following thresholds without understanding context is, frankly, a recipe for misguided refactoring efforts that waste your team\u0026rsquo;s time and actively damage your codebase.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"understanding-code-metrics-what-are-we-actually-measuring\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#understanding-code-metrics-what-are-we-actually-measuring\" title=\"Understanding Code Metrics: What Are We Actually Measuring?\"\u003eUnderstanding Code Metrics: What Are We Actually Measuring?\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eVisual Studio provides several key code metrics, each designed to quantify different aspects of code complexity and maintainability. Understanding what these numbers actually represent is essential before you start making decisions based on them.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"maintainability-index-mi\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#maintainability-index-mi\" title=\"Maintainability Index (MI)\"\u003eMaintainability Index (MI)\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe \u003cstrong\u003eMaintainability Index\u003c/strong\u003e is a composite metric ranging from 0 to 100, where higher values supposedly indicate better maintainability. Microsoft\u0026rsquo;s thresholds suggest:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eGreen (20 to 100)\u003c/strong\u003e: Good maintainability\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eYellow (10 to 19)\u003c/strong\u003e: Moderate maintainability\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRed (0 to 9)\u003c/strong\u003e: Poor maintainability\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe formula considers cyclomatic complexity, lines of code, and computational complexity. However, this single number masks important nuances. A method with a high maintainability index might still be poorly designed if it violates single responsibility principles or lacks proper abstraction. Conversely, a legitimately complex algorithm might score poorly despite being optimally implemented.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"cyclomatic-complexity\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#cyclomatic-complexity\" title=\"Cyclomatic Complexity\"\u003eCyclomatic Complexity\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis metric counts the number of linearly independent paths through a method\u0026rsquo;s code. Each \u003ccode\u003eif\u003c/code\u003e, \u003ccode\u003ewhile\u003c/code\u003e, \u003ccode\u003efor\u003c/code\u003e, \u003ccode\u003ecase\u003c/code\u003e, and logical operator (\u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e, \u003ccode\u003e||\u003c/code\u003e) increases the count. The conventional wisdom suggests:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e1 to 10\u003c/strong\u003e: Simple, low risk\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e11 to 20\u003c/strong\u003e: Moderate complexity\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e21 to 50\u003c/strong\u003e: High complexity\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e50+\u003c/strong\u003e: Untestable, critical risk\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eWhile cyclomatic complexity provides valuable insights into testability, it can be seriously misleading. A well-structured method with clear guard clauses might score higher than a convoluted method with fewer branches but objectively worse logical flow. The metric measures branches, not clarity.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"lines-of-code-loc\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#lines-of-code-loc\" title=\"Lines of Code (LOC)\"\u003eLines of Code (LOC)\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis counts executable lines, excluding comments and blank lines. While straightforward, LOC is perhaps the most misunderstood metric. \u003cstrong\u003eA high line count doesn\u0026rsquo;t automatically indicate poor quality\u003c/strong\u003e. It might represent thorough error handling, comprehensive validation, or simply necessary business logic. Splitting a 200-line method into ten 20-line methods doesn\u0026rsquo;t magically improve anything if those ten methods are tightly coupled and need to be understood together anyway.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"depth-of-inheritance\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#depth-of-inheritance\" title=\"Depth of Inheritance\"\u003eDepth of Inheritance\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis measures how many classes are in the inheritance hierarchy above a type. Deep inheritance trees can indicate over-engineering, but shallow hierarchies aren\u0026rsquo;t automatically better. The appropriate depth depends entirely on the domain model and design patterns being employed. Blindly flattening inheritance hierarchies to satisfy a metric threshold often results in awkward composition patterns or duplicated logic.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"class-coupling\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#class-coupling\" title=\"Class Coupling\"\u003eClass Coupling\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis counts the number of unique types a class references. High coupling suggests tight dependencies and reduced modularity, but some coupling is inevitable and even desirable when working with framework types or established patterns. A web controller that references request models, response models, service interfaces, and result types will naturally have higher coupling, and that\u0026rsquo;s perfectly fine.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-critical-flaw-arbitrary-thresholds-without-context\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#the-critical-flaw-arbitrary-thresholds-without-context\" title=\"The Critical Flaw: Arbitrary Thresholds Without Context\"\u003eThe Critical Flaw: Arbitrary Thresholds Without Context\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis is where the industry consistently gets it wrong. \u003cstrong\u003eApplying universal thresholds to code metrics fundamentally ignores the reality that different code serves different purposes\u003c/strong\u003e. The notion that a cyclomatic complexity of 10 is universally \u0026ldquo;good\u0026rdquo; while 11 is suddenly \u0026ldquo;problematic\u0026rdquo; is, quite honestly, nonsense. It\u0026rsquo;s the software equivalent of declaring that all methods must be exactly 15 lines long because someone once read that in a blog post.\u003c/p\u003e\n\u003cp\u003eConsider a service orchestrator that validates input, checks permissions, coordinates multiple services, handles errors, and logs operations. Such a method might legitimately have a cyclomatic complexity of 15 to 20 while being perfectly maintainable if it\u0026rsquo;s well-structured with clear sections and appropriate abstractions. In 2023, I watched a team spend two full weeks refactoring a beautifully clear order processing coordinator, splitting it into 18 micro-methods scattered across four files, all because SonarQube flagged it red. The result? Nobody on the team could follow the execution flow anymore without constantly jumping between files. The cyclomatic complexity went down. The actual maintainability went down with it.\u003c/p\u003e\n\u003cp\u003eConversely, a method with a cyclomatic complexity of 5 could be an absolute maintenance nightmare if it contains obscure bit manipulation, poorly named variables, or nested ternary operators that mask its true intent. I\u0026rsquo;ve seen plenty of \u0026ldquo;low complexity\u0026rdquo; code that nobody dares touch because figuring out what it actually does requires a whiteboard and strong coffee.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eThe metric is a signal, not a verdict.\u003c/strong\u003e Treating threshold violations as automated refactoring triggers leads to cargo cult programming. You end up splitting methods not because it actually improves design, but because a tool says a number is too high. If you\u0026rsquo;re refactoring solely to satisfy a metric, you\u0026rsquo;re doing it wrong. Full stop.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"configuring-code-metrics-analysis-in-net\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#configuring-code-metrics-analysis-in-net\" title=\"Configuring Code Metrics Analysis in .NET\"\u003eConfiguring Code Metrics Analysis in .NET\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDespite these significant limitations, code metrics remain useful when properly configured and (this is crucial) interpreted with actual human judgment. The key is setting them up as discussion triggers, not as automated quality gates. Here\u0026rsquo;s how to configure them effectively without falling into the trap of metric-driven madness.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"enabling-code-metrics-in-visual-studio\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#enabling-code-metrics-in-visual-studio\" title=\"Enabling Code Metrics in Visual Studio\"\u003eEnabling Code Metrics in Visual Studio\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCode metrics can be calculated for entire solutions, projects, or individual code files. Visual Studio makes this relatively straightforward, even if the UI hasn\u0026rsquo;t been meaningfully updated since roughly 2010.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eSolution or Project Level\u003c/strong\u003e: Right-click on the solution or project in Solution Explorer, then select \u003cstrong\u003eAnalyze and Code Cleanup\u003c/strong\u003e followed by \u003cstrong\u003eCalculate Code Metrics\u003c/strong\u003e. This gives you a basic overview, though frankly the results window is a masterclass in wasted screen real estate.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eEditorConfig Configuration\u003c/strong\u003e: For more meaningful control, use \u003ccode\u003e.editorconfig\u003c/code\u003e to configure specific metric thresholds:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Code metrics configuration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[*.cs]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Cyclomatic complexity warning threshold\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1502.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ewarning\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Maintainability index warning threshold\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1501.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ewarning\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1501.maintainability_index\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e15\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Maximum lines of code per method\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1505.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003esuggestion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1505.lines_of_code\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"the-ca1509-rule-understanding-invalid-configuration\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#the-ca1509-rule-understanding-invalid-configuration\" title=\"The CA1509 Rule: Understanding Invalid Configuration\"\u003eThe CA1509 Rule: Understanding Invalid Configuration\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eMicrosoft\u0026rsquo;s documentation on \u003cstrong\u003eCA1509\u003c/strong\u003e addresses a specific but genuinely important issue: \u003cstrong\u003einvalid analyzer configuration values\u003c/strong\u003e. This rule fires when you\u0026rsquo;ve misconfigured code analysis settings, typically by:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eProviding non-numeric values where numbers are expected\u003c/li\u003e\n\u003cli\u003eUsing values outside acceptable ranges\u003c/li\u003e\n\u003cli\u003eSpecifying invalid enumeration values\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eExample of \u003cstrong\u003einvalid configuration\u003c/strong\u003e (that will silently fail in older tooling):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# WRONG: Non-numeric value\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehigh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# WRONG: Value out of range\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e-5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# WRONG: Invalid severity level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1502.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ecritical\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eCorrect configuration:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# CORRECT: Numeric value in valid range\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# CORRECT: Valid severity level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1502.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ewarning\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe CA1509 rule exists precisely because \u003cstrong\u003esilent failures in configuration can lead to dangerously false confidence\u003c/strong\u003e. You might genuinely believe you\u0026rsquo;ve enforced strict complexity limits when, in reality, your misconfiguration has effectively disabled the checks entirely. In a previous role, our team operated for three months under the assumption that our code quality gates were being enforced. They weren\u0026rsquo;t. A single typo (\u003ccode\u003ewarnin\u003c/code\u003e instead of \u003ccode\u003ewarning\u003c/code\u003e) in the \u003ccode\u003e.editorconfig\u003c/code\u003e had neutered the entire setup. Nobody noticed until a code review caught something that should have been flagged automatically.\u003c/p\u003e\n\u003cp\u003eThis is particularly insidious in team environments where configuration files are committed to source control. A typo or misunderstanding propagates across the entire team, systematically undermining code quality initiatives without anyone noticing until much later. Usually someone eventually asks \u0026ldquo;Why isn\u0026rsquo;t this rule triggering?\u0026rdquo; and then you discover that your quality process has been theatre for weeks or months.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"project-level-configuration\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#project-level-configuration\" title=\"Project-Level Configuration\"\u003eProject-Level Configuration\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFor comprehensive control, configure code metrics in your \u003ccode\u003e.csproj\u003c/code\u003e or \u003ccode\u003eDirectory.Build.props\u003c/code\u003e file:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Enable all code analysis rules --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;EnableNETAnalyzers\u0026gt;\u003c/span\u003etrue\u003cspan class=\"nt\"\u003e\u0026lt;/EnableNETAnalyzers\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;AnalysisLevel\u0026gt;\u003c/span\u003elatest\u003cspan class=\"nt\"\u003e\u0026lt;/AnalysisLevel\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;EnforceCodeStyleInBuild\u0026gt;\u003c/span\u003etrue\u003cspan class=\"nt\"\u003e\u0026lt;/EnforceCodeStyleInBuild\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Treat specific metrics violations as errors in CI/CD --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;WarningsAsErrors\u0026gt;\u003c/span\u003eCA1502;CA1505\u003cspan class=\"nt\"\u003e\u0026lt;/WarningsAsErrors\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Add code analysis package for additional metrics --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Microsoft.CodeAnalysis.NetAnalyzers\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;8.0.0\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis configuration ensures that:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCode analysis runs during every build (not just when you remember to click \u0026ldquo;Calculate Metrics\u0026rdquo;)\u003c/li\u003e\n\u003cli\u003eSpecific violations break the build in CI/CD environments (preventing \u0026ldquo;I\u0026rsquo;ll fix it later\u0026rdquo; syndrome)\u003c/li\u003e\n\u003cli\u003eTeams maintain consistent standards across all machines (no more \u0026ldquo;it works on my machine\u0026rdquo; with different analyzer settings)\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"real-world-examples-when-metrics-mislead\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#real-world-examples-when-metrics-mislead\" title=\"Real-World Examples: When Metrics Mislead\"\u003eReal-World Examples: When Metrics Mislead\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere are some actual scenarios from production codebases where metrics painted an incomplete (or outright misleading) picture. These are real examples I\u0026rsquo;ve encountered, though I\u0026rsquo;ve simplified them slightly for clarity.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"example-1-the-high-complexity-coordinator\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#example-1-the-high-complexity-coordinator\" title=\"Example 1: The High-Complexity Coordinator\"\u003eExample 1: The High-Complexity Coordinator\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"n\"\u003eTask\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eProcessOrderAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eOrderRequest\u003c/span\u003e \u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// Cyclomatic Complexity: 18\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003eArgumentNullException\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enameof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_authService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValidateUserAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eUserId\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eUnauthorized\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eItems\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCount\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eInvalid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;No items in order\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003einventory\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_inventoryService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCheckAvailabilityAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eItems\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003einventory\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAllAvailable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOutOfStock\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einventory\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eUnavailableItems\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003epayment\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_paymentService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcessPaymentAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePayment\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003epayment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSuccess\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePaymentFailed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epayment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eReason\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRequiresShipping\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eshipping\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_shippingService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCalculateShippingAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddress\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003eshipping\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCanDeliver\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eShippingUnavailable\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eorder\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_orderRepository\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCreateOrderAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003epayment\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003einventory\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_notificationService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSendOrderConfirmationAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eorder\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderResult\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSuccess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eorder\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eId\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eMetric\u003c/strong\u003e: Cyclomatic complexity of 18\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTool Recommendation\u003c/strong\u003e: Split this method immediately into smaller methods to reduce complexity.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eReality\u003c/strong\u003e: This is a well-structured orchestration method with clear, sequential steps. Each condition represents a legitimate business rule. The flow is obvious: validate, check inventory, process payment, arrange shipping, create order. Splitting this would scatter related logic across multiple methods without improving understandability. In fact, it would make it worse because you\u0026rsquo;d need to trace through multiple method calls to understand what should be a single logical operation.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"example-2-the-deceptively-simple-method\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#example-2-the-deceptively-simple-method\" title=\"Example 2: The Deceptively Simple Method\"\u003eExample 2: The Deceptively Simple Method\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eCalculateDiscount\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCustomer\u003c/span\u003e \u003cspan class=\"n\"\u003ecustomer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eOrder\u003c/span\u003e \u003cspan class=\"n\"\u003eorder\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// Cyclomatic Complexity: 3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecustomer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTier\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Gold\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eorder\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTotal\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e20\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecustomer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTier\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Silver\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eorder\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTotal\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e500\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eMetric\u003c/strong\u003e: Cyclomatic complexity of 3\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTool Recommendation\u003c/strong\u003e: Acceptable, no action needed\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eReality\u003c/strong\u003e: This nested ternary operator is significantly harder to understand than its complexity suggests. The metric doesn\u0026rsquo;t capture cognitive load. This should be refactored into explicit if/else blocks or (better) a strategy pattern, despite having \u0026ldquo;acceptable\u0026rdquo; metrics. Low complexity doesn\u0026rsquo;t automatically mean readable code.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"example-3-the-configuration-validation\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#example-3-the-configuration-validation\" title=\"Example 3: The Configuration Validation\"\u003eExample 3: The Configuration Validation\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eValidateConfiguration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eAppConfiguration\u003c/span\u003e \u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// Cyclomatic Complexity: 25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsNullOrEmpty\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseConnection\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsNullOrEmpty\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eApiKey\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTimeout\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMaxRetries\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"p\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMaxRetries\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsNullOrEmpty\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eServiceUrl\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003eUri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTryCreate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eServiceUrl\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUriKind\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAbsolute\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003eout\u003c/span\u003e \u003cspan class=\"n\"\u003e_\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCacheSize\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"p\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCacheSize\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e10000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsNullOrEmpty\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLogPath\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWorkers\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e \u003cspan class=\"p\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWorkers\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsNullOrEmpty\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEncryptionKey\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEncryptionKey\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// ... and so on\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eMetric\u003c/strong\u003e: Cyclomatic complexity of 25+\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTool Recommendation\u003c/strong\u003e: CRITICAL! Refactor immediately! Code smell detected!\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eReality\u003c/strong\u003e: This is a guard clause pattern performing straightforward validation. Each check is independent and clear. While this could potentially be refactored to use a validation framework like FluentValidation, the current implementation is perfectly maintainable. Anyone can read this method and immediately understand what\u0026rsquo;s being validated. \u003cstrong\u003eThe high complexity reflects the number of configuration options, not poor design.\u003c/strong\u003e Refactoring this just to lower a number would likely make it more complex to understand, not less.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"best-practices-for-code-metrics-configuration\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#best-practices-for-code-metrics-configuration\" title=\"Best Practices for Code Metrics Configuration\"\u003eBest Practices for Code Metrics Configuration\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eBased on years of working with code metrics across various projects (and watching teams both succeed and fail spectacularly at using them), here are practical recommendations:\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"1-set-contextual-thresholds\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#1-set-contextual-thresholds\" title=\"1. Set Contextual Thresholds\"\u003e1. Set Contextual Thresholds\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDon\u0026rsquo;t use Microsoft\u0026rsquo;s default thresholds blindly. They were probably set by someone who never maintained a real-world enterprise application. Analyze your actual codebase and set realistic limits based on what you\u0026rsquo;re building:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[*.cs]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# More lenient for coordinators and facades\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e25\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Stricter for business logic\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[**/Domain/**.cs]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_code_quality.CA1502.cyclomatic_complexity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e15\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Most lenient for generated code\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[**/Generated/**.cs]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003edotnet_diagnostic.CA1502.severity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003enone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"2-combine-metrics-with-code-reviews\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#2-combine-metrics-with-code-reviews\" title=\"2. Combine Metrics with Code Reviews\"\u003e2. Combine Metrics with Code Reviews\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eMetrics are \u003cstrong\u003eindicators for discussion\u003c/strong\u003e, not automatic refactoring triggers. This cannot be emphasized enough. When a metric threshold is exceeded:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eReview the code with the team (not just accept what the tool says)\u003c/li\u003e\n\u003cli\u003eDiscuss whether the complexity is essential or accidental\u003c/li\u003e\n\u003cli\u003eConsider readability and maintainability alongside the numbers\u003c/li\u003e\n\u003cli\u003eRefactor only when there\u0026rsquo;s genuine consensus that it improves the code\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eIf someone suggests refactoring purely because \u0026ldquo;the metric is red,\u0026rdquo; push back. Ask them to explain what specifically is hard to understand or maintain. If they can\u0026rsquo;t articulate a concrete problem beyond \u0026ldquo;the number is high,\u0026rdquo; the refactoring probably isn\u0026rsquo;t worth doing.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"3-track-trends-not-absolutes\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#3-track-trends-not-absolutes\" title=\"3. Track Trends, Not Absolutes\"\u003e3. Track Trends, Not Absolutes\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFocus on whether metrics are improving or degrading over time, not on hitting specific numbers. A codebase where average complexity is gradually decreasing is healthier than one where you\u0026rsquo;ve arbitrarily set thresholds that everyone routinely suppresses:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- Ratchet approach: prevent regression --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;MaxAllowedCyclomaticComplexity\u0026gt;\u003c/span\u003e25\u003cspan class=\"nt\"\u003e\u0026lt;/MaxAllowedCyclomaticComplexity\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Gradually decrease this threshold over time --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"4-validate-your-configuration\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#4-validate-your-configuration\" title=\"4. Validate Your Configuration\"\u003e4. Validate Your Configuration\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEnsure your \u003ccode\u003e.editorconfig\u003c/code\u003e and project settings are actually valid and doing what you think they\u0026rsquo;re doing:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Build with warnings as errors to catch configuration issues\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edotnet build /p:TreatWarningsAsErrors\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis will cause CA1509 violations (invalid configuration) to break the build, preventing those silent failures that undermine your entire quality process.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"5-document-exceptions\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#5-document-exceptions\" title=\"5. Document Exceptions\"\u003e5. Document Exceptions\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWhen you intentionally exceed thresholds (and you will), document why. Future developers (including yourself in six months) will thank you:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Cyclomatic complexity: 22\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// JUSTIFICATION: This coordinator method orchestrates the entire checkout process.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Splitting it would scatter cohesive logic and reduce maintainability.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Reviewed: 2024-12-15, approved by architecture team.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e[SuppressMessage(\u0026#34;Microsoft.Maintainability\u0026#34;, \u0026#34;CA1502:AvoidExcessiveComplexity\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    Justification = \u0026#34;Orchestration method with clear sequential steps\u0026#34;)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"n\"\u003eTask\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCheckoutResult\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eProcessCheckoutAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCheckoutRequest\u003c/span\u003e \u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// Implementation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch2 id=\"the-bigger-picture-metrics-as-tools-not-goals\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#the-bigger-picture-metrics-as-tools-not-goals\" title=\"The Bigger Picture: Metrics as Tools, Not Goals\"\u003eThe Bigger Picture: Metrics as Tools, Not Goals\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe fundamental issue with code metrics isn\u0026rsquo;t the measurements themselves. It\u0026rsquo;s how we respond to them. \u003cstrong\u003eOptimizing for metrics rather than maintainability is a textbook case of Goodhart\u0026rsquo;s Law\u003c/strong\u003e: \u0026ldquo;When a measure becomes a target, it ceases to be a good measure.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;ve watched teams obsess over reducing cyclomatic complexity, creating elaborate abstractions and indirection that make the code objectively harder to understand, all to satisfy a tool\u0026rsquo;s threshold. I\u0026rsquo;ve seen developers split perfectly cohesive methods into multiple smaller methods that require jumping between five different files to understand the flow, all because a metric said \u0026ldquo;this is too complex.\u0026rdquo; The metric improved. The code got worse. Nobody seemed to notice the contradiction.\u003c/p\u003e\n\u003cp\u003eIn one particularly memorable case, a developer created a 200-line method that consisted entirely of calls to other private methods in the same class. Each of those methods was 10 to 15 lines and accessed the same five instance fields. The cyclomatic complexity of each individual method was beautiful. The overall design was a maintenance nightmare. But hey, the metrics dashboard was green, so management was happy.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCode metrics should inform judgment, not replace it.\u003c/strong\u003e They highlight areas that deserve scrutiny, but the decision to refactor must be based on whether the change genuinely improves the codebase. If you find yourself refactoring code that was already clear and maintainable just to lower a number, stop. You\u0026rsquo;re making things worse while convincing yourself you\u0026rsquo;re making them better.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"configuration-checklist-for-production-systems\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#configuration-checklist-for-production-systems\" title=\"Configuration Checklist for Production Systems\"\u003eConfiguration Checklist for Production Systems\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWhen setting up code metrics for a production system, ensure you:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eEnable all relevant analyzers\u003c/strong\u003e via \u003ccode\u003eEnableNETAnalyzers\u003c/code\u003e and \u003ccode\u003eAnalysisLevel\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConfigure thresholds based on your codebase\u003c/strong\u003e, not arbitrary industry standards\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eValidate configuration\u003c/strong\u003e by treating warnings as errors during CI/CD builds\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDocument your thresholds and rationale\u003c/strong\u003e in a \u003ccode\u003eCODE_METRICS.md\u003c/code\u003e file\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eReview violations as a team\u003c/strong\u003e before enforcing automatic build failures\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCreate exemptions for special cases\u003c/strong\u003e (generated code, third-party code, test data builders)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMonitor trends over time\u003c/strong\u003e rather than focusing on absolute values\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIntegrate with pull request checks\u003c/strong\u003e to catch regressions early\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eProvide training\u003c/strong\u003e to help developers understand what the metrics mean\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRevisit thresholds regularly\u003c/strong\u003e as the codebase and team mature\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"final-thoughts-measure-what-matters\"\u003e\u003ca href=\"/posts/code-metrics-configuration/#final-thoughts-measure-what-matters\" title=\"Final Thoughts: Measure What Matters\"\u003eFinal Thoughts: Measure What Matters\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eCode metrics are valuable tools when used with appropriate skepticism and contextual awareness. They can highlight potential issues, guide code reviews, and track quality trends over time. But they are \u003cstrong\u003ediagnostic tools, not prescriptive rules\u003c/strong\u003e. They tell you where to look, not what to do.\u003c/p\u003e\n\u003cp\u003eThe CA1509 rule\u0026rsquo;s existence (a rule about configuring rules correctly) is almost poetic in its meta-commentary on the complexity of modern code analysis. We\u0026rsquo;ve built elaborate systems to measure code quality, then needed additional rules to ensure we\u0026rsquo;re measuring correctly, all while the fundamental question remains: \u003cstrong\u003eAre we building software that solves real problems effectively?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eConfigure your code metrics thoughtfully. Understand what they measure and (equally important) what they don\u0026rsquo;t measure. Use them to start conversations, not end them. And above all, \u003cstrong\u003eremember that the goal is maintainable, working software, not perfectly scoring metrics.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eBecause at the end of the day, your users don\u0026rsquo;t care about your cyclomatic complexity. They care whether your software works reliably, performs well, and can be enhanced to meet their evolving needs. Code metrics can help you achieve that, but only if you resist the temptation to treat them as the goal itself.\u003c/p\u003e\n\u003cp\u003eIf you\u0026rsquo;re a developer who\u0026rsquo;s been blindly following metric thresholds, consider this your wake-up call. If you\u0026rsquo;re a team lead enforcing arbitrary complexity limits without understanding context, you\u0026rsquo;re actively harming your codebase while congratulating yourself on maintaining \u0026ldquo;quality standards.\u0026rdquo; The numbers matter, but they don\u0026rsquo;t matter more than clear, maintainable code that actually works.\u003c/p\u003e","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-11-18T17:00:00+01:00","id":"https://daily-devops.net/posts/code-metrics-configuration/","language":"en","summary":"A critical look at .NET and Visual Studio code metrics, their configuration, and why context matters infinitely more than arbitrary thresholds.","tags":["codequality","bestpractices","csharp","dotnet","visualstudio","softwareengineering"],"title":"Code Metrics and Configuration: Beyond the Numbers Game","url":"https://daily-devops.net/posts/code-metrics-configuration/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eMore than thirteen years ago, I was \u003cem\u003eforced\u003c/em\u003e by a project to switch from VB.NET to C# as my primary language. It wasn’t a change I had planned or wanted at the time. VB.NET had its quirks, but it also had a pragmatic and forgiving nature that made certain things feel\u0026hellip; effortless. Over the years, I grew to love C#: its precision, its tooling, its expressiveness. I never looked back.\u003c/p\u003e\n\u003cp\u003eWell – almost never.\u003c/p\u003e\n\u003cp\u003eThere was always one thing I missed. A tiny, elegant helper that VB.NET allowed me to write. A method that I’ve silently wished C# could express as cleanly:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vb\" data-lang=\"vb\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e\u0026lt;HideModuleName\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003ePublic\u003c/span\u003e \u003cspan class=\"k\"\u003eModule\u003c/span\u003e \u003cspan class=\"nn\"\u003eDisposableExtensions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c\"\u003e\u0026#39;\u0026#39;\u0026#39; \u0026lt;summary\u0026gt;Tries to release allocated resources.\u0026lt;/summary\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    \u0026lt;Extension, DebuggerStepThrough\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ePublic\u003c/span\u003e \u003cspan class=\"k\"\u003eFunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eTryDispose\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eOf\u003c/span\u003e \u003cspan class=\"n\"\u003eT\u003c/span\u003e \u003cspan class=\"ow\"\u003eAs\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eClass\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIDisposable\u003c/span\u003e\u003cspan class=\"p\"\u003e})(\u003c/span\u003e\u003cspan class=\"k\"\u003eByRef\u003c/span\u003e \u003cspan class=\"n\"\u003esource\u003c/span\u003e \u003cspan class=\"ow\"\u003eAs\u003c/span\u003e \u003cspan class=\"n\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ow\"\u003eAs\u003c/span\u003e \u003cspan class=\"kt\"\u003eBoolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eIf\u003c/span\u003e \u003cspan class=\"n\"\u003esource\u003c/span\u003e \u003cspan class=\"ow\"\u003eIs\u003c/span\u003e \u003cspan class=\"k\"\u003eNothing\u003c/span\u003e \u003cspan class=\"k\"\u003eThen\u003c/span\u003e \u003cspan class=\"k\"\u003eReturn\u003c/span\u003e \u003cspan class=\"k\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eTry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003esource\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDispose\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"n\"\u003esource\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eNothing\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003eReturn\u003c/span\u003e \u003cspan class=\"k\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eCatch\u003c/span\u003e \u003cspan class=\"n\"\u003eex\u003c/span\u003e \u003cspan class=\"ow\"\u003eAs\u003c/span\u003e \u003cspan class=\"n\"\u003eException\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003eReturn\u003c/span\u003e \u003cspan class=\"k\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eEnd\u003c/span\u003e \u003cspan class=\"k\"\u003eTry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eEnd\u003c/span\u003e \u003cspan class=\"k\"\u003eFunction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eEnd\u003c/span\u003e \u003cspan class=\"k\"\u003eModule\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis was a genuine life- and time-saver. It not only disposed of an object safely but also \u003cem\u003enulled out\u003c/em\u003e the reference afterwards. In VB.NET, this was possible because extension methods could take parameters \u003cem\u003e\u003ccode\u003eByRef\u003c/code\u003e\u003c/em\u003e – meaning the method could modify the original reference.\u003c/p\u003e\n\u003cp\u003eIn C#, for over a decade, this wasn’t possible. You could write an extension method to call \u003ccode\u003eDispose()\u003c/code\u003e, sure – but you couldn’t also set the caller’s variable to \u003ccode\u003enull\u003c/code\u003e. The language just didn’t allow it.\u003c/p\u003e\n\u003cp\u003eThat missing capability kept this one helper locked in the past, forever trapped in a VB.NET module.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"looking-ahead\"\u003e\u003ca href=\"/posts/still-waiting-for-the-final-piece/#looking-ahead\" title=\"Looking Ahead\"\u003eLooking Ahead\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"net-10-and-c-14-extension-everything\"\u003e\u003ca href=\"/posts/still-waiting-for-the-final-piece/#net-10-and-c-14-extension-everything\" title=\".NET 10 and C# 14: Extension Everything\"\u003e.NET 10 and C# 14: Extension Everything\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eNow with \u003cstrong\u003e.NET 10\u003c/strong\u003e and \u003cstrong\u003eC# 14\u003c/strong\u003e, Microsoft introduces one of the most impactful additions to the language in years: \u003cstrong\u003eExtension Everything\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThis feature expands what extensions can do. Instead of being limited to methods, extensions can now define \u003cem\u003eproperties\u003c/em\u003e, \u003cem\u003eoperators\u003c/em\u003e, and even participate in pattern matching. The new syntax is expressive, elegant, and feels like the logical next step for C#.\u003c/p\u003e\n\u003cp\u003eHere’s what a modern \u003ccode\u003eTryDispose\u003c/code\u003e might look like using the new \u003ccode\u003eextension\u0026lt;T\u0026gt;\u003c/code\u003e construct:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"nn\"\u003eSystem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kd\"\u003estatic\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eIDisposableExtensions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eextension\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;(\u003c/span\u003e\u003cspan class=\"n\"\u003eT\u003c/span\u003e \u003cspan class=\"n\"\u003edisposable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ewhere\u003c/span\u003e \u003cspan class=\"n\"\u003eT\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eIDisposable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eTryDispose\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edisposable\u003c/span\u003e \u003cspan class=\"k\"\u003eis\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003etry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003edisposable\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDispose\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003edisposable\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eClean. Expressive. \u003cstrong\u003eImagine this:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003estream\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOpenRead\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Lots of code...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003estream\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTryDispose\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elogger\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWarn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Could not release stream properly.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIt reads perfectly. It’s elegant. And yet today, it’s still only half real. For now, the value won’t become \u003ccode\u003enull\u003c/code\u003e. The compiler still passes a copy. The concept is ready, but the implementation is not.\u003c/p\u003e\n\u003cp\u003eExactly what we’ve been waiting for.\u003c/p\u003e\n\u003cp\u003eExcept\u0026hellip; not quite.\u003c/p\u003e\n\u003cp\u003eWhile the syntax is here, the semantics aren’t – at least not yet. The extended instance (\u003ccode\u003edisposable\u003c/code\u003e) behaves as a copy of the reference, not a true alias to the caller’s variable. So even though the method compiles and runs, the original variable won’t be set to \u003ccode\u003enull\u003c/code\u003e afterwards. The dream of safely disposing and nulling in a single step remains just out of reach.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"why-it-still-matters\"\u003e\u003ca href=\"/posts/still-waiting-for-the-final-piece/#why-it-still-matters\" title=\"Why It Still Matters\"\u003eWhy It Still Matters\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis syntax is more than just an aesthetic change—it represents an intentional step toward making the language more expressive and aligned with real-world usage. It points in the right direction, even if the final step hasn’t landed yet.\u003c/p\u003e\n\u003cp\u003eThe idea is simple: bring intent and safety together. Give developers the ability to describe what should happen to a resource without extra ceremony. Whether it’s cleanup, resetting, or transformation—such syntax makes intent explicit and code safer.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"closing-thoughts\"\u003e\u003ca href=\"/posts/still-waiting-for-the-final-piece/#closing-thoughts\" title=\"Closing Thoughts\"\u003eClosing Thoughts\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis evolution in syntax feels like the final stretch in a journey that began more than a decade ago. It’s tantalizingly close—a feature that captures the spirit of what VB.NET once made easy, expressed in the elegance of modern C#.\u003c/p\u003e\n\u003cp\u003eVB.NET was always about readability and pragmatism. C# built on that foundation with structure and precision. With \u003cem\u003eExtension Everything\u003c/em\u003e, the two worlds almost meet—but not entirely. Not yet.\u003c/p\u003e\n\u003cp\u003eFor me, that’s both exciting and frustrating. The language can now express the shape of what I’ve wanted for years, but the behavior still isn’t there. So, I’ll keep that old VB.NET module around a little longer — partly out of nostalgia, partly because C# is still a step behind its little brother in this very specific trick. Even though VB.NET no longer holds any real relevance in my work, it’s amusing to see that it still has this one ace up its sleeve.\u003c/p\u003e\n\u003cp\u003eBut we’re getting close. Very close. \u003cstrong\u003eStill waiting for the final piece.\u003c/strong\u003e\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-10-06T09:00:00+02:00","id":"https://daily-devops.net/posts/still-waiting-for-the-final-piece/","language":"en","summary":"C# 14’s new 'Extension Everything' syntax comes close to VB.NET’s ByRef magic—but not quite. A witty look at what’s still missing in modern .NET.\n","tags":["csharp","dotnet","extensions","hidden-gems","vbnet","visualstudio"],"title":"Still Waiting for the Final Piece: C# 14 Comes Close","url":"https://daily-devops.net/posts/still-waiting-for-the-final-piece/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eLet’s skip the typical release-cycle enthusiasm for a second: Most IDE updates come and go. New features, some refactoring helpers, a bit of polish, then back to business as usual. \u003cstrong\u003eVisual Studio 2026 is different.\u003c/strong\u003e For once, the promise of \u0026ldquo;AI-native\u0026rdquo; isn’t just marketing. If Microsoft lands even half of what they’re previewing, it’s going to matter—a lot.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-road-to-2026-why-this-release-actually-matters\"\u003e\u003ca href=\"/posts/visual-studio-2026/#the-road-to-2026-why-this-release-actually-matters\" title=\"The Road to 2026: Why This Release Actually Matters\"\u003eThe Road to 2026: Why This Release Actually Matters\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor anyone who’s built real-world enterprise solutions with .NET, the pain points are obvious. Tooling that can’t keep up with architectural complexity. Boilerplate and manual migration work that never quite get automated. Refactoring that stalls out at the \u0026ldquo;Hello World\u0026rdquo; demo stage.\u003cbr\u003e\nWith Visual Studio 2026, something fundamental is shifting. Microsoft isn’t just layering AI on top of the same old workflows—they’re weaving it into the foundation.\u003c/p\u003e\n\u003cp\u003eEarly signals are strong. Microsoft engineers are already using VS 2026 daily. The pace of public previews is picking up, and the roadmap finally looks like it’s written for actual developers—not just for marketing slides.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBottom line:\u003c/strong\u003e This isn’t just about UI updates or another Copilot sidebar. This is Microsoft’s bid to make Visual Studio the default \u0026ldquo;AI-native\u0026rdquo; platform for .NET, C#, and enterprise-scale software.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAt the time of writing, Visual Studio 2026 was available to download as an Insider Preview. \u003ca href=\"https://visualstudio.microsoft.com/insiders/\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003e\u003cstrong\u003eDownload it now!\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\n\n\n\u003ch2 id=\"expectations-raising-the-bar-for-ai-native-development\"\u003e\u003ca href=\"/posts/visual-studio-2026/#expectations-raising-the-bar-for-ai-native-development\" title=\"Expectations: Raising the Bar for AI-Native Development\"\u003eExpectations: Raising the Bar for AI-Native Development\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf \u0026ldquo;AI-powered\u0026rdquo; means only better code completion, the industry has learned nothing. Here’s what I’m actually looking for—and what VS 2026 \u003cem\u003eneeds\u003c/em\u003e to deliver if it wants to earn its place.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"agent-modelet-ai-do-the-dirty-work\"\u003e\u003ca href=\"/posts/visual-studio-2026/#agent-modelet-ai-do-the-dirty-work\" title=\"Agent Mode—Let AI Do the Dirty Work\"\u003eAgent Mode—Let AI Do the Dirty Work\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEnough with shallow integrations. I want AI that anticipates what comes next—refactorings that cut across dozens of projects, solution-wide migrations, architectural suggestions, and test scaffolding. And it should do this \u003cem\u003ewithout\u003c/em\u003e needing me to hand-craft a prompt every time.\u003c/p\u003e\n\u003cp\u003eAgent Mode needs to move past the chatbot gimmick. Context isn’t just the open file—it’s the shape of the solution, dependency graphs, historical commit data, and even open PRs. If the agent only helps with toy demos, it’s just Copilot with a different skin.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"mcpai-should-fit-my-domain-not-the-other-way-around\"\u003e\u003ca href=\"/posts/visual-studio-2026/#mcpai-should-fit-my-domain-not-the-other-way-around\" title=\"MCP—AI Should Fit My Domain, Not the Other Way Around\"\u003eMCP—AI Should Fit My Domain, Not the Other Way Around\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eLet’s talk Model Context Protocol (MCP). Most teams don’t work like Redmond. Our codebases have quirks. Our architecture, our debt, our standards—all different. MCP must allow \u003cem\u003egenuine extensibility\u003c/em\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eBring your own model (not just OpenAI or whatever’s trendy this year)\u003c/li\u003e\n\u003cli\u003eShare prompts and automation patterns inside the org\u003c/li\u003e\n\u003cli\u003eFine-tune context, so the AI actually learns what matters to us\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf this turns out to be just another wrapper for GPT with a new logo, I’ll keep my skepticism. If it unlocks true domain adaptation, then we’re talking about something disruptive.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"copilot-grows-up\"\u003e\u003ca href=\"/posts/visual-studio-2026/#copilot-grows-up\" title=\"Copilot Grows Up\"\u003eCopilot Grows Up\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCopilot is fine for snippets and tests. But in the .NET enterprise world, I want an assistant that understands architecture, not just syntax. Real intelligence would be recognizing design patterns, surfacing tech debt hotspots, and proposing migration paths—not just stubbing out another service class.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"benefits-what-professional-developers-stand-to-gain\"\u003e\u003ca href=\"/posts/visual-studio-2026/#benefits-what-professional-developers-stand-to-gain\" title=\"Benefits: What Professional Developers Stand to Gain\"\u003eBenefits: What Professional Developers Stand to Gain\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere’s where the marketing fluff usually takes over. But there are \u003cem\u003ereal\u003c/em\u003e benefits on the table—if, and only if, the execution matches the ambition.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"productivity-that-actually-frees-up-headspace\"\u003e\u003ca href=\"/posts/visual-studio-2026/#productivity-that-actually-frees-up-headspace\" title=\"Productivity That Actually Frees Up Headspace\"\u003eProductivity That Actually Frees Up Headspace\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIf VS 2026 does its job, developers should get hours back each week. The goal isn’t \u0026ldquo;faster typing\u0026rdquo;—it’s less cognitive drag. Automate the 80% of tasks that any good developer can do in their sleep, and let us focus on problems that require human judgment.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"contextual-guidance-not-more-noise\"\u003e\u003ca href=\"/posts/visual-studio-2026/#contextual-guidance-not-more-noise\" title=\"Contextual Guidance, Not More Noise\"\u003eContextual Guidance, Not More Noise\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eI’m not interested in more squiggly lines or generic code suggestions. I want real context:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhat’s changed in this branch?\u003c/li\u003e\n\u003cli\u003eHow did the last migration go?\u003c/li\u003e\n\u003cli\u003eWhat are the unwritten architectural boundaries here?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAI in VS 2026 should help me \u003cem\u003eunderstand\u003c/em\u003e and \u003cem\u003eenforce\u003c/em\u003e these realities—not distract me with irrelevant tips.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"quality-and-reliability-as-defaults\"\u003e\u003ca href=\"/posts/visual-studio-2026/#quality-and-reliability-as-defaults\" title=\"Quality and Reliability as Defaults\"\u003eQuality and Reliability as Defaults\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eTesting, static analysis, security scanning—these shouldn’t be optional. I expect VS 2026 to surface problems (and solutions) in real time, with recommendations that respect my architecture, not just industry best practices.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"customization-that-goes-deep\"\u003e\u003ca href=\"/posts/visual-studio-2026/#customization-that-goes-deep\" title=\"Customization That Goes Deep\"\u003eCustomization That Goes Deep\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eExtensions, themes, code policies—they matter. But I want even more:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eProject- and repo-level themes\u003c/li\u003e\n\u003cli\u003eAutomated enforcement of architectural decisions\u003c/li\u003e\n\u003cli\u003eAI-augmented linters and code analyzers that can be tuned for \u003cem\u003emy\u003c/em\u003e needs\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"architectural-impact-preparing-for-the-shift\"\u003e\u003ca href=\"/posts/visual-studio-2026/#architectural-impact-preparing-for-the-shift\" title=\"Architectural Impact: Preparing for the Shift\"\u003eArchitectural Impact: Preparing for the Shift\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis is where most \u0026ldquo;future of IDE\u0026rdquo; articles check out. But if you’re building or maintaining real .NET systems, the architectural implications are front and center.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"automation-as-a-design-principle\"\u003e\u003ca href=\"/posts/visual-studio-2026/#automation-as-a-design-principle\" title=\"Automation as a Design Principle\"\u003eAutomation as a Design Principle\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eAI isn’t a magic wand, but it’s an accelerant. Teams that design for automatable work—clear boundaries, documented contracts, metadata-rich solutions—will benefit most. Legacy codebases will need to evolve if they want to tap into these gains.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"governance-moves-upstream\"\u003e\u003ca href=\"/posts/visual-studio-2026/#governance-moves-upstream\" title=\"Governance Moves Upstream\"\u003eGovernance Moves Upstream\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEnterprise devs know the pain: compliance, traceability, code review audits. With AI making changes, \u003cem\u003ewho owns what\u003c/em\u003e gets murkier. VS 2026 needs hooks for code provenance, audit trails, and review flows that can incorporate AI-generated changes as first-class citizens.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"devops-rewired\"\u003e\u003ca href=\"/posts/visual-studio-2026/#devops-rewired\" title=\"DevOps Rewired\"\u003eDevOps Rewired\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe lines between dev and ops will blur even more. Smarter CI/CD, dynamic builds, automated rollback logic—if VS 2026 integrates natively, we could finally see an end to brittle build scripts and manual deployment pain. Technical debt, at last, might become something you measure (and tackle) continuously.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"final-take\"\u003e\u003ca href=\"/posts/visual-studio-2026/#final-take\" title=\"Final Take\"\u003eFinal Take\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI’m not interested in hype. I’m interested in whether Visual Studio 2026 can move the needle for real developers building real systems.\u003cbr\u003e\nIf Microsoft follows through, this will reset expectations—not just for IDEs, but for what \u0026ldquo;intelligent tooling\u0026rdquo; really means. If they fall short, it’ll be just another missed opportunity.\u003c/p\u003e\n\u003cp\u003eEither way, enterprise .NET teams can’t afford to ignore what’s coming. Start prepping your codebase, your architecture, and your DevOps pipelines. The next era of software development is about to land in your IDE—ready or not.\n\u003cem\u003eWhat are your thoughts on Visual Studio 2026? Are you excited about the AI-native features, or skeptical about their real-world impact? Share your views in the comments below!\u003c/em\u003e\u003c/p\u003e","date_modified":"2026-02-16T08:03:33+01:00","date_published":"2025-09-10T01:00:00+02:00","id":"https://daily-devops.net/posts/visual-studio-2026/","language":"en","summary":"Visual Studio 2026 brings AI-native tooling. Learn what professional .NET teams should expect and how enterprise architecture adapts to changes.","tags":["visualstudio","csharp","dotnet"],"title":"Visual Studio 2026 - Why AI-Native Tooling Will Matter","url":"https://daily-devops.net/posts/visual-studio-2026/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn a previous article, we laid it out – unfiltered: \u003ca href=\"https://daily-devops.net/posts/copilot-turns-junior-devs-into-syntax-secretaries/\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003e\u003cstrong\u003eCopilot turns junior devs into syntax secretaries.\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eNot because it’s evil. But because it \u003cstrong\u003eremoves friction before understanding\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eIt gives you working code before you know what \u003cem\u003eworking\u003c/em\u003e even means. It creates the illusion of progress, while slowly eroding the very skills that define a software engineer: reasoning, decision-making, and technical ownership.\u003c/p\u003e\n\u003cp\u003eThat critique still stands.\u003c/p\u003e\n\u003cp\u003eBut here’s the catch: \u003cstrong\u003eThe same tool that disables junior developers can empower senior engineers – if they know what they’re doing.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe key isn’t the tool. It’s \u003cstrong\u003ewho’s holding the keyboard\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThis article is about reclaiming Copilot – not as a crutch, but as a force multiplier.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"seven-steps-to-master-copilot\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#seven-steps-to-master-copilot\" title=\"Seven Steps to Master Copilot\"\u003eSeven Steps to Master Copilot\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"step-1-stop-worshipping-the-output\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-1-stop-worshipping-the-output\" title=\"Step 1: Stop Worshipping the Output\"\u003eStep 1: Stop Worshipping the Output\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eLet’s get one thing straight: \u003cstrong\u003eCopilot is not \u0026ldquo;AI\u0026rdquo;.\u003c/strong\u003e It’s a token prediction engine trained on millions of public repositories – including the bad ones.\u003c/p\u003e\n\u003cp\u003eIt doesn’t:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUnderstand your business logic\u003c/li\u003e\n\u003cli\u003eKnow your system constraints\u003c/li\u003e\n\u003cli\u003eRespect your architecture\u003c/li\u003e\n\u003cli\u003eOr care if your code silently corrupts production data\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eCopilot doesn’t think. It \u003cem\u003eguesses\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eThat means every suggestion it makes should be treated as \u003cstrong\u003eguilty until proven useful\u003c/strong\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWould you deploy code written by a clueless intern who sounds confident?\n\u003cem\u003eThen don’t blindly accept Copilot output either.\u003c/em\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\n\n\n\u003ch3 id=\"step-2-dont-let-the-tool-set-the-pace\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-2-dont-let-the-tool-set-the-pace\" title=\"Step 2: Don’t Let the Tool Set the Pace\"\u003eStep 2: Don’t Let the Tool Set the Pace\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eOne of the most subtle traps Copilot sets for senior devs is \u003cstrong\u003evelocity addiction\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eIt gives you a dopamine rush: you type three letters, and a full method appears.\nIt’s seductive. It feels efficient. It feels productive.\u003c/p\u003e\n\u003cp\u003eBut here’s the reality:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDid you just skip the error-handling strategy?\u003c/li\u003e\n\u003cli\u003eDid you consider testability?\u003c/li\u003e\n\u003cli\u003eDid you choose the right abstraction layer?\u003c/li\u003e\n\u003cli\u003eDid you even \u003cem\u003ename\u003c/em\u003e things meaningfully?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eIf you didn’t stop and ask those questions, Copilot didn’t make you faster.\nIt made you \u003cem\u003elazy\u003c/em\u003e.\nAnd lazy senior engineers are more dangerous than clueless juniors – because they ship code that looks trustworthy.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-3-use-it-to-offload--not-outsource--thinking\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-3-use-it-to-offload--not-outsource--thinking\" title=\"Step 3: Use It to Offload – Not Outsource – Thinking\"\u003eStep 3: Use It to Offload – Not Outsource – Thinking\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe real value of Copilot begins when you \u003cstrong\u003ealready know\u003c/strong\u003e what you’re doing.\u003c/p\u003e\n\u003cp\u003eIf you’ve built a hundred layered service implementations in .NET Core – by all means, let Copilot generate the scaffolding.\u003c/p\u003e\n\u003cp\u003eIf you’re writing a test fixture with tedious mocking boilerplate – fine, autocomplete away.\u003c/p\u003e\n\u003cp\u003eBut when you’re:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDesigning a concurrency model\u003c/li\u003e\n\u003cli\u003eCrafting a DSL\u003c/li\u003e\n\u003cli\u003eBuilding a distributed system component\u003c/li\u003e\n\u003cli\u003eDefining a new domain abstraction\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eThen \u003cstrong\u003eCopilot has no business driving.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eUse it for:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLow-brainpower scaffolding\u003c/li\u003e\n\u003cli\u003eRepetitive composition\u003c/li\u003e\n\u003cli\u003eAuto-generating test stubs\u003c/li\u003e\n\u003cli\u003eExploring syntactic variations\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eBut \u003cem\u003eyou\u003c/em\u003e decide the design. Not the suggestion.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-4-prompt-like-a-professional-not-a-prompt-engineer\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-4-prompt-like-a-professional-not-a-prompt-engineer\" title=\"Step 4: Prompt Like a Professional, Not a Prompt Engineer\"\u003eStep 4: Prompt Like a Professional, Not a Prompt Engineer\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCopilot doesn’t \u0026ldquo;understand\u0026rdquo; context. It responds to \u003cstrong\u003epatterns\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eSo don’t write vague half-sentences like \u0026ldquo;make this better\u0026rdquo; and expect miracles.\u003c/p\u003e\n\u003cp\u003eInstead, treat Copilot prompts like function signatures:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eBe explicit\u003c/li\u003e\n\u003cli\u003eBe scoped\u003c/li\u003e\n\u003cli\u003eAssume ambiguity is punished\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e✅ Example prompt:\u003c/strong\u003e Write a thread-safe async method in C# that wraps a third-party API call with exponential backoff using Polly, and logs all non-transient failures via Serilog.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cbr\u003e\n\u003cp\u003eThat prompt gets you \u003cem\u003eleverage\u003c/em\u003e.\nBecause you’re setting the architectural contract.\nCopilot just fills in the boring parts.\u003c/p\u003e\n\u003cbr\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e🚫 What not to do:\u003c/strong\u003e Call API with retries.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cbr\u003e\n\u003cp\u003eThat’s how you end up with retry-on-404 garbage logic that silently fails in production.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-5-copilot-is-a-mirror--train-it-to-reflect-quality\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-5-copilot-is-a-mirror--train-it-to-reflect-quality\" title=\"Step 5: Copilot Is a Mirror – Train It to Reflect Quality\"\u003eStep 5: Copilot Is a Mirror – Train It to Reflect Quality\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCopilot doesn’t invent style – it reflects what it sees.\u003c/p\u003e\n\u003cp\u003eWhich means:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIf your codebase is clean, expressive, well-factored – Copilot suggestions improve.\u003c/li\u003e\n\u003cli\u003eIf it’s inconsistent, under-tested, or polluted with lazy shortcuts – Copilot amplifies that rot.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eIn other words:\n\u003cstrong\u003eYour discipline teaches the tool what \u0026ldquo;normal\u0026rdquo; looks like.\u003c/strong\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eSo:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUse explicit, descriptive method names\u003c/li\u003e\n\u003cli\u003eKeep test coverage high\u003c/li\u003e\n\u003cli\u003eEnforce boundaries\u003c/li\u003e\n\u003cli\u003eWrite proper failure paths\u003c/li\u003e\n\u003cli\u003eMaintain clear separation of concerns\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eIf your code smells like engineering, Copilot will start to autocomplete \u003cem\u003eengineering\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eIf it smells like Stack Overflow duct tape – well, you already know the result.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-6-review-it-like-it-was-written-by-a-liar\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-6-review-it-like-it-was-written-by-a-liar\" title=\"Step 6: Review It Like It Was Written by a Liar\"\u003eStep 6: Review It Like It Was Written by a Liar\u003c/a\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eHere’s a non-negotiable rule:\u003c/strong\u003e Every Copilot suggestion must be reviewed as if it came from someone trying to impress you without understanding the problem.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cbr\u003e\n\u003cp\u003eThat means:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCheck for race conditions\u003c/li\u003e\n\u003cli\u003eExamine exception handling\u003c/li\u003e\n\u003cli\u003eValidate parameter boundaries\u003c/li\u003e\n\u003cli\u003eWatch for leaky abstractions\u003c/li\u003e\n\u003cli\u003eAssess performance under real-world constraints\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eJust because the code compiles doesn’t mean it’s correct.\u003c/p\u003e\n\u003cp\u003eJust because it runs doesn’t mean it scales.\u003c/p\u003e\n\u003cp\u003eJust because it works doesn’t mean it’s safe.\u003c/p\u003e\n\u003cp\u003eYou’re the engineer. Copilot is just a code monkey with good grammar.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-7-know-when-to-walk-away\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#step-7-know-when-to-walk-away\" title=\"Step 7: Know When to Walk Away\"\u003eStep 7: Know When to Walk Away\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eGreat developers know \u003cstrong\u003ewhen not to automate\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eDo not use Copilot:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIn security-sensitive logic (encryption, auth flows, claims handling)\u003c/li\u003e\n\u003cli\u003eWhen designing new public interfaces\u003c/li\u003e\n\u003cli\u003eWhile writing infrastructure-as-code\u003c/li\u003e\n\u003cli\u003eFor architecture decisions\u003c/li\u003e\n\u003cli\u003eWhen you’re unclear about the problem domain\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn these cases, Copilot isn’t helpful.\u003c/p\u003e\n\u003cp\u003eIt’s noise. Distraction. \u003cem\u003eA confident liar offering false shortcuts.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eAnd your job as a senior engineer is to guard against shortcuts that violate long-term quality.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"final-word-you-dont-need-copilot-thats-why-you-can-use-it\"\u003e\u003ca href=\"/posts/copilot-without-becoming-its-puppet/#final-word-you-dont-need-copilot-thats-why-you-can-use-it\" title=\"Final Word: You Don’t Need Copilot. That’s Why You Can Use It\"\u003eFinal Word: You Don’t Need Copilot. That’s Why You Can Use It\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf you still think Copilot is \u003cem\u003eyour coding assistant,\u003c/em\u003e you’ve missed the point.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eIt’s not your peer. It’s your tool.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eYou already know how to:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWrite expressive code\u003c/li\u003e\n\u003cli\u003eDesign reliable systems\u003c/li\u003e\n\u003cli\u003eReview and refactor ruthlessly\u003c/li\u003e\n\u003cli\u003eQuestion defaults\u003c/li\u003e\n\u003cli\u003eOwn the outcome\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eThat’s why you can use Copilot \u003cem\u003ewithout losing yourself in it\u003c/em\u003e.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eBecause at the end of the day: \u003cem\u003e\u003cstrong\u003eTools don’t build software. Engineers do.\u003c/strong\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eAnd if we want to preserve the quality of our craft in a world of AI-assisted mediocrity, we need to lead by example.\u003c/p\u003e\n\u003cbr\u003e\n\u003cp\u003eCopilot can help you go faster – but only \u003cstrong\u003eafter\u003c/strong\u003e you’ve done the work to know where you\u0026rsquo;re going.\u003c/p\u003e\n","date_modified":"2026-05-20T21:28:40+02:00","date_published":"2025-05-14T17:30:00+02:00","id":"https://daily-devops.net/posts/copilot-without-becoming-its-puppet/","language":"en","summary":"Master GitHub Copilot as a productivity tool while maintaining your coding skills, critical thinking abilities, and commitment to software craftsmanship.","tags":["ai-code-assistant","bestpractices","dotnet","github","github-copilot","testing","visualstudio"],"title":"How to Use Copilot Without Becoming Its Puppet","url":"https://daily-devops.net/posts/copilot-without-becoming-its-puppet/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eThe hype around GitHub Copilot (or any other AI code assistant) is deafening. AI-assisted coding. Effortless automation. \u003cem\u003e\u003cstrong\u003e10x productivity.\u003c/strong\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eBut here’s the harsh truth: \u003cstrong\u003eCopilot isn’t empowering junior developers – it’s deskilling them.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNo shortcuts. No sugarcoating. Just software done right.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eIt’s not making them engineers. It’s turning them into \u003cem\u003esyntax secretaries\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eThey type. The tool fills in the blanks. They deploy.\nNo understanding. No design thinking. No learning.\u003c/p\u003e\n\u003cp\u003eLet’s break this down – in code, in context, and in consequence.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"it-writes-code-but-youre-supposed-to-write-systems\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#it-writes-code-but-youre-supposed-to-write-systems\" title=\"It Writes Code. But You’re Supposed to Write Systems\"\u003eIt Writes Code. But You’re Supposed to Write Systems\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eProgramming isn’t about writing lines of code. It’s about designing systems.\nIt’s about thinking through:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eState transitions\u003c/li\u003e\n\u003cli\u003eFault tolerance\u003c/li\u003e\n\u003cli\u003eTrade-offs between readability, performance, and maintainability\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eCopilot bypasses all of that.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"example-from-net-build-a-caching-layer-that-wraps-a-call-to-an-external-api\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#example-from-net-build-a-caching-layer-that-wraps-a-call-to-an-external-api\" title=\"Example from .NET: Build a caching layer that wraps a call to an external API\"\u003eExample from .NET: Build a caching layer that wraps a call to an external API\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCopilot gives you:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eIMemoryCache\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHttpClient\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003easync/await\u003c/li\u003e\n\u003cli\u003emaybe some exception handling\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eBut it \u003cstrong\u003edoesn’t\u003c/strong\u003e make you think about:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTransient fault handling (\u003ccode\u003ePolly\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eHttpClient reuse and DNS updates\u003c/li\u003e\n\u003cli\u003eCache invalidation semantics\u003c/li\u003e\n\u003cli\u003eTimezone-safe comparisons\u003c/li\u003e\n\u003cli\u003eWhat happens if the API fails silently for two hours\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIt gives you code that \u003cem\u003elooks right\u003c/em\u003e – and that’s the most dangerous kind of code.\nBecause junior developers don’t know what to doubt.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"youre-not-learning-the-why-youre-memorizing-the-what\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#youre-not-learning-the-why-youre-memorizing-the-what\" title=\"You\u0026rsquo;re Not Learning the Why. You\u0026rsquo;re Memorizing the What\"\u003eYou\u0026rsquo;re Not Learning the Why. You\u0026rsquo;re Memorizing the What\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWhen Copilot gives you an answer, there’s no struggle.\nNo exploration. No doc-reading. No architecture discussions. No trade-offs.\u003c/p\u003e\n\u003cp\u003eIt’s just output.\u003c/p\u003e\n\u003cp\u003eAnd juniors, understandably, assume the output is correct.\nSo they learn \u003cem\u003epatterns\u003c/em\u003e, but not \u003cem\u003eprinciples\u003c/em\u003e.\nThey learn \u003cem\u003esolutions\u003c/em\u003e, but not \u003cem\u003eproblems\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eAsk them:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhy \u003ccode\u003eConfigureAwait(false)\u003c/code\u003e appears in library code?\u003c/li\u003e\n\u003cli\u003eWhy \u003ccode\u003eAddScoped\u003c/code\u003e and not \u003ccode\u003eAddSingleton\u003c/code\u003e for that service?\u003c/li\u003e\n\u003cli\u003eWhy \u003ccode\u003easync void\u003c/code\u003e is almost always wrong?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThey won’t know.\nBecause Copilot doesn’t teach that. And they never had to care.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"copilot-rewards-passivity\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#copilot-rewards-passivity\" title=\"Copilot Rewards Passivity\"\u003eCopilot Rewards Passivity\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLet’s be brutally honest: \u003cstrong\u003eMost junior developers don’t need help writing more code.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eThey need help:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDebugging\u003c/li\u003e\n\u003cli\u003eReasoning\u003c/li\u003e\n\u003cli\u003eModeling\u003c/li\u003e\n\u003cli\u003eTesting\u003c/li\u003e\n\u003cli\u003eReading logs\u003c/li\u003e\n\u003cli\u003eNaming things\u003c/li\u003e\n\u003cli\u003eUnderstanding the system outside their function\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\nCopilot doesn’t train that. It rewards passivity.\n\u003cp\u003eIt turns proactive engineering into reactive prompting.\u003c/p\u003e\n\u003cp\u003eIt’s no longer: \u003cem\u003eHow should I design this?\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eIt’s: \u003cem\u003eHow do I phrase my prompt to get something close enough?\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eThat mindset might produce a feature. But it will never produce a \u003cstrong\u003edeveloper\u003c/strong\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"youre-not-building-knowledge-youre-outsourcing-it\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#youre-not-building-knowledge-youre-outsourcing-it\" title=\"You\u0026rsquo;re Not Building Knowledge. You\u0026rsquo;re Outsourcing It\"\u003eYou\u0026rsquo;re Not Building Knowledge. You\u0026rsquo;re Outsourcing It\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere’s the most perverse irony of all:\u003c/p\u003e\n\u003cp\u003eThe developer who uses Copilot the most ends up knowing the least.\u003c/p\u003e\n\u003cp\u003eThey’ve outsourced:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSyntax\u003c/li\u003e\n\u003cli\u003eControl flow\u003c/li\u003e\n\u003cli\u003eAPI usage\u003c/li\u003e\n\u003cli\u003eDesign patterns\u003c/li\u003e\n\u003cli\u003eException handling\u003c/li\u003e\n\u003cli\u003eTest coverage\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\nEverything but the typing.\n\u003cp\u003eWhich means they become \u003cstrong\u003edependent\u003c/strong\u003e on Copilot to do their job.\u003c/p\u003e\n\u003cp\u003eRemove the tool – and the facade collapses.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"it-looks-like-productivity--until-something-breaks\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#it-looks-like-productivity--until-something-breaks\" title=\"It Looks Like Productivity – Until Something Breaks\"\u003eIt Looks Like Productivity – Until Something Breaks\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eA junior dev with Copilot might look fast.\nThey push code. Close tickets. Move features.\u003c/p\u003e\n\u003cp\u003eBut fast code isn’t good code.\nAnd when things break – and they will – they have no idea where to start.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLogs? Unfamiliar.\u003c/li\u003e\n\u003cli\u003eThreading? Scary.\u003c/li\u003e\n\u003cli\u003eSystem behavior under load? Never even considered.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eBecause they’ve never been forced to reason about any of it.\nCopilot took that friction away.\nAnd with it, all the growth.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"whats-the-alternative\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#whats-the-alternative\" title=\"What’s the Alternative?\"\u003eWhat’s the Alternative?\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIt’s not about banning Copilot.\nIt’s about \u003cstrong\u003etiming\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eCopilot is fine when you:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUnderstand the abstraction\u003c/li\u003e\n\u003cli\u003eKnow the system constraints\u003c/li\u003e\n\u003cli\u003eCan review the output critically\u003c/li\u003e\n\u003cli\u003eWould’ve written the same code manually anyway\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbr\u003e\n\u003cp\u003eIn other words:\nUse it \u003cstrong\u003eafter\u003c/strong\u003e you’ve learned to think.\u003c/p\u003e\n\u003cp\u003eUntil then? \u003cstrong\u003eIf you can’t write it without Copilot, don’t write it with Copilot.\u003c/strong\u003e\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"final-word\"\u003e\u003ca href=\"/posts/copilot-turns-junior-devs-into-syntax-secretaries/#final-word\" title=\"Final Word\"\u003eFinal Word\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eEarly-career developers need friction.\nThey need confusion.\nThey need mistakes that teach lessons Copilot will never explain.\u003c/p\u003e\n\u003cp\u003eBecause real engineering starts where Copilot stops.\u003c/p\u003e\n\u003cp\u003eSo to every junior developer out there:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eClose the AI tab.\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOpen the docs.\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStruggle a bit.\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBreak things.\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFix them.\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnderstand why.\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAnd remember: \u003cstrong\u003eNo shortcuts. No sugarcoating. Just software done right.\u003c/strong\u003e\u003c/p\u003e","date_modified":"2026-05-05T17:06:04+02:00","date_published":"2025-05-13T17:30:00+02:00","id":"https://daily-devops.net/posts/copilot-turns-junior-devs-into-syntax-secretaries/","language":"en","summary":"Explore how GitHub Copilot and AI assistants impact junior developer growth, focusing on learning fundamentals beyond syntax completion and automation.","tags":["ai-code-assistant","bestpractices","dotnet","github","github-copilot","testing","visualstudio"],"title":"Copilot Turns Junior Devs Into Syntax Secretaries","url":"https://daily-devops.net/posts/copilot-turns-junior-devs-into-syntax-secretaries/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn the ever-evolving world of .NET development, managing project configurations effectively is crucial for maintaining a clean and efficient build process. One of the less frequently discussed but highly useful properties is \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e. This property, when correctly utilized, can streamline your build process and ensure that your project is configured properly depending on the build environment. In this article, we\u0026rsquo;ll explore the \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property with concrete examples and discuss best practices for using it effectively.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"understanding-the-buildinginsidevisualstudio-property\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#understanding-the-buildinginsidevisualstudio-property\" title=\"Understanding the BuildingInsideVisualStudio Property\"\u003eUnderstanding the \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e Property\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property is a conditional flag that can be used within your project files (.csproj) to apply certain settings or include/exclude packages and references based on whether the project is being built inside Visual Studio. This property is particularly useful when you need to differentiate between builds triggered from Visual Studio and those triggered from other environments such as command-line builds or CI/CD pipelines. See also \u003ca href=\"https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003eMSBuild conditions\u003c/a\u003e and \u003ca href=\"https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003ecommon project properties\u003c/a\u003e for context.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"example-adding-a-package-reference-conditionally\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#example-adding-a-package-reference-conditionally\" title=\"Example: Adding a Package Reference Conditionally\"\u003eExample: Adding a Package Reference Conditionally\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLet\u0026rsquo;s start with a practical example: adding a package reference only when the project is being built inside Visual Studio. This can be useful when you want to include certain tools or analyzers only in the development environment to keep the build lean for production.\u003c/p\u003e\n\u003cp\u003eAssuming you want to add a reference to \u003ccode\u003eSonarAnalyzer.CSharp\u003c/code\u003e, a popular static code analysis tool, but only when building the project within Visual Studio, you can use the \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property to conditionally include this package reference in your \u003ccode\u003e.csproj\u003c/code\u003e file. Why would you want to do this? It\u0026rsquo;s already included in your CI/CD pipeline, so you don\u0026rsquo;t need it in your local development environment? The answer is simple: you want to have the same code analysis rules and hints in your local development environment as in your CI/CD pipeline. This way, you can fix issues early and avoid surprises when pushing your code to the repository, and executing maybe long-running CI/CD pipelines.\u003c/p\u003e\n\u003cp\u003eHere\u0026rsquo;s how you can do it:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;Project\u003c/span\u003e \u003cspan class=\"na\"\u003eSdk=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Microsoft.NET.Sdk\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u003c/span\u003e \u003cspan class=\"na\"\u003eCondition=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;$(BuildingInsideVisualStudio)\u0026#39; == \u0026#39;true\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;SonarAnalyzer.CSharp\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;9.6.0\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Rest of the project file --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/Project\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch2 id=\"beware-of-pitfalls-with-buildinginsidevisualstudio\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#beware-of-pitfalls-with-buildinginsidevisualstudio\" title=\"Beware of Pitfalls with BuildingInsideVisualStudio\"\u003eBeware of Pitfalls with \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWhile the \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property is a powerful tool for customizing your build process, there are some common pitfalls to be aware of when using it in your project files. Let\u0026rsquo;s explore these pitfalls and how to avoid them.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"expectation-that-buildinginsidevisualstudio-is-configured-correctly\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#expectation-that-buildinginsidevisualstudio-is-configured-correctly\" title=\"Expectation that BuildingInsideVisualStudio is configured correctly\"\u003eExpectation that \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e is configured correctly\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWhen using the \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property, it\u0026rsquo;s important to remember that it may not always be set to \u003ccode\u003etrue\u003c/code\u003e. For example, when building the project outside of Visual Studio, this property may be empty or set to a different value. Relying on the assumption that \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e will always be \u003ccode\u003etrue\u003c/code\u003e or \u003ccode\u003efalse\u003c/code\u003e can lead to unexpected behavior and misconfigurations.\u003c/p\u003e\n\u003cp\u003eWhen using conditional checks in your project files, it\u0026rsquo;s essential to ensure that the property values are correctly set and evaluated. Misconfiguring the property values can lead to unexpected behavior or missing configurations. In the case of \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e, the only valid fact is \u003ccode\u003etrue\u003c/code\u003e when the project is built inside Visual Studio. Otherwise, it could be \u003ccode\u003efalse\u003c/code\u003e or empty.\u003c/p\u003e\n\u003cp\u003eTo avoid issues where the property might be empty or not set, you should use a condition that checks against \u003ccode\u003etrue\u003c/code\u003e explicitly. This ensures that the feature is enabled only when the property is explicitly set to \u003ccode\u003etrue\u003c/code\u003e. Here\u0026rsquo;s an example of a conditional property check:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;Project\u003c/span\u003e \u003cspan class=\"na\"\u003eSdk=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Microsoft.NET.Sdk\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Instead of this 👎 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u003c/span\u003e \u003cspan class=\"na\"\u003eCondition=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;$(BuildingInsideVisualStudio)\u0026#39; == \u0026#39;false\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;FeatureXPackage\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1.0.0\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Use this 👍 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u003c/span\u003e \u003cspan class=\"na\"\u003eCondition=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;$(BuildingInsideVisualStudio)\u0026#39; != \u0026#39;true\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;FeatureXPackage\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;1.0.0\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/Project\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch4 id=\"benefits\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#benefits\" title=\"Benefits\"\u003eBenefits\u003c/a\u003e\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAvoids Null or Empty Values:\u003c/strong\u003e With a condition like \u003ccode\u003e!= 'true'\u003c/code\u003e, you ensure that the feature is enabled only when the property is not explicitly set to \u003ccode\u003etrue\u003c/code\u003e, avoiding issues with null or empty values.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConsistent Behavior:\u003c/strong\u003e This approach ensures consistent behavior across different environments and build scenarios.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch4 id=\"potential-errors\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#potential-errors\" title=\"Potential Errors\"\u003ePotential Errors\u003c/a\u003e\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMisconfigured Conditions:\u003c/strong\u003e Incorrectly configured conditions can lead to unexpected behavior or missing configurations. Always test your project settings thoroughly.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnintended Enabling:\u003c/strong\u003e Be cautious of unintended enabling of features or dependencies if the property is not set as expected.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"assumption-that-this-works-in-other-ides\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#assumption-that-this-works-in-other-ides\" title=\"Assumption that this works in other IDEs\"\u003eAssumption that this works in other IDEs\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn general assumptions are bad. The \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property is a Visual Studio specific property. It is not guaranteed to work in other IDEs like Visual Studio Code, or any other IDE. If you want to have the same behavior in other IDEs, you have to check if the IDE supports this property or if there is a similar property available. Like in JetBrains Rider, you can use the \u003ccode\u003eBuildingByReSharper\u003c/code\u003e property.\u003c/p\u003e\n\n\n\n\n\u003ch4 id=\"potential-errors-1\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#potential-errors-1\" title=\"Potential Errors\"\u003ePotential Errors\u003c/a\u003e\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eIncompatibility with Other IDEs:\u003c/strong\u003e Relying solely on \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e can lead to incompatibility issues when using other IDEs or build environments. Always check the compatibility of the property with your target environment.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"conclusion\"\u003e\u003ca href=\"/posts/buildinginsidevisualstudio/#conclusion\" title=\"Conclusion\"\u003eConclusion\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe \u003ccode\u003eBuildingInsideVisualStudio\u003c/code\u003e property and conditional checks in your .NET project files offer powerful ways to customize your build process depending on the environment. By following best practices such as checking conditions against \u003ccode\u003etrue\u003c/code\u003e and being mindful of how properties are used, you can avoid common pitfalls and optimize your build configurations for different scenarios.\u003c/p\u003e\n\u003cp\u003eLeveraging these techniques not only helps in maintaining a clean and efficient build process but also ensures that your project is configured correctly across various development environments. As always, thorough testing and careful configuration are key to making the most out of these features.\u003c/p\u003e\n\u003cp\u003eFeel free to incorporate these examples into your own projects and see how they can simplify and improve your build process. Happy coding!\u003c/p\u003e","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2024-09-10T17:00:00+02:00","id":"https://daily-devops.net/posts/buildinginsidevisualstudio/","language":"en","summary":"Learn how to use the BuildingInsideVisualStudio property in .NET to conditionally include packages, optimize builds, and streamline developer workflows.","tags":["msbuild","visualstudio","bestpractices","csharp","dotnet","hidden-gems"],"title":"BuildingInsideVisualStudio: .NET Project Properties","url":"https://daily-devops.net/posts/buildinginsidevisualstudio/"}],"language":"en","title":"Visual Studio IDE and Extensions on Daily DevOps \u0026 .NET","version":"https://jsonfeed.org/version/1.1"}