40 Lessons I Learned in 12 Years as a .NET Developer
Forty honest, beginner-friendly lessons from 12 years of .NET work, covering C#, EF Core, testing, deployment, teamwork, and a calm career.
A quick story before the lessons
Imagine you are learning to cook in your home kitchen. On day one you burn the rice. You add too much salt. You cut your finger a little. But you keep cooking. After a few years, you do not even look at the recipe. Your hands just know.
Writing software is the same. Nobody is born knowing it. You learn by making small mistakes, again and again, until the mistakes become wisdom.
I have spent twelve years writing .NET code. I started scared and confused. I am still learning today. Below are forty lessons I wish someone had handed me on my first day. They are simple. They are honest. And a careful twelve-year-old can follow most of them.
Let me show you how a small daily habit grows into real skill.
Lessons about code (the C# itself)
1. Names matter more than you think. A variable called d tells nobody anything. daysUntilExpiry tells the whole story. Good names are free documentation.
2. Small methods are easier to trust. If a method does not fit on your screen, it is probably doing two jobs. Split it.
3. null is the source of most bugs. Turn on nullable reference types. The compiler will warn you before your users do.
#nullable enable
// The compiler now warns you here, because GetName might return null.
string? name = user.GetName();
Console.WriteLine(name.Length); // warning: possible null
// Safer:
Console.WriteLine(name?.Length ?? 0);4. Prefer var only when the type is obvious. var total = 0; is fine. var x = Process(); hides too much.
5. Learn LINQ early, but read what it does. LINQ is lovely. It can also hide slow loops. Know when a query touches the database and when it runs in memory.
6. Records are great for data that does not change. They give you equality and a clean shape for free.
7. Use new C# features, but do not chase every one. C# 14 added field-backed properties and nicer extension members. They are useful. Still, a clear if statement beats a clever one-liner you cannot read next month.
8. async all the way, or not at all. Mixing blocking calls like .Result with async code causes deadlocks. Pick one path.
9. Exceptions are for the unexpected. Do not use them for normal flow, like "user not found." That is slow and confusing.
10. Delete dead code. If it is commented out, your git history already keeps it. Remove it.
Here is how a single request flows through a typical .NET app. Knowing this map makes debugging far calmer.
Lessons about data and EF Core
11. The database is usually the slow part. Most "my app is slow" problems are really "my query is slow."
12. Beware the N+1 query. Looping over a list and hitting the database each time is a classic trap. Load what you need in one go.
// ❌ N+1: one query for orders, then one query per order for its customer
var orders = await db.Orders.ToListAsync();
foreach (var o in orders)
Console.WriteLine(o.Customer.Name); // hidden query each loop!
// ✅ One query that brings the customer along
var orders = await db.Orders
.Include(o => o.Customer)
.ToListAsync();13. Use AsNoTracking() for read-only data. If you are only showing data, you do not need EF Core to watch it for changes. It is faster.
14. Never trust user input near SQL. Use parameters. EF Core does this for you, so do not glue raw strings together.
15. Migrations are your friend, but review them. Always open the generated migration and read it before running it on real data.
16. Back up before you change production data. This lesson cost me a long, scary night once. Learn it the cheap way.
Here is a simple table of EF Core habits and why they help.
| Habit | Why it helps |
|---|---|
AsNoTracking() on reads | Less memory, faster queries |
Include() for related data | Avoids N+1 queries |
| Review migrations | Catches accidental data loss |
| Index your filter columns | Database finds rows quickly |
Avoid SELECT * patterns | Move less data over the wire |
Lessons about testing
17. A test you trust lets you sleep. When tests pass, you can change code without fear.
18. Test behavior, not the inside. Check what the method returns, not which private field it set.
19. Start with the simple cases. Empty list. Null input. Zero. Bugs love these corners.
[Fact]
public void Discount_Is_Zero_When_Cart_Is_Empty()
{
var cart = new Cart(); // no items
var discount = cart.CalculateDiscount();
Assert.Equal(0m, discount);
}20. Slow tests get skipped. If the suite takes ten minutes, people stop running it. Keep most tests fast.
21. One assert idea per test. A test should fail for one clear reason.
22. Do not test the framework. You do not need to test that EF Core saves a row. Trust the tools. Test your own logic.
Lessons about building and shipping
This is the part beginners fear most. Let me lay out a calm release flow.
A Safe Release Flow
Steps
Code
Write on a branch, not on main
Pull Request
A teammate reviews your change
CI Tests
The build runs all tests automatically
Staging
Try it in a safe copy of production
Production
Release in small, reversible steps
23. Automate the build. If shipping needs ten manual steps, one will be forgotten. Let a pipeline do it.
24. Small releases are safer than big ones. A tiny change is easy to undo. A giant change is a guessing game when it breaks.
25. Always have a way back. Know how to roll back before you roll forward.
26. Read your logs. Good logging is like leaving footprints. When something breaks at 2 a.m., footprints save you.
27. Configuration does not belong in code. Keep secrets and settings outside the source. Never commit a password.
28. Measure before you optimize. "I think this is slow" is a guess. A profiler gives you the truth. Fix the real hot spot, not the imagined one.
Here is how problems get cheaper to fix the earlier you catch them.
Cost of a Bug Over Time
Steps
While Typing
Almost free; the compiler tells you
In Review
Cheap; a teammate spots it
In Tests
Still cheap; caught before users
In Production
Expensive; users and trust are hurt
Lessons about tools and the ecosystem
29. Stay on supported versions. .NET 10 is the current LTS release with three years of support. Old, unsupported versions stop getting security fixes. Plan upgrades early, not in a panic.
30. Pick libraries carefully. A library is a long-term marriage, not a quick chat.
31. Watch the license, not just the features. Some popular tools changed their rules. For example, MediatR and MassTransit are now commercially licensed for many uses. They are still good, but check the cost and terms before you depend on them in a big project.
32. You do not need a library for everything. Sometimes ten lines of your own code beats a heavy dependency you must keep updated.
33. Learn your debugger. Breakpoints, stepping, and watching variables will teach you more than a hundred print statements.
34. The docs are usually right. Microsoft Learn is free and accurate. Read it before searching random blogs.
Here is a comparison of a few choices you will make often.
| Choice | Good when | Be careful when |
|---|---|---|
| A big library | It solves a hard, common problem | Its license or size grows costly |
| Your own code | The task is small and specific | It becomes complex and untested |
| Newest .NET version | You want speed and new features | You are mid-project and stable |
| Microservices | Teams and scale are large | Your app is still small and simple |
Lessons about people and yourself
This is the half nobody tells beginners. Software is built by humans.
35. Ask questions early. Being stuck quietly for a day helps no one. A good question is a sign of strength, not weakness.
36. Code review is a gift, not an attack. When a teammate marks up your code, they are protecting the product and teaching you. Say thank you.
37. Write for the next person. The next person reading your code might be you, six months from now, tired and forgetful. Be kind to that person.
38. Rest is part of the work. Tired brains write buggy code. A walk often solves the problem a long night could not.
39. You will never know everything, and that is fine. Twelve years in, I still Google basic things. The goal is not to memorize. The goal is to know how to find out.
40. Be patient with yourself. Every expert was once a beginner who burned the rice. Keep cooking.
Let me show how these soft skills and hard skills grow together over a career.
How a beginner should use this list
You do not need to apply all forty lessons today. That would be too much, like trying to learn every spice on the first day of cooking.
Pick three. Maybe lesson 3 (turn on nullable), lesson 12 (avoid N+1), and lesson 35 (ask questions early). Practice those for a month. Then come back and pick three more.
Skill is not a single jump. It is many small steps, repeated with care. The compiler will catch you. Your tests will protect you. Your teammates will guide you. And one day you will look back and realize your hands just know.
Quick recap
- Software skill grows from many small mistakes, like learning to cook.
- Clear names, small methods, and
asyncdiscipline make code easy to trust. - The database is often the slow part; watch out for the N+1 query.
- Tests you trust let you change code without fear, so keep them fast.
- Automate your build, ship small, and always keep a way to roll back.
- Stay on supported versions like .NET 10 LTS, and check library licenses (note: MediatR and MassTransit are now commercially licensed).
- People skills matter as much as code: ask early, welcome reviews, and rest.
- Be patient. Pick three lessons, practice, then pick three more.
References and further reading
- What's new in .NET 10 (Microsoft Learn)
- What's new in C# 14 (Microsoft Learn)
- .NET 10 ships as LTS with Visual Studio 2026 (The Register)
- C# 14 new features: a developer guide (Dirk Strauss)
Related Posts
SOLID Principles in C# and .NET: A Beginner-Friendly Guide
Learn the 5 SOLID principles in C# and .NET with simple words, real-life examples, diagrams, and clean code you can copy and try yourself today.
Clean Architecture Folder Structure in .NET: A Simple Guide
Learn how to organise a .NET solution with Clean Architecture. Understand the Domain, Application, Infrastructure, and Presentation layers, the dependency rule, and the exact folders, with diagrams and examples.
Vertical Slice Architecture in .NET: The Easy Guide
Learn Vertical Slice Architecture in .NET in simple words. Organise code by feature instead of by layer, with diagrams, real examples, a comparison with Clean Architecture, and when to use each.
8 Tips to Write Clean Code in C# and .NET
Learn 8 simple, beginner-friendly tips to write clean C# and .NET code with clear names, small methods, good error handling, and easy-to-read structure.
Top 10 Things Every .NET Developer Needs to Do in 2026
A warm, beginner-friendly checklist of the 10 most useful habits and skills every .NET developer should pick up in 2026, with .NET 10 and C# 14.
How to Write Better and Cleaner Code in .NET
A beginner-friendly guide to writing better, cleaner C# and .NET code using clear names, small methods, modern C# 14 features, and simple structure.