Software Engineering Principles and Practices

Software engineering is the practice that turns code into systems people can rely on. The distinction matters because typing code has never been easier — AI assistants produce syntactically valid output in seconds — yet the rate at which production systems fail, leak data, or quietly accumulate maintenance debt has not improved. The discipline lives in the gap between code that compiles and code that survives contact with reality.

The articles in this collection treat software engineering as a profession, not a productivity exercise. The recurring theme is the feedback loop: write code, watch it fail, understand why, refine thinking. That loop cannot be automated because closing it requires learning from production failures and applying that knowledge to prevent the next one. Prompt engineering optimizes for speed; engineering optimizes for survival under conditions the original author did not anticipate.

Topics range from defensive programming with ArgumentNullException.ThrowIfNull and guard-clause patterns, through structured logging that does not lie about what happened, to multi-framework targeting decisions that look harmless and quietly break the build on the third project that consumes the library. Clean Code is treated as a starting point rather than a creed — most teams that quote SOLID rarely apply it consistently, and the articles examine what actually works in production versus what looks defensible in code review.

A second cluster of articles addresses the economic reality. Technical debt compounds like financial debt, and small shortcuts become the dominant cost driver three years in. Retiring legacy projects, illuminating debt with analyzers, and recognizing when a refactor is cheaper than another feature release are covered with the trade-offs named explicitly.

The voice across these articles is opinionated and grounded in specific failures. Generic advice rarely changes behavior. Specific failure modes, named clearly, do.

Stop Pretending TimeProvider Doesn't Exist

Stop Pretending TimeProvider Doesn't Exist

DateTime.UtcNow looks harmless. It is not. It is a hidden dependency you cannot control in tests, cannot reproduce in staging, and cannot freeze to catch the bugs that only surface at midnight or on the last day of the month. .NET 8 shipped TimeProvider to fix this. Two years on, most codebases still ignore it. Some planned to adopt it later. Later has not arrived.
AI Code Review Is a Sycophant: Why It Always Approves

AI Code Review Is a Sycophant

AI code review tools are genuinely useful for catching syntax errors, obvious bugs, and common anti-patterns. They are also systematically unable to tell you that the feature you built was the wrong call, that the abstraction is off, that the naming reveals confused thinking, or that the correct review comment is “delete this.” Here is what AI reviews find, what they miss, and why human judgment still has no substitute.
Source Generators: The Build Performance Killer

Source Generator Costs

Source generators are powerful. They are also running on every single build, blocking IntelliSense, breaking Hot Reload, and multiplying their cost across every target framework you support. Nobody mentions this in the getting started guides. Here is how to measure the damage, find the culprits, and decide when source generators are actually worth it.
Purpose Limitation in API Design: Leaking Data You Shouldn't

Purpose Limitation in API Design: Leaking Data You Shouldn't

Most APIs expose personal data based on database entities, not caller needs. When a password reset endpoint returns a user’s full profile, purchase history, and marketing preferences, that’s purpose drift. This article shows how to restructure ASP.NET Core APIs around caller purposes using resource-based authorization, consent validation, and field-level access control.
Real Professional Software Engineering in the AI Era

Real Professional Software Engineering in the AI Era

Throughout this series, we’ve established that AI-generated code without understanding creates productivity illusions that collapse in production (Part 1), and that the feedback loop between code and reality—compilation, testing, profiling, production—sharpens thinking in ways AI can’t replicate (Part 2). Now we confront the practical question: What defines professional software engineering when code generation becomes trivial? This final part examines the irreplaceable skillset: understanding execution characteristics (recognizing allocation patterns that cause GC pressure before deployment), asking questions AI can’t formulate (What’s the failure mode when this service is unavailable?), recognizing when plausible AI solutions diverge from correct ones, debugging production failures AI has no execution model to reason about, and evaluating maintainability for code that becomes tomorrow’s burden. We explore why prompt engineering optimizes for speed while architecture optimizes for survival, why “AI productivity” often means faster technical debt accumulation, and why the economic reality favors organizations that measure system reliability over lines of code generated. The feedback loop can’t be automated because closing it requires learning from production failures and applying that knowledge to prevent future ones—the irreplaceable discipline that defines real professionals in 2026 and beyond.