Clean Code, Testing & Best Practices
What it is & where it is used
Clean code is code that other people can read, change and trust. Interviews for mid and senior roles check whether you write maintainable code, test it, review others' code and follow team practices (Git flow, CI, logging, security).
Core ideas, from Robert C. Martin's Clean Code (2008), Martin Fowler's Refactoring (1999, 2nd ed. 2018) and Kent Beck's Test-Driven Development (2002):
- Code is read far more often than it is written — optimise for the reader.
- Small, focused functions and classes with intention-revealing names.
- Tests are part of the code, not an afterthought.
- Leave the code cleaner than you found it (the "Boy Scout rule").
Versions & history
| Year | Milestone |
|---|---|
| 1999 | Fowler, Refactoring (code smells catalogue); Beck, Extreme Programming Explained |
| 2002 | Beck, Test-Driven Development: By Example |
| 2004 | Feathers, Working Effectively with Legacy Code |
| 2007 | xUnit.net 1.0 released (by NUnit's original author) |
| 2008 | Martin, Clean Code |
| 2011 | Martin, The Clean Coder |
| 2018 | Refactoring 2nd edition |
| 2024 | xUnit v3 released; MSTest 3.x, NUnit 4 are current |
.NET analyzers: Roslyn analyzers ship in the SDK (<AnalysisLevel>latest</AnalysisLevel>), plus .editorconfig rules enforced at build.
Lifecycle
Code lifecycle in a team (typical Git + PR flow):
- Pick a ticket (Azure Boards/Jira) → create a branch
feature/1234-order-export. - Write a failing test (TDD) or write the code, then the tests.
- Run the analyzers, formatter (
dotnet format) and tests locally. - Commit small, meaningful commits; push; open a pull request.
- CI pipeline: build → unit tests → code coverage → static analysis (SonarQube) → security scan.
- Code review by 1–2 peers; address comments.
- Merge (squash) to
main; CD deploys to dev → QA → staging → production. - Monitor logs and metrics; fix bugs with a regression test first.
Test lifecycle (xUnit): for each test, a new instance of the test class is created (constructor = setup), the test runs, then Dispose() = teardown. Shared expensive setup uses IClassFixture<T> (per class) or collection fixtures (across classes).
Tools used to develop
| Area | Tools |
|---|---|
| Unit testing | xUnit, NUnit, MSTest |
| Mocking | Moq, NSubstitute, FakeItEasy |
| Assertions | Shouldly, FluentAssertions (v8+ needs a commercial licence) |
| Integration tests | WebApplicationFactory (Microsoft.AspNetCore.Mvc.Testing), Testcontainers, Respawn |
| Coverage | Coverlet, ReportGenerator, Visual Studio Enterprise |
| Static analysis | Roslyn analyzers, SonarQube/SonarCloud, ReSharper, StyleCop.Analyzers |
| Formatting | dotnet format, .editorconfig, CSharpier |
| Mutation testing | Stryker.NET |
| Architecture tests | NetArchTest, ArchUnitNET |
| Security | Dependabot, dotnet list package --vulnerable, GitHub Advanced Security, OWASP ZAP |