{"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 Risk and Cost Driven Architecture (RCDA) on Daily DevOps \u0026 .NET","favicon":"https://daily-devops.net/images/logo_hu_6465d873dfa490cf.png","feed_url":"https://daily-devops.net/tags/rcda/feed.json","home_page_url":"https://daily-devops.net/tags/rcda/","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\u003eIn every mature .NET landscape, legacy projects represent both heritage and hazard.\nThey once powered entire business models — now they silently consume time, budget, and attention.\nThe decision to retire or modernize them isn’t about technology fashion. It’s about sustaining the organization’s \u003cstrong\u003ecapacity for value creation\u003c/strong\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-real-cost-of-staying-still\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-real-cost-of-staying-still\" title=\"The Real Cost of Staying Still\"\u003eThe Real Cost of Staying Still\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLegacy .NET systems rarely collapse overnight. Instead, they leak productivity, talent, and opportunity.\nAcross enterprise portfolios, the same pattern emerges: \u003cstrong\u003edeath by a thousand cuts\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eEach day brings smaller compromises. A deployment that takes three hours instead of ten minutes. A critical patch delayed because nobody remembers how the authentication module works. A talented developer who leaves because they\u0026rsquo;re tired of debugging 15-year-old code with zero documentation.\u003c/p\u003e\n\u003cp\u003eThe symptoms compound silently:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eTechnical debt interest\u003c/strong\u003e accumulates faster than principal payments\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eKnowledge gaps\u003c/strong\u003e widen as original developers retire or move on\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSecurity vulnerabilities\u003c/strong\u003e multiply in unmaintained dependencies\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePerformance degradation\u003c/strong\u003e becomes \u0026ldquo;just how the system works\u0026rdquo;\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIntegration bottlenecks\u003c/strong\u003e prevent adoption of modern tools and platforms\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eOrganizations often don\u0026rsquo;t realize the true cost until it\u0026rsquo;s measured. One mid-size company discovered their legacy .NET Framework applications consumed \u003cstrong\u003e40% of their total IT budget\u003c/strong\u003e while delivering only \u003cstrong\u003e12% of new business value\u003c/strong\u003e. The remainder went to keeping old systems breathing — patching, monitoring, and working around limitations that modern architectures solve by design.\u003c/p\u003e\n\u003cp\u003eMeanwhile, competitors move faster. They deploy daily instead of quarterly. They scale automatically instead of manually provisioning servers. They innovate while you maintain.\u003c/p\u003e\n\u003cp\u003eThe most insidious cost isn\u0026rsquo;t technical — it\u0026rsquo;s \u003cstrong\u003eopportunity cost\u003c/strong\u003e. Every hour spent nursing legacy systems is an hour not spent building competitive advantage.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eFactor\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eTypical Overhead\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eBusiness Impact\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMaintenance \u0026amp; Support\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e+25–35 %\u003c/strong\u003e vs. modern systems\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eSlower response, fragile builds\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eSecurity \u0026amp; Compliance\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e2× audit effort\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eManual patching, unsupported dependencies\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eTalent Retention\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e+20–40 % cost\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eFewer developers skilled in legacy tech\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eDelivery Velocity\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e\u003cstrong\u003e−30 % throughput\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003eMissed releases and delayed features\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eIn short: legacy code is not just \u003cem\u003eold\u003c/em\u003e. It’s \u003cem\u003eexpensive to keep right\u003c/em\u003e and \u003cem\u003erisky to ignore\u003c/em\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"a-business-view-of-modernization\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#a-business-view-of-modernization\" title=\"A Business View of Modernization\"\u003eA Business View of Modernization\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eModernization is not a technology upgrade — it\u0026rsquo;s a \u003cstrong\u003erisk trade-off\u003c/strong\u003e.\nThe right question isn\u0026rsquo;t \u003cem\u003e\u0026ldquo;What will it cost to rebuild?\u0026rdquo;\u003c/em\u003e but \u003cem\u003e\u0026ldquo;What will it cost if we don\u0026rsquo;t?\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-economics-of-standing-still\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-economics-of-standing-still\" title=\"The Economics of Standing Still\"\u003eThe Economics of Standing Still\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFor most medium-size .NET systems, the financial picture reveals a compelling case for action:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMaintenance Cost (Legacy):\u003c/strong\u003e ~€180 k/year\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMigration Effort:\u003c/strong\u003e ~€600–700 k one-time\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePost-Migration Cost:\u003c/strong\u003e ~€110–130 k/year\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAverage Payback:\u003c/strong\u003e ~3–4 years\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThose are directional numbers — but they tell a story.\nEach year of delay increases the risk of outage, compliance findings, and missed releases.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"hidden-multipliers\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#hidden-multipliers\" title=\"Hidden Multipliers\"\u003eHidden Multipliers\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe visible costs represent only the baseline. Legacy systems create cascading inefficiencies that compound over time:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDeveloper Productivity Loss:\u003c/strong\u003e Teams spend \u003cstrong\u003e60–70% of their time\u003c/strong\u003e on maintenance tasks rather than feature development. This translates to roughly €40–60k annually in lost opportunity per developer on legacy codebases.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSecurity and Compliance Gaps:\u003c/strong\u003e Outdated frameworks often lack modern security features. Organizations typically face \u003cstrong\u003e2–3× higher audit costs\u003c/strong\u003e and increased exposure to penalties. A single compliance violation can cost €25–100k in fines and remediation.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePlatform Lock-in Penalties:\u003c/strong\u003e Legacy systems often run on expensive, proprietary infrastructure. Cloud migration savings of \u003cstrong\u003e20–35%\u003c/strong\u003e remain inaccessible while maintaining legacy dependencies.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-compound-interest-of-technical-debt\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-compound-interest-of-technical-debt\" title=\"The Compound Interest of Technical Debt\"\u003eThe Compound Interest of Technical Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eUnlike financial debt, technical debt doesn\u0026rsquo;t have a fixed interest rate — it accelerates. A legacy system that costs €180k to maintain today will likely cost €220–250k within three years without intervention.\u003c/p\u003e\n\u003cp\u003eMeanwhile, the migration cost remains relatively stable, but the gap between legacy and modern operational costs widens:\u003c/p\u003e\n\u003ctable class=\"striped\"\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eYear\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eLegacy Annual Cost\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eModern Annual Cost\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: left\"\u003eCumulative Savings (Post-Migration)\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e1\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€180k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€120k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€60k\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e2\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€200k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€125k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€135k\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e3\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€225k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€130k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€230k\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e4\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€250k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€135k\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: left\"\u003e€345k\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\n\n\u003ch3 id=\"risk-quantification\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#risk-quantification\" title=\"Risk Quantification\"\u003eRisk Quantification\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eBeyond operational costs, legacy systems carry measurable business risks:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDowntime Exposure:\u003c/strong\u003e Legacy systems typically experience \u003cstrong\u003e40–60% more unplanned outages\u003c/strong\u003e than modern architectures. For revenue-critical applications, each hour of downtime can cost €5–25k.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTalent Flight Risk:\u003c/strong\u003e Organizations running predominantly legacy stacks report \u003cstrong\u003e25–40% higher developer turnover\u003c/strong\u003e. Replacement and training costs average €35–50k per departing developer.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMarket Responsiveness:\u003c/strong\u003e Legacy systems constrain feature delivery speed. Companies report \u003cstrong\u003e6–12 month delays\u003c/strong\u003e in competitive responses due to legacy technical constraints.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-strategic-threshold\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-strategic-threshold\" title=\"The Strategic Threshold\"\u003eThe Strategic Threshold\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe modernization decision becomes clear when viewing it through a portfolio lens. Legacy systems consuming more than \u003cstrong\u003e30% of IT budget\u003c/strong\u003e while delivering less than \u003cstrong\u003e20% of business value\u003c/strong\u003e represent a strategic inflection point.\u003c/p\u003e\n\u003cp\u003eAt this threshold, every dollar invested in modernization generates measurable returns in:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eReduced operational overhead\u003c/li\u003e\n\u003cli\u003eImproved development velocity\u003c/li\u003e\n\u003cli\u003eEnhanced security posture\u003c/li\u003e\n\u003cli\u003eIncreased platform flexibility\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe question isn\u0026rsquo;t whether to modernize — it\u0026rsquo;s whether you can afford not to.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"from-tight-coupling-to-composable-systems\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#from-tight-coupling-to-composable-systems\" title=\"From Tight Coupling to Composable Systems\"\u003eFrom Tight Coupling to Composable Systems\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLegacy applications often follow a tightly coupled monolithic pattern where everything is hardwired together.\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// Legacy .NET Framework approach\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=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eOrderController\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eController\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=\"n\"\u003eActionResult\u003c/span\u003e \u003cspan class=\"n\"\u003eProcessOrder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eorderId\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\"\u003eorder\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003eOrderRepository\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eGet\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eorderId\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=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003epayment\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003ePaymentService\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eProcess\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    \u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eemail\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003eEmailService\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eSend\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\"\u003eCustomerEmail\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\"\u003eView\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  \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\u003eThis creates dependencies that can\u0026rsquo;t be tested, swapped, or deployed independently. Changing the email provider means editing and redeploying the entire application.\u003c/p\u003e\n\u003cp\u003eA modern .NET approach separates these concerns:\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// Modern .NET 8 approach\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMapPost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;/orders/{id}/process\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIOrderService\u003c/span\u003e \u003cspan class=\"n\"\u003eorders\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\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\"\u003eresult\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eorders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcessAsync\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=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eresult\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\"\u003eResults\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOk\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eResults\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBadRequest\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=\"kd\"\u003epublic\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eOrderService\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eIOrderService\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\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e \u003cspan class=\"n\"\u003eIPaymentClient\u003c/span\u003e \u003cspan class=\"n\"\u003e_payment\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=\"kd\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e \u003cspan class=\"n\"\u003eIEmailClient\u003c/span\u003e \u003cspan class=\"n\"\u003e_email\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\"\u003easync\u003c/span\u003e \u003cspan class=\"n\"\u003eTask\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eResult\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eProcessAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eorderId\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\"\u003eorder\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eGetOrderAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eorderId\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_payment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcessAsync\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    \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003e_email\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSendConfirmationAsync\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    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eResult\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=\"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\u003eThe improvement is measurable: teams report \u003cstrong\u003e30-40% faster delivery\u003c/strong\u003e once dependencies can be developed and deployed separately.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"practical-modernization-steps\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#practical-modernization-steps\" title=\"Practical Modernization Steps\"\u003ePractical Modernization Steps\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eModernization works best as incremental improvements, not big rewrites:\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"1-wrap-legacy-code\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#1-wrap-legacy-code\" title=\"1. Wrap Legacy Code\"\u003e1. Wrap Legacy Code\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003ePut APIs around existing functionality to stop it from spreading:\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// Simple wrapper approach\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMapPost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;/legacy/orders\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eOrderRequest\u003c/span\u003e \u003cspan class=\"n\"\u003ereq\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\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\"\u003eLegacyOrderSystem\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ereq\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eToLegacyFormat\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\"\u003eResults\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOk\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\n\n\n\n\u003ch3 id=\"2-replace-piece-by-piece\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#2-replace-piece-by-piece\" title=\"2. Replace Piece by Piece\"\u003e2. Replace Piece by Piece\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eGradually swap old components for new ones:\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// Route to modern or legacy based on feature flags\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\"\u003eprocessor\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003euseModern\u003c/span\u003e \u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003emodernOrderProcessor\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003elegacyOrderProcessor\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\"\u003eprocessor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProcessAsync\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\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"3-remove-whats-left\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#3-remove-whats-left\" title=\"3. Remove What\u0026rsquo;s Left\"\u003e3. Remove What\u0026rsquo;s Left\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDecommission the old system once everything valuable has been extracted.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-real-benefits\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-real-benefits\" title=\"The Real Benefits\"\u003eThe Real Benefits\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eModernization delivers measurable business value:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDeployment speed:\u003c/strong\u003e From hours to minutes\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBug fixes:\u003c/strong\u003e 40% fewer defects in modern codebases\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDeveloper productivity:\u003c/strong\u003e Teams spend 60% more time on features vs. maintenance\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInfrastructure costs:\u003c/strong\u003e 20-30% savings through cloud-native patterns\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"the-choice-is-clear\"\u003e\u003ca href=\"/posts/retiring-legacy-dotnet-projects/#the-choice-is-clear\" title=\"The Choice is Clear\"\u003eThe Choice is Clear\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLegacy systems consume resources without creating value. Every month of delay makes modernization more expensive and risky.\u003c/p\u003e\n\u003cp\u003eThe goal isn\u0026rsquo;t perfect code — it\u0026rsquo;s \u003cstrong\u003esustainable progress\u003c/strong\u003e. Modern .NET gives you the tools to build systems that adapt, scale, and evolve with your business needs.\u003c/p\u003e\n\u003cp\u003eBecause maintaining the past shouldn\u0026rsquo;t prevent you from building the future.\u003c/p\u003e","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-10-13T11:30:00+02:00","id":"https://daily-devops.net/posts/retiring-legacy-dotnet-projects/","language":"en","summary":"Modernize legacy .NET systems with modular architecture, risk reduction, cost efficiency strategies, and practical patterns for measurable impact.","tags":["architecture","bestpractices","dotnet","rcda","softwareengineering"],"title":"Retiring Legacy .NET Projects: Risk, Cost, Forward Motion","url":"https://daily-devops.net/posts/retiring-legacy-dotnet-projects/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn the .NET ecosystem, few things have remained as stable as the unit testing landscape.\nFor years, \u003cstrong\u003exUnit\u003c/strong\u003e, \u003cstrong\u003eNUnit\u003c/strong\u003e, and \u003cstrong\u003eMSTest\u003c/strong\u003e have been the go-to frameworks — dependable, predictable, and well-integrated.\nNow, \u003cstrong\u003eTUnit\u003c/strong\u003e, a new open-source project from the community (not Microsoft), is challenging the status quo with a modern design built on source generation, concurrency, and native AOT support.\u003c/p\u003e\n\u003cp\u003eThe question isn’t whether it’s new — it’s whether it’s worth adopting.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-testing-landscape-stability-meets-disruption\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#the-testing-landscape-stability-meets-disruption\" title=\"The Testing Landscape: Stability Meets Disruption\"\u003eThe Testing Landscape: Stability Meets Disruption\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eMost enterprise .NET teams rely on mature testing stacks that have proven themselves through countless CI/CD cycles.\nEach of the established frameworks has its place:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMSTest\u003c/strong\u003e – The traditional, Microsoft-endorsed option, tightly integrated into Visual Studio and Azure DevOps; predictable and enterprise-friendly, though somewhat dated in syntax and extensibility.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNUnit\u003c/strong\u003e – Feature-rich and stable, ideal for complex testing scenarios and broad legacy support.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003exUnit\u003c/strong\u003e – Modern conventions, parallelization by default, and a cleaner programming model for test organization.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTUnit\u003c/strong\u003e – The newcomer, built with Roslyn source generators and a modern runtime model (using \u003cem\u003eMicrosoft.Testing.Platform\u003c/em\u003e) focused on speed, determinism, and native AOT compatibility.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe innovation TUnit offers is architectural — not syntactical. It moves responsibility from runtime to build-time, changing how tests are discovered and executed.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"familiar-syntax-subtle-evolution\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#familiar-syntax-subtle-evolution\" title=\"Familiar Syntax, Subtle Evolution\"\u003eFamiliar Syntax, Subtle Evolution\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eOne of TUnit’s most compelling strengths is that it feels instantly familiar to developers.\nThe syntax closely mirrors that of xUnit, minimizing friction while adding small but meaningful improvements.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"example--tunit\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#example--tunit\" title=\"Example — TUnit\"\u003eExample — TUnit\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=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"nn\"\u003eTUnit\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=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eArithmeticTests\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=\"na\"\u003e    [Test]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eAdd_ShouldReturnSum\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eThat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eIsEqualTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e5\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=\"na\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [Test]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [Arguments(2, 3, 5)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [Arguments(10, 20, 30)]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eParameterized_Add\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eexpected\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eThat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eIsEqualTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eexpected\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=\"na\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [Test]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [DependsOn(nameof(Add_ShouldReturnSum))]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDependentTest\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eThat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eIsEqualTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e2\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\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eCompare that to \u003cstrong\u003eMSTest\u003c/strong\u003e, \u003cstrong\u003exUnit\u003c/strong\u003e, and \u003cstrong\u003eNUnit\u003c/strong\u003e:\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"mstest\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#mstest\" title=\"MSTest\"\u003eMSTest\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=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"nn\"\u003eMicrosoft.VisualStudio.TestTools.UnitTesting\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=\"na\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e[TestClass]\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=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eArithmeticTests\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=\"na\"\u003e    [TestMethod]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [DataRow(2, 3, 5)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [DataRow(10, 20, 30)]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eAdd_ShouldReturnSum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eexpected\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAreEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eexpected\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\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\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"xunit\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#xunit\" title=\"xUnit\"\u003exUnit\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=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"nn\"\u003eXunit\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=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eArithmeticTests\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=\"na\"\u003e    [Theory]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [InlineData(2, 3, 5)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [InlineData(10, 20, 30)]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eAdd_ShouldReturnSum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eexpected\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eexpected\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\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\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"nunit\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#nunit\" title=\"NUnit\"\u003eNUnit\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=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"nn\"\u003eNUnit.Framework\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=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eArithmeticTests\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=\"na\"\u003e    [TestCase(2, 3, 5)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003e    [TestCase(10, 20, 30)]\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=\"k\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eAdd_ShouldReturnSum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eexpected\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=\"n\"\u003eAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eThat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEqualTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eexpected\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\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAcross these examples, the differences are subtle — but TUnit introduces compile-time discovery, dependency control, and async-aware assertions without abandoning the simplicity that makes xUnit and MSTest approachable.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"performance-and-discovery-the-compile-time-advantage\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#performance-and-discovery-the-compile-time-advantage\" title=\"Performance and Discovery: The Compile-Time Advantage\"\u003ePerformance and Discovery: The Compile-Time Advantage\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe real technical distinction lies under the surface.\nWhile MSTest, xUnit, and NUnit rely on \u003cstrong\u003ereflection\u003c/strong\u003e to discover and run tests, TUnit shifts this process to \u003cstrong\u003ecompile time\u003c/strong\u003e via Roslyn source generators.\nThat change has measurable consequences:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eFramework\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eDiscovery Model\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eAvg. Startup Time\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eParallel Execution\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eAOT Compatible\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eEcosystem Maturity\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eMSTest\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eReflection\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e~1.6s\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eLimited\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eNo\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eVery High\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eNUnit\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eReflection\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e~1.8s\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eOptional\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eNo\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eVery High\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003exUnit\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eReflection\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e~1.4s\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eDefault\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePartial\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eExcellent\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eTUnit\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSource Generation\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e~0.9s\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eBuilt-in\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eYes\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eEmerging\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eEarly benchmarks (from \u003ca href=\"https://andrewlock.net/converting-an-xunit-project-to-tunit/\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003eAndrew Lock, 2024\u003c/a\u003e) show discovery and execution overhead reduced by \u003cstrong\u003e15–25%\u003c/strong\u003e in mid-sized suites.\nThat’s not academic — in enterprise CI pipelines, small savings compound fast.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eExample:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e10,000 builds per week × 15 seconds saved per run → \u003cstrong\u003e41 hours saved weekly\u003c/strong\u003e.\u003cbr/\u003e\nAt $50/hour in build infrastructure costs, that’s roughly \u003cstrong\u003e$2,000 per month\u003c/strong\u003e in real value.\u003c/p\u003e\n\u003cp\u003eThis is where TUnit begins to show \u003cstrong\u003eeconomic relevance\u003c/strong\u003e — not just theoretical efficiency.\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\n\n\n\u003ch2 id=\"tooling-and-ecosystem-integration\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#tooling-and-ecosystem-integration\" title=\"Tooling and Ecosystem Integration\"\u003eTooling and Ecosystem Integration\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTooling maturity remains TUnit’s biggest hurdle.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMSTest\u003c/strong\u003e integrates seamlessly with Visual Studio, Azure DevOps, and corporate reporting pipelines — it’s stable, predictable, and requires zero friction.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003exUnit\u003c/strong\u003e and \u003cstrong\u003eNUnit\u003c/strong\u003e enjoy broad support across IDEs, build systems, and test runners; they’re the de facto standards for mature teams.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTUnit\u003c/strong\u003e works seamlessly through the \u003ccode\u003eMicrosoft.Testing.Platform\u003c/code\u003e layer, so it integrates well with existing tools and workflows. It works in Visual Studio, other IDEs and the CLI.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFor greenfield projects, this is acceptable. For enterprise ecosystems with thousands of tests, it\u0026rsquo;s currently a deal-breaker, though automatic migration tools are emerging to address this limitation.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"maintainability-and-lifecycle-considerations\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#maintainability-and-lifecycle-considerations\" title=\"Maintainability and Lifecycle Considerations\"\u003eMaintainability and Lifecycle Considerations\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTUnit’s design aligns well with modern .NET runtime evolution — it’s built for SDK-level integration and AOT compatibility.\nHowever, unlike MSTest, it doesn’t follow Microsoft’s LTS cadence, which means \u003cstrong\u003efaster iteration\u003c/strong\u003e but \u003cstrong\u003eless predictable stability\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThat’s both opportunity and risk:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMSTest\u003c/strong\u003e is safe but slow-moving.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003exUnit/NUnit\u003c/strong\u003e are stable and predictable.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTUnit\u003c/strong\u003e evolves rapidly, reflecting the latest language and SDK advances.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFor teams comfortable with early adoption, that’s an advantage. For conservative enterprise stacks, it introduces change management overhead.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"adoption-guidance\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#adoption-guidance\" title=\"Adoption Guidance\"\u003eAdoption Guidance\u003c/a\u003e\u003c/h2\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eScenario\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eRecommendation\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eNew .NET 10+ projects\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e✅ Worth adopting; future-ready and performance-efficient\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003ePerformance-critical CI pipelines\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e✅ Pilot candidate\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eExisting MSTest/xUnit/NUnit suites\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e⚠️ Defer migration until ecosystem matures\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eLong-term enterprise projects (LTS)\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e❌ Too early; lifecycle alignment uncertain\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eA reasonable approach is hybrid adoption: start with new modules or performance-sensitive components, measure, and expand only if the ROI is tangible.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-business-view-value-cost-risk\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#the-business-view-value-cost-risk\" title=\"The Business View: Value, Cost, Risk\"\u003eThe Business View: Value, Cost, Risk\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAt its core, the choice of testing framework is not a technical one — it’s architectural.\nThe framework defines reliability, maintainability, and operational efficiency for years.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMSTest\u003c/strong\u003e guarantees continuity and corporate integration — ideal where risk avoidance trumps innovation.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003exUnit\u003c/strong\u003e offers balance — modern yet stable, performant yet well-supported.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNUnit\u003c/strong\u003e remains feature-rich but leans toward legacy or test-heavy applications.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTUnit\u003c/strong\u003e pushes testing forward — faster discovery, AOT readiness, smarter concurrency — but its youth carries risk.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe decision is ultimately about \u003cem\u003etiming\u003c/em\u003e: adopting too early adds cost; adopting too late loses competitive edge.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"final-thoughts\"\u003e\u003ca href=\"/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/#final-thoughts\" title=\"Final Thoughts\"\u003eFinal Thoughts\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTUnit represents the direction .NET testing is headed — toward compile-time determinism, deeper runtime integration, and minimal overhead.\nIt’s technically elegant and forward-looking, but still maturing.\u003c/p\u003e\n\u003cp\u003eFor most organizations today, the pragmatic answer is balance:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eKeep \u003cstrong\u003eMSTest\u003c/strong\u003e, \u003cstrong\u003exUnit\u003c/strong\u003e, and \u003cstrong\u003eNUnit\u003c/strong\u003e where stability matters.\u003c/li\u003e\n\u003cli\u003ePilot \u003cstrong\u003eTUnit\u003c/strong\u003e where innovation pays off.\u003c/li\u003e\n\u003cli\u003eMeasure, not assume.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn short: \u003cstrong\u003eTUnit is not a replacement (yet) for all teams, but a glimpse of the future.\u003c/strong\u003e\nAnd as always in architecture, progress is best managed, not rushed.\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-10-09T11:30:00+02:00","id":"https://daily-devops.net/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/","language":"en","summary":"A pragmatic TUnit evaluation for .NET teams - comparing performance, maintainability, and ecosystem readiness against MSTest, xUnit, and NUnit frameworks.","tags":["architecture","bestpractices","dotnet","performance","rcda","softwareengineering","testing"],"title":"TUnit — A Pragmatic Evaluation for .NET Teams\n","url":"https://daily-devops.net/posts/tunit-a-pragmatic-evaluation-for-dotnet-teams/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eArchitectural Decision Records (ADRs) capture the \u0026ldquo;why\u0026rdquo; behind your technical choices—documenting decisions, rationale, and context for future reference. They should guide teams through complex landscapes, inform new decisions, and provide clarity during audits or onboarding.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBut here\u0026rsquo;s the problem:\u003c/strong\u003e Most ADRs become digital dust collectors.\u003c/p\u003e\n\u003cp\u003eThey sit in repositories, referenced only during crisis meetings or compliance audits. Developers bypass them during daily work, and automation tools ignore them completely. The gap between architectural intent and daily practice grows wider every sprint.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"understanding-the-problem\"\u003e\u003ca href=\"/posts/instruction-by-design/#understanding-the-problem\" title=\"Understanding the Problem\"\u003eUnderstanding the Problem\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"the-core-challenge\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-core-challenge\" title=\"The Core Challenge\"\u003eThe Core Challenge\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eTraditional ADRs are \u003cstrong\u003epassive documentation\u003c/strong\u003e—they record what happened, but don\u0026rsquo;t actively shape what happens next:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDiscovery friction:\u003c/strong\u003e New team members must hunt through scattered documents to understand current standards\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEnforcement gaps:\u003c/strong\u003e Build systems and linters operate independently of architectural decisions\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConsistency drift:\u003c/strong\u003e Without active reinforcement, even well-documented standards gradually erode across teams\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"the-vision-adrs-that-actually-work\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-vision-adrs-that-actually-work\" title=\"The Vision: ADRs That Actually Work\"\u003eThe Vision: ADRs That Actually Work\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eImagine ADRs that don\u0026rsquo;t just document decisions—they \u003cstrong\u003edrive\u003c/strong\u003e them:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEvery architectural choice directly influences code suggestions from AI Code Assistant\u003c/li\u003e\n\u003cli\u003eNew developers instantly understand current standards through integrated guidance\u003c/li\u003e\n\u003cli\u003eAutomation systems enforce architectural decisions in real time\u003c/li\u003e\n\u003cli\u003eTeams work with consistent, up-to-date guidance embedded in their daily tools\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis isn\u0026rsquo;t just better documentation—it\u0026rsquo;s \u003cstrong\u003eoperational architecture\u003c/strong\u003e. By making ADRs machine-consumable and embedding clear instructions, they become the single source of truth that powers both human understanding and automated enforcement.\u003c/p\u003e\n\u003cp\u003eThe result? Development environments where architectural intent is always clear, actionable, and automatically aligned across every team member and tool.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"why-traditional-adrs-fall-short\"\u003e\u003ca href=\"/posts/instruction-by-design/#why-traditional-adrs-fall-short\" title=\"Why Traditional ADRs Fall Short\"\u003eWhy Traditional ADRs Fall Short\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe gap between architectural intent and daily practice is where most projects struggle. Traditional ADRs capture decisions brilliantly but fail to integrate them into the development workflow where they matter most.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePassive documentation:\u003c/strong\u003e ADRs become historical artifacts that developers consult only during crisis or retrospectives—if at all.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDisconnected from automation:\u003c/strong\u003e Build systems, linters, and AI tools operate independently of architectural decisions, missing opportunities to enforce standards automatically.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOnboarding friction:\u003c/strong\u003e New team members must manually discover and interpret scattered decisions, slowing their ability to contribute effectively.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInconsistent application:\u003c/strong\u003e Without active reinforcement, even well-documented decisions gradually drift or get forgotten across different teams and projects.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"the-solution-instruction-by-design\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-solution-instruction-by-design\" title=\"The Solution: Instruction by Design\"\u003eThe Solution: Instruction by Design\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"instruction-by-design-from-records-to-directives\"\u003e\u003ca href=\"/posts/instruction-by-design/#instruction-by-design-from-records-to-directives\" title=\"Instruction by Design: From Records to Directives\"\u003eInstruction by Design: From Records to Directives\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe transformation begins when we stop thinking of ADRs as documentation and start treating them as executable specifications for both human and AI behavior.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMachine-consumable structure:\u003c/strong\u003e Every ADR includes structured metadata and clear instructions that AI Code Assistant can parse and apply immediately.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOperational states with meaning:\u003c/strong\u003e \u0026ldquo;Accepted\u0026rdquo; decisions become mandatory requirements, \u0026ldquo;proposed\u0026rdquo; become considerations, while \u0026ldquo;deprecated\u0026rdquo; and \u0026ldquo;superseded\u0026rdquo; trigger active avoidance patterns.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDirect workflow integration:\u003c/strong\u003e Decisions automatically influence code suggestions, review processes, and validation pipelines without manual intervention.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSingle source of truth:\u003c/strong\u003e Both developers and AI agents reference the same authoritative guidance, eliminating interpretation gaps and ensuring consistent application.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"the-ai-enforcement-layer\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-ai-enforcement-layer\" title=\"The AI Enforcement Layer\"\u003eThe AI Enforcement Layer\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWhen architectural decisions become machine-readable, they can drive intelligent automation throughout your development process:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gu\"\u003e## Decision References\n\u003c/span\u003e\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\"\u003e*\u003c/span\u003e MUST document all decisions in \u003cspan class=\"sb\"\u003e`decisions/`\u003c/span\u003e folder using \u003cspan class=\"sb\"\u003e`templates/architecture-decision.md`\u003c/span\u003e format.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e*\u003c/span\u003e MUST treat \u0026#34;accepted\u0026#34; decisions as mandatory requirements with highest precedence.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e*\u003c/span\u003e MUST respect decision states:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003e-\u003c/span\u003e **accepted**: mandatory requirements\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003e-\u003c/span\u003e **proposed**: optional considerations\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003e-\u003c/span\u003e **deprecated**: avoid in new implementations\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003e-\u003c/span\u003e **superseded**: forbidden, follow superseding decision instead\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e*\u003c/span\u003e MUST use the \u003cspan class=\"sb\"\u003e`instructions`\u003c/span\u003e frontmatter property as primary AI guidance for each decision.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThese rules make every ADR actionable. Human or AI, your team always knows what matters most. Now the journey with your AI buddy begins with clear, actionable guidance. Without the day-to-day friction of interpreting static documents, your team can focus on what really matters: building great software.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-enhanced-adr-template-built-for-action\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-enhanced-adr-template-built-for-action\" title=\"The Enhanced ADR Template: Built for Action\"\u003eThe Enhanced ADR Template: Built for Action\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe template itself is full of helpful instructions and required fields, for clarity and standardization:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;!-- List of authors who contributed to this decision. Include full names and roles if applicable. --\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eauthors:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Name Surname \u0026lt;!-- Replace with actual name --\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Another Name Surname \u0026lt;!-- Add more authors as needed --\u0026gt;\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eThe patterns this decision applies to. Each entry is a glob pattern that matches files affected by this decision.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eExample:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eapplyTo:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e \u0026#34;**/*.cs\u0026#34;          # Applies to all C# files\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e \u0026#34;src/**/*.razor\u0026#34;   # Applies to all Blazor components in src folder\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e \u0026#34;tests/**/*.sql\u0026#34;   # Applies to all SQL files in tests folder\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eapplyTo:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e \u0026#34;**/*\u0026#34; \u0026lt;!-- Replace with specific glob patterns --\u0026gt;\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\u0026lt;!-- The date this ADR was initially created in YYYY-MM-DD format. --\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecreated: YYYY-MM-DD\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eThe most recent date this ADR was updated in YYYY-MM-DD format.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eIMPORTANT: Update this field whenever the decision is modified.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elastModified: YYYY-MM-DD\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eThe current state of this ADR. If superseded, include references to the superseding ADR.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eValid values: proposed, accepted, deprecated, superseded\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003estate: proposed\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eA compact AI LLM compatible definition of this decision.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eThis should be a precise, structured description that AI systems can easily parse and understand.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eInclude the core decision, key rationale, and primary impact in 1-2 concise sentences.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003einstructions: |\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  Compact definition of the decision made and its core purpose.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  Key rationale and primary impact on the project or development process.\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\u0026lt;!-- REQUIRED: Filename MUST follow the format: YYYY-MM-DD-Title (replace all spaces with hyphens) --\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gh\"\u003e# Title \u0026lt;!-- A concise title that summarizes the decision. Use a format like \u0026#34;Decision: [Short Description of Decision]\u0026#34;. --\u0026gt;\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eA brief summary of the decision. This should be a short paragraph that captures the essence of the decision made.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\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=\"gu\"\u003e## Context\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eProvide a detailed explanation of the problem or issue that led to this decision. Include background information, constraints, and any relevant context to help readers understand why this decision was necessary.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\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=\"gu\"\u003e## Decision\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eClearly state the decision made. Describe the chosen solution or approach in detail, including any specific technologies, tools, or methods involved.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\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=\"gu\"\u003e## Consequences\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eExplain the implications of this decision. What are the expected benefits, trade-offs, and potential risks? How will this decision impact the project or organization?\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\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=\"gu\"\u003e## Alternatives Considered\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eList and describe other options that were considered. For each alternative, explain why it was not chosen. Include pros and cons, feasibility, and any other relevant factors.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\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=\"gu\"\u003e## Related Decisions (Optional)\n\u003c/span\u003e\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\u0026lt;!--\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eProvide links or references to other ADRs that are related to this decision. Explain how they are connected and why they are relevant.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eUse markdown link syntax to reference other decisions: [\u003cspan class=\"nt\"\u003eDecision Title\u003c/span\u003e](\u003cspan class=\"na\"\u003e./YYYY-MM-DD-decision-filename.md\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eIf there are no related decisions, this section may be omitted or include a note stating \u0026#34;None at this time.\u0026#34;\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\"\u003eExample:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e [\u003cspan class=\"nt\"\u003eCentralized Package Version Management\u003c/span\u003e](\u003cspan class=\"na\"\u003e./2025-07-10-centralized-package-version-management.md\u003c/span\u003e) - Related because this decision impacts how we manage dependencies\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e [\u003cspan class=\"nt\"\u003eConventional Commits\u003c/span\u003e](\u003cspan class=\"na\"\u003e./2025-07-10-conventional-commits.md\u003c/span\u003e) - This decision affects our commit message format which impacts versioning\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this structure matters:\u003c/strong\u003e\nEvery field drives your team toward actionable clarity. No more vague rationale, ambiguous decisions, or documentation drift. The template itself becomes machine-readable—AI Code Assistant can parse every element directly, while humans get the structure they need to make consistent, enforceable decisions.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"concrete-example-english-as-project-language\"\u003e\u003ca href=\"/posts/instruction-by-design/#concrete-example-english-as-project-language\" title=\"Concrete Example: English as Project Language\"\u003eConcrete Example: English as Project Language\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eLet’s see how this works with a real, high-impact example.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-markdown\" data-lang=\"markdown\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eauthors:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Jane Doe, Solution Architect\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e John Smith, Lead Developer\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eapplyTo:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e \u0026#34;**/*\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecreated: 2025-07-15\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elastModified: 2025-07-15\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003estate: accepted\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003einstructions: |\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  Establish English as the mandatory language for all code, documentation, comments, commit messages, and written content to ensure consistency and global accessibility.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  Applies to all identifiers, configuration files, database objects, and communication using clear, professional English standards.\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=\"gh\"\u003e# Decision: English as Project Language\n\u003c/span\u003e\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\"\u003eAll project artifacts, including code, docs, configs, database objects, and commit messages, must use clear, professional English. This enables global collaboration, faster onboarding, and consistent reviews—by both people and AI.\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=\"gu\"\u003e## Context\n\u003c/span\u003e\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\"\u003eFragmented language use has slowed down onboarding, increased misunderstandings, and made collaboration harder across regions. A single language standard solves these problems.\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=\"gu\"\u003e## Decision\n\u003c/span\u003e\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\"\u003eAll content—code, comments, documentation, configs, and communication—must be in English, using clear and professional standards.\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=\"gu\"\u003e## Consequences\n\u003c/span\u003e\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=\"gs\"\u003e**Benefits:**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Global teams onboard faster and communicate better\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Automated tools and AI Code Assistant can parse, review, and generate content reliably\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Fewer mistakes, less rework, and smoother audits\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=\"gs\"\u003e**Trade-offs/Risks:**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Non-native English speakers may need support\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Existing teams may need time to adapt\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=\"gu\"\u003e## Alternatives Considered\n\u003c/span\u003e\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\"\u003e-\u003c/span\u003e Local language flexibility: Increased confusion and audit risk\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e-\u003c/span\u003e Bilingual documentation: High maintenance, likely to get out of sync\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=\"gu\"\u003e## Related Decisions\n\u003c/span\u003e\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\"\u003e-\u003c/span\u003e [\u003cspan class=\"nt\"\u003eCentralized Documentation Standards\u003c/span\u003e](\u003cspan class=\"na\"\u003e./2025-07-10-centralized-documentation-standards.md\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis ADR is a perfect example of \u003cstrong\u003eInstruction by Design\u003c/strong\u003e. It’s not just a record of a decision; it’s a directive that shapes how your team works every day. By specifying that all project artifacts must be in English, it sets clear expectations for both human developers and AI Code Assistant.\u003c/p\u003e\n\u003cp\u003eIt eliminates ambiguity, reduces friction, and ensures that everyone—regardless of their native language—can contribute effectively.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"why-this-matters\"\u003e\u003ca href=\"/posts/instruction-by-design/#why-this-matters\" title=\"Why This Matters\"\u003eWhy This Matters\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis ADR is more than just a decision; it’s a \u003cstrong\u003estandard\u003c/strong\u003e that your team can rely on. It’s clear, actionable, and enforceable. By using this template, you ensure that every architectural decision is not only documented but also actively shapes your development process.\u003c/p\u003e\n\u003cp\u003eIt’s a living document that evolves with your project, guiding both human and AI agents toward consistent, high-quality outcomes.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"how-ai-and-automation-put-this-to-work\"\u003e\u003ca href=\"/posts/instruction-by-design/#how-ai-and-automation-put-this-to-work\" title=\"How AI and Automation Put This to Work\"\u003eHow AI and Automation Put This to Work\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWith Instruction by Design, your ADRs become living documents that AI Code Assistant can use to guide development. Here’s how it works in practice:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eAutomatic code and docs checks:\u003c/strong\u003e\nAI Code Assistant flag any non-English content and suggest improvements in real time. Always considering the ADRs as the source of truth.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eGuided pull requests:\u003c/strong\u003e\nEvery reviewer can refer to the ADR for clear, objective decisions. Without friction, they can align on expectations and requirements quickly.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eFast onboarding:\u003c/strong\u003e\nNew developers and AI agents see the language policy immediately—and know it’s enforced.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"the-bigger-picture-operationalizing-architecture\"\u003e\u003ca href=\"/posts/instruction-by-design/#the-bigger-picture-operationalizing-architecture\" title=\"The Bigger Picture: Operationalizing Architecture\"\u003eThe Bigger Picture: Operationalizing Architecture\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eInstruction by Design is about more than just better ADRs. It’s about \u003cstrong\u003eoperationalizing architecture\u003c/strong\u003e—making your architectural decisions active participants in your development process.\nBy embedding clear, actionable instructions into every ADR, you create a system where architectural intent is always clear, enforceable, and aligned with your team’s daily work.\u003c/p\u003e\n\u003cp\u003eThis approach transforms ADRs from passive records into active guides that shape both human and AI behavior. It ensures that every decision is not just documented but also \u003cstrong\u003eoperationalized\u003c/strong\u003e—driving consistent, high-quality outcomes across your development teams.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"benefits-of-instruction-by-design\"\u003e\u003ca href=\"/posts/instruction-by-design/#benefits-of-instruction-by-design\" title=\"Benefits of Instruction by Design\"\u003eBenefits of Instruction by Design\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eConsistency:\u003c/strong\u003e Every team member and AI agent follows the same standards, reducing drift and confusion\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eClarity:\u003c/strong\u003e Clear, actionable instructions eliminate ambiguity and ensure everyone knows what’s expected\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAutomation:\u003c/strong\u003e AI Code Assistant can enforce decisions in real time, catching issues before they become problems\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEvolution:\u003c/strong\u003e As projects grow, ADRs evolve with them—ensuring that architectural intent remains clear and actionable\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"conclusion-transform-your-adrs-today\"\u003e\u003ca href=\"/posts/instruction-by-design/#conclusion-transform-your-adrs-today\" title=\"Conclusion: Transform Your ADRs Today\"\u003eConclusion: Transform Your ADRs Today\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eInstruction by Design is a game-changer for how we think about architectural decision records. By transforming ADRs into actionable, AI-ready guidance, we bridge the gap between architectural intent and daily practice.\nNo more passive documentation—now your ADRs actively shape how your teams work, ensuring consistency, clarity, and quality across every project.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDon’t just document. Operationalize.\u003c/strong\u003e - Turn your ADRs into active guides for your people and your tools—because real progress comes from decisions you actually use. \u003cstrong\u003eReady to transform your ADRs?\u003c/strong\u003e\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-07-15T10:30:00+02:00","id":"https://daily-devops.net/posts/instruction-by-design/","language":"en","summary":"Transform architectural decision records (ADRs) into actionable AI guidance for enhanced team consistency, streamlined onboarding, and automated workflows.","tags":["ai-code-assistant","architecture","bestpractices","github","github-copilot","rcda","softwareengineering","technicaldebt"],"title":"Instruction by Design: Transforming ADRs into Actionable AI Guidance","url":"https://daily-devops.net/posts/instruction-by-design/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn software development, there’s a silent debt that accrues interest over time, often hidden beneath layers of code and decisions made in haste or ignorance. This debt is aptly termed \u003cem\u003etechnical debt\u003c/em\u003e. Much like the german proverb, \u003cem\u003e\u0026ldquo;Wer den Pfennig nicht ehrt, ist den Taler nicht wert\u0026rdquo;,\u003c/em\u003e (or the english equivalent, \u003cem\u003e\u0026ldquo;A penny saved is a penny earned\u0026rdquo;\u003c/em\u003e) technical debt reminds us that small oversights or compromises in the present can snowball into significant challenges down the road. This article critically examines the parallels between financial principles and technical debt, emphasizing the importance of addressing both direct and indirect debt while understanding its distinction from external risks such as hacking or abuse.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"understanding-technical-debt-an-analogy-to-finance\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#understanding-technical-debt-an-analogy-to-finance\" title=\"Understanding Technical Debt: An Analogy to Finance\"\u003eUnderstanding Technical Debt: An Analogy to Finance\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAt its core, technical debt is a metaphor borrowed from finance. When developers take shortcuts—perhaps by writing suboptimal code or delaying refactoring—they incur a \u0026ldquo;debt\u0026rdquo; that must eventually be \u0026ldquo;repaid\u0026rdquo; through additional effort, time, and resources. Like monetary debt, technical debt accumulates interest in the form of maintenance overhead, slower development cycles, and reduced system stability.\u003c/p\u003e\n\u003cp\u003eIn financial terms, there are two types of debt:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eGood Debt\u003c/strong\u003e: Investments like mortgages or education loans, where borrowing yields long-term benefits.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBad Debt\u003c/strong\u003e: High-interest loans or credit card balances, where borrowing becomes a perpetual burden.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSimilarly, technical debt can be intentional or unintentional:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eIntentional Technical Debt\u003c/strong\u003e: Decisions made knowingly to meet deadlines or prioritize feature delivery. This is akin to taking a calculated loan with the intention to repay soon.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnintentional Technical Debt\u003c/strong\u003e: Debt accrued due to lack of knowledge, poor design, or inadequate code reviews. This resembles bad debt—unplanned and harmful over time.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"intentional-vs-unintentional-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#intentional-vs-unintentional-technical-debt\" title=\"Intentional vs. Unintentional Technical Debt\"\u003eIntentional vs. Unintentional Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eNot all technical debt is created equal. To fully grasp its impact, it’s critical to differentiate between \u003cstrong\u003eintentional\u003c/strong\u003e and \u003cstrong\u003eunintentional\u003c/strong\u003e technical debt.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"intentional-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#intentional-technical-debt\" title=\"Intentional Technical Debt\"\u003eIntentional Technical Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis is the visible and measurable debt—the code shortcuts, hardcoded values, or outdated libraries. Developers know it exists and can point to it with precision. Examples include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSkipping unit tests to deliver a feature faster.\u003c/li\u003e\n\u003cli\u003eWriting non-optimized SQL queries.\u003c/li\u003e\n\u003cli\u003eUsing deprecated APIs for quicker implementation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDirect technical debt is like borrowing a small sum with a clear repayment plan. The problem arises when repayment is delayed, leading to compounding interest.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"indirect-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#indirect-technical-debt\" title=\"Indirect Technical Debt\"\u003eIndirect Technical Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis is the hidden debt that manifests indirectly over time, often as a consequence of direct debt or systemic issues. Examples include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePoorly documented code leading to knowledge silos.\u003c/li\u003e\n\u003cli\u003eOutdated infrastructure that becomes harder to replace.\u003c/li\u003e\n\u003cli\u003eAccumulated complexity that slows innovation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIndirect debt is insidious—it’s harder to quantify and often only becomes apparent when the system begins to falter.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-compound-interest-effect-in-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#the-compound-interest-effect-in-technical-debt\" title=\"The Compound Interest Effect in Technical Debt\"\u003eThe Compound Interest Effect in Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eA defining feature of both financial and technical debt is \u003cem\u003ecompound interest\u003c/em\u003e. In software, this translates to the exponential growth of effort required to address issues as they remain unresolved.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"financial-analogy-the-power-of-compound-interest\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#financial-analogy-the-power-of-compound-interest\" title=\"Financial Analogy: The Power of Compound Interest\"\u003eFinancial Analogy: The Power of Compound Interest\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn finance, compound interest is a double-edged sword. For savings, it’s a wealth generator. For debt, it’s a destroyer. A $1,000 credit card balance at 20% annual interest, left unpaid, grows to over $6,000 in just 10 years.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"technical-debts-compound-interest\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#technical-debts-compound-interest\" title=\"Technical Debt’s Compound Interest\"\u003eTechnical Debt’s Compound Interest\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn technical systems, unresolved debt compounds in the following ways:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eIncreased Maintenance Costs\u003c/strong\u003e: Every new feature or bug fix becomes harder to implement in a convoluted codebase.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTeam Productivity Decline\u003c/strong\u003e: Developers spend more time deciphering old code instead of writing new features.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHigher Failure Risk\u003c/strong\u003e: Overloaded systems are more prone to bugs and outages.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eFor instance, ignoring outdated dependencies today might seem trivial, but in a year, these dependencies could cause compatibility issues that require a complete system overhaul.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-financial-mindset-paying-off-debt-wisely\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#the-financial-mindset-paying-off-debt-wisely\" title=\"The Financial Mindset: Paying Off Debt Wisely\"\u003eThe Financial Mindset: Paying Off Debt Wisely\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo manage technical debt effectively, developers and stakeholders need to adopt a financial mindset, considering concepts like \u003cstrong\u003eamortization\u003c/strong\u003e, \u003cstrong\u003eprincipal repayment\u003c/strong\u003e, and \u003cstrong\u003erisk assessment\u003c/strong\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"amortization-gradual-repayment\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#amortization-gradual-repayment\" title=\"Amortization: Gradual Repayment\"\u003eAmortization: Gradual Repayment\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eAmortization is the process of gradually paying off a debt over time. In technical debt terms, this means allocating time in each sprint or release to tackle existing debt. For example:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrincipal\u003c/strong\u003e: Refactor key modules incrementally.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInterest\u003c/strong\u003e: Address bugs and performance issues caused by the debt.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"cost-benefit-analysis\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#cost-benefit-analysis\" title=\"Cost-Benefit Analysis\"\u003eCost-Benefit Analysis\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEvery debt repayment decision should involve a cost-benefit analysis. Ask questions like:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhat’s the effort required to fix this debt?\u003c/li\u003e\n\u003cli\u003eWhat’s the risk of leaving it unresolved?\u003c/li\u003e\n\u003cli\u003eWill repaying it now unlock future opportunities?\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"debt-consolidation-strategic-prioritization\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#debt-consolidation-strategic-prioritization\" title=\"Debt Consolidation: Strategic Prioritization\"\u003eDebt Consolidation: Strategic Prioritization\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn finance, consolidating loans simplifies repayment. Similarly, technical debt can be \u0026ldquo;consolidated\u0026rdquo; by identifying the most critical areas to address first. Focus on high-impact debt—areas where small fixes can yield significant improvements.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"external-risks-are-not-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#external-risks-are-not-technical-debt\" title=\"External Risks Are Not Technical Debt\"\u003eExternal Risks Are Not Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIt’s essential to distinguish technical debt from external risks such as hacking, misuse, or other security vulnerabilities. While they may share some consequences, the root causes and solutions differ.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"differences-in-scope\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#differences-in-scope\" title=\"Differences in Scope\"\u003eDifferences in Scope\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eAspect\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eTechnical Debt\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eExternal Risks\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eOrigin\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eInternal decisions or shortcuts\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eExternal threats or bad actors\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eControl\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eFully within the development team’s control\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePartially or entirely external\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eMitigation\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eRefactoring, tests, documentation\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSecurity protocols, firewalls, monitoring\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\n\n\u003ch3 id=\"overlap-when-risks-become-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#overlap-when-risks-become-debt\" title=\"Overlap: When Risks Become Debt\"\u003eOverlap: When Risks Become Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eOccasionally, external risks can create technical debt. For example, failing to patch a known vulnerability due to resource constraints incurs a debt that compounds if the system is exploited.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"a-self-reflective-look-where-we-fall-short\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#a-self-reflective-look-where-we-fall-short\" title=\"A Self-Reflective Look: Where We Fall Short\"\u003eA Self-Reflective Look: Where We Fall Short\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAs developers, we often rationalize technical debt. We promise to revisit a quick fix later or assume that future teams will handle the mess we leave behind. These assumptions are rarely true. In reality:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eShort-Term Thinking Prevails\u003c/strong\u003e: Deadlines often take precedence over quality, leading to rushed decisions.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDebt Is Underestimated\u003c/strong\u003e: Teams often misjudge the time and effort required to repay debt.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStakeholders Lack Awareness\u003c/strong\u003e: Non-technical stakeholders may not understand the implications of debt, leading to underinvestment in addressing it.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis self-critique is not to assign blame but to encourage accountability. We must recognize our role in creating and perpetuating debt, as well as our power to mitigate it.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"honoring-the-penny-practical-steps-forward\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#honoring-the-penny-practical-steps-forward\" title=\"Honoring the Penny: Practical Steps Forward\"\u003eHonoring the Penny: Practical Steps Forward\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo honor the \u0026ldquo;penny\u0026rdquo; of technical debt and avoid losing the \u0026ldquo;dollar\u0026rdquo; of system stability, consider the following practices:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eTrack Debt Transparently\u003c/strong\u003e: Use tools to log and prioritize technical debt alongside feature development.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eImplement Governance\u003c/strong\u003e: Establish policies for code quality, testing, and documentation to minimize unintentional debt.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEducate Stakeholders\u003c/strong\u003e: Communicate the cost of debt in terms stakeholders understand—time, money, and risk.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCelebrate Refactoring\u003c/strong\u003e: Make debt repayment a visible and celebrated part of your team’s work.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAutomate Debt Detection\u003c/strong\u003e: Use static analysis tools to identify debt early in the development process.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEncourage Ownership\u003c/strong\u003e: Empower developers and operations to take responsibility for the debt they create and resolve it proactively.\u003c/li\u003e\n\u003c/ol\u003e\n\n\n\n\n\u003ch2 id=\"conclusion\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#conclusion\" title=\"Conclusion\"\u003eConclusion\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe proverb \u003cem\u003e\u0026ldquo;Wer den Pfennig nicht ehrt, ist den Taler nicht wert\u0026rdquo;\u003c/em\u003e teaches us the value of small, consistent actions. In software development, this wisdom is crucial for managing technical debt. By respecting the pennies—addressing small issues promptly and intentionally—we can avoid the compound interest that turns minor debts into major crises.\u003c/p\u003e\n\u003cp\u003eAs stewards of our systems, let us commit to honoring the pennies of our craft, ensuring that our codebases remain worthy of the dollars they aim to generate.\u003c/p\u003e\n","date_modified":"2026-05-25T23:10:21+02:00","date_published":"2024-11-22T16:45:00+01:00","id":"https://daily-devops.net/posts/tale-of-forgotten-pennies-and-lost-dollars/","language":"en","summary":"Discover how small technical debts accumulate into major project costs and learn strategies to manage them effectively in software development.","tags":["technicaldebt","bestpractices","dependency-management","rcda","softwareengineering"],"title":"A Tale of Forgotten Pennies and Lost Dollars","url":"https://daily-devops.net/posts/tale-of-forgotten-pennies-and-lost-dollars/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eWhatever our role, be it developer, IT professional or architect, we try to avoid technical debt. If this is not possible from the outset, or if we decide to accept this technical debt for a limited period of time, we usually lack the tools to do so. This is where this article may help.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"what-is-technical-debt\"\u003e\u003ca href=\"/posts/illuminate-technical-debt/#what-is-technical-debt\" title=\"What is technical debt?\"\u003eWhat is technical debt?\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTechnical debt is a metaphor used to describe the costs and risks incurred as a result of decisions or omissions. It is important to note that this metaphor can be applied to all types of technical debt.\u003c/p\u003e\n\u003cp\u003eFirst, there is \u003cstrong\u003earchitectural debt\u003c/strong\u003e, which is usually based on a decision made by an individual architect or group of architects. Then there is \u003cstrong\u003eimplementation debt\u003c/strong\u003e, which is probably the most common in most projects, as it is also identified through source code analysis. And then there is the \u003cstrong\u003etest\u003c/strong\u003e and \u003cstrong\u003edocumentation\u003c/strong\u003e debt, which is far too often neglected.\u003c/p\u003e\n\u003cp\u003e\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003cfigure class=\"responsive\"\u003e\n  \u003cpicture\u003e\n    \n      \n      \n    \n    \u003cimg\n      src=\"/images/what-colors-is-your-backlog-kruchten.svg?v=cbed4f593fdd5d7d97b708ff8f33da51\"\n      alt=\"What colors is your backlog?\"\n      loading=\"lazy\"\n      \n      decoding=\"async\"\n      width=\"1444\" height=\"1444\"\n      title=\"Phillipe Kruchten - https://pkruchten.files.wordpress.com/2012/07/kruchten-110707-what-colours-is-your-backlog-2up.pdf\"\n      copyright=\"Phillipe Kruchten - https://pkruchten.files.wordpress.com/2012/07/kruchten-110707-what-colours-is-your-backlog-2up.pdf\" /\u003e\n  \u003c/picture\u003e\n  \n  \u003cfooter\u003e\u003csmall\u003ePhillipe Kruchten - https://pkruchten.files.wordpress.com/2012/07/kruchten-110707-what-colours-is-your-backlog-2up.pdf\u003c/small\u003e\u003c/footer\u003e\n  \n  \n\u003c/figure\u003e\n\nWhatever the type of technical debt, the common denominator is that it tends to cause problems in projects and later in operations. In July 2011, Phillipe Kruchten described them as \u0026ldquo;invisible negative elements in the backlog\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eHowever, they are rarely recorded and visualized.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"how-can-i-still-make-them-visible\"\u003e\u003ca href=\"/posts/illuminate-technical-debt/#how-can-i-still-make-them-visible\" title=\"How can I still make them visible?\"\u003eHow can I still make them visible?\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIn most projects, it is individuals or a small group of individuals who are aware of individual Technical Debts. However, these projects usually have another thing in common: when these technical debts are addressed, they are postponed or even dismissed.\u003c/p\u003e\n\u003cp\u003eTo avoid this, Technical Debts need to be tracked in the same way as requirements or defects. All you need is a person with administrative rights in Azure DevOps or comparable platforms.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"extension-of-the-azure-devops-process-templates\"\u003e\u003ca href=\"/posts/illuminate-technical-debt/#extension-of-the-azure-devops-process-templates\" title=\"Extension of the Azure DevOps process templates\"\u003eExtension of the Azure DevOps process templates\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAzure DevOps provides the ability to visualize technical debt by extending process templates. The Microsoft article [Customize a process template] (\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/reference/process-templates/customize-process?view=azure-devops\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003ehttps://learn.microsoft.com/en-us/azure/devops/reference/process-templates/customize-process?view=azure-devops\u003c/a\u003e) details how to inherit and extend a process template to achieve the following result.\u003c/p\u003e\n\u003cp\u003e\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003cfigure class=\"responsive\"\u003e\n  \u003cpicture\u003e\n    \n      \n        \n        \n\n        \n          \n        \n\n        \n\n        \n        \n\n        \n        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-544x111.webp?v=8d9af73128053bf12e79a9a910bdec83\"\n  type=\"image/webp\"\n  media=\" (max-width: 575.98px)\" /\u003e\n  \n  \n\n\n\n\n\n\n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-544x111.png?v=f138a1d35f81eb1c94e190694d99c3be\"\n  type=\"image/png\"\n  media=\" (max-width: 575.98px)\" /\u003e\n  \n  \n\n\n\n\n        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-672x137.webp?v=f77240208a267ede01ad7ba67d8111fa\"\n  type=\"image/webp\"\n  media=\" (max-width: 767.98px)\" /\u003e\n  \n  \n\n\n\n\n\n\n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-672x137.png?v=c62698be0bfc91fdaaa7dce809015f72\"\n  type=\"image/png\"\n  media=\" (max-width: 767.98px)\" /\u003e\n  \n  \n\n\n\n\n        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-896x182.webp?v=301a2d3e0dc3d923117bae4e1d24d94e\"\n  type=\"image/webp\"\n  media=\" (max-width: 991.98px)\" /\u003e\n  \n  \n\n\n\n\n\n\n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-896x182.png?v=c61cf536954ee7ebb57a90f5933cbc27\"\n  type=\"image/png\"\n  media=\" (max-width: 991.98px)\" /\u003e\n  \n  \n\n\n\n\n        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-1104x224.webp?v=ba7177e89e0191052e1f13719f93da32\"\n  type=\"image/webp\" /\u003e\n  \n  \n\n\n\n\n\n\n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-process-templates-1104x224.png?v=b6ef52b236efe2029b6041fe258dc5ee\"\n  type=\"image/png\" /\u003e\n  \n  \n\n\n\n\n        \n\n\n\n\n\n\n      \n      \n    \n    \u003cimg\n      src=\"/posts/illuminate-technical-debt/azure-devops-process-templates.png?v=07ef92b07b784fd85b4eb91ec33eddf1\"\n      alt=\"Azure DevOps Prozess Templates Erweiterung\"\n      loading=\"lazy\"\n      \n      decoding=\"async\"\n      width=\"1444\" height=\"1444\"\n      \n       /\u003e\n  \u003c/picture\u003e\n  \n  \n\u003c/figure\u003e\n\u003c/p\u003e\n\u003cp\u003eIn this case, the extended process templates AgileRCDA and ScrumRCDA were simply extended by an additional WorkItem type, which will be used in the future to record and visualize technical debt. In 2011, Kruchten already used the color black for the color scheme of technical debt.\n\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003cfigure class=\"responsive\"\u003e\n  \u003cpicture\u003e\n    \n      \n        \n        \n\n        \n          \n        \n\n        \n\n        \n        \n\n        \n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n      \n      \n    \n    \u003cimg\n      src=\"/posts/illuminate-technical-debt/azure-devops-workitem-technical-debt.png?v=cf328b57fb1eb531943745c3671c492f\"\n      alt=\"WorkItem Type: Technical Debt\"\n      loading=\"lazy\"\n      \n      decoding=\"async\"\n      width=\"1444\" height=\"1444\"\n      \n       /\u003e\n  \u003c/picture\u003e\n  \n  \n\u003c/figure\u003e\n\u003c/p\u003e\n\u003cp\u003eFor later prioritization and sorting, it is advisable to pass additional parameters to the WorkItem type, such as\n\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003cfigure class=\"responsive\"\u003e\n  \u003cpicture\u003e\n    \n      \n        \n        \n\n        \n          \n        \n\n        \n\n        \n        \n\n        \n        \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-workitem-technical-debt-settings-544x145.webp?v=fab732c602641b73883dce8c1b304a4c\"\n  type=\"image/webp\" /\u003e\n  \n  \n\n\n\n\n\n\n  \n  \n\u003csource\n  srcset=\"/posts/illuminate-technical-debt/azure-devops-workitem-technical-debt-settings-544x145.png?v=ed5e00c199145fa56e8ffeeb123a1865\"\n  type=\"image/png\" /\u003e\n  \n  \n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n        \n\n\n\n\n\n\n      \n      \n    \n    \u003cimg\n      src=\"/posts/illuminate-technical-debt/azure-devops-workitem-technical-debt-settings.png?v=7e567c600ecc2d9fe97aa179a4779f95\"\n      alt=\"WorkItem-Typ: Technical Debt - Settings\"\n      loading=\"lazy\"\n      \n      decoding=\"async\"\n      width=\"1444\" height=\"1444\"\n      \n       /\u003e\n  \u003c/picture\u003e\n  \n  \n\u003c/figure\u003e\n\u003c/p\u003e\n\u003cp\u003eThis creates the technical foundation based on the process templates, and within the project only the technical debt type work items need to be recorded.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"summary\"\u003e\u003ca href=\"/posts/illuminate-technical-debt/#summary\" title=\"Summary\"\u003eSummary\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe Azure DevOps extension (or alternative platforms) presented here takes only a few minutes to extend and deploy. But it will have the desired effect by the next sprint meeting. That\u0026rsquo;s because the black work items of the \u0026ldquo;technical debt\u0026rdquo; type quickly give the impression of a tombstone and provide the necessary visibility.\u003c/p\u003e\n\u003cp\u003eDon\u0026rsquo;t be surprised if the tombstones start to pile up after a few weeks. Your colleagues and team members know about other Technical Debts that you probably haven\u0026rsquo;t noticed yet.\u003c/p\u003e","date_modified":"2026-05-25T22:16:53+02:00","date_published":"2023-04-12T17:00:00+02:00","id":"https://daily-devops.net/posts/illuminate-technical-debt/","language":"en","summary":"Learn how to make technical debt visible, measurable, and manageable using platforms like Azure DevOps with practical tools, metrics, and strategies.","tags":["azuredevops","extensions","rcda","technicaldebt"],"title":"Illuminate Technical Debt with .NET Analyzers \u0026 Metrics","url":"https://daily-devops.net/posts/illuminate-technical-debt/"}],"language":"en","title":"Risk and Cost Driven Architecture (RCDA) on Daily DevOps \u0026 .NET","version":"https://jsonfeed.org/version/1.1"}