.NET Lessons from the Pit
I’ve been doing .NET since Framework 4 days. Spent 13 years in the trenches, banking systems, insurance platforms, teams that made decisions under pressure. This is what stuck.
Code reviews: the real teaching tool
I learned this the hard way early on. I didn’t always handle code reviews well: I’d focus on what was wrong instead of why it mattered. Then it clicked: instead of “This is wrong,” ask “Why did you choose this pattern?” and explain the trade-off. “IAsyncEnumerable streams results instead of loading everything into memory: matters at scale.” That changed everything for me.
When I made that shift, code reviews became conversations instead of gates. It took me years to realize that teaching why worked better than pointing out mistakes.
Standards: agree once, argue never
Every team I’ve joined argues about braces, naming, spacing. The fix is brutal in its simplicity: decide together, then automate it away.
I’ve shipped .editorconfig files that ended the debate. Roslyn analysers caught the quality stuff (CA rules that actually matter). dotnet format in CI caught the drift. After that, code reviews became about logic and design, not formatting.
The difference in morale is real. Developers stop defending their style choices and start thinking about architecture.
Developer experience wins quietly
I’ve been on teams where slow builds quietly killed morale, and I didn’t always push hard enough to fix it fast enough.
Fast CI pipelines (parallelized tests, cached NuGet, incremental builds), clean local setup (Docker Compose for your database, seed scripts that work), structured logging with Serilog, health endpoints, these aren’t nice-to-haves. They’re the difference between a team shipping and a team burning out.
I’ve seen organizations spend months tuning architecture and ignore the fact that their developers hate opening their laptops.
Microservices: I’ve seen this movie
I’ve been on projects where we jumped to microservices too soon, and I felt the pain of that firsthand. All the distributed systems complexity (network failures, eventual consistency, debugging nightmares) without the benefits.
Start with a modular monolith. Build it right, separate assemblies per domain, clear module boundaries, testable internal APIs. If you can’t structure a single codebase, you can’t structure a hundred services. Extract microservices only when domain boundaries are proven and operationally, you have the team for it.
The patterns that wreck teams
I’ve felt the drag of distributed complexity without the payoff. I’ve been in code reviews that turned punitive, where I gave feedback that felt like judgment instead of care, and I watched developers stop taking risks.
I’ve lived through teams bogged down because we didn’t automate standards, so every review was a formatting debate. I’ve seen good people quiet down or leave because local development hurt and I didn’t push hard enough to fix it.
I’ve mentored wrong too, pushed autonomy on someone who needed pairing, or treated a senior like they needed oversight. These lessons stick because they cost something.
Hard-won
Ship smaller. Write tests for code that scares you. Learn fundamentals before framework-chasing. Your team’s growth matters more than your hero output.
These aren’t theories. These are scars.
Happy coding!
Key takeaways
- Code reviews teach better when you explain the why behind decisions and trade-offs instead of just pointing out mistakes
- Automate away style debates with editorconfig, formatters, and analyzers so code reviews focus on logic and design instead of formatting
- Fast builds, clean local setup, and good logging have a multiplier effect on team morale and shipping velocity that outweighs architecture decisions
- Start with a modular monolith with clear boundaries between domains, then extract microservices only when you’ve proven the split is necessary
- Ship smaller batches, write tests for code that scares you, and invest in team growth because your people matter more than hero output
Happy Coding! 🎉