As I've been working on my current project, I've found that many freshman developers who want to get better often have a hard time navigating the huge amount of resources out there to improve their skills. It's hard to commit given the cost of some of these books (usually at least $30 a pop) and the time it takes to make it through them if you don't know where to begin.
IMO, there are six books which are must reads for any serious .NET developer with aspirations for architecture (I'd probably recommend reading them in this order, too):
- Pro C# by Andrew Troelson which covers just enough about the CLR and the high level concepts in .NET programming with enough readability to not put you to sleep every time you crack it open. Even if you never use some of the features of the platform, it's important to know what's possible on the platform as it influences your design and implementation choices. While the "bookend" chapters aren't necessarily that great, the middle chapters are invaluable.
- Framework Design Guidelines by Cwalina and Abrams which provides a lot of insight into the guidelines that Microsoft implemented internally in designing the .NET framework. This is important for writing usable code, in general. I tend to think that all code that I write is -- on some level -- a framework (even if in miniature). Many otherwise tedious discussions on standards, naming, type/member design, etc. can be resolved by simply referencing this book as The Guideline.
- Design Patterns by GoF all too often, I come across terrible, terrible code where the original coder just goes nuts with if-else, switch-case statements...basic knowledge of how to resolve these issues leads to more maintainable and easier to read code. At the end of the day, design patterns are aimed at helping you organize your code into elements that are easier to understand conceptually, easier to read, easier to use, and easier to maintain. It's about letting the structure of your objects and the interactions between your objects dictate the flow of logic, not crazy, deeply nested conditional logic (I hope to never again see another 2000+ line method...yes, a single method).
- Patterns of Enterprise Application Architecture by Fowler My mantra that I repeat to clients and coworkers is that "it's been done before". There are very few design scenarios where you need to reinvent the wheel from the ground up. For business applications, many of the common patterns are documented and formalized in this book (to be paired with Design Patterns). This and Design Patterns are must reads for any developer that is seriously aspiring to be a technical lead or technical architect. As the .NET framework matures and we diverge from the legacy programming, understanding design patterns is becoming more important to grasping the benefits and liabilities of designs and frameworks. For high level technical resources, it's important to understand how to write "clean" code by designing around object interactions; design patterns document these commonly recurring interactions. It is also a vocabulary and set of conventions by which programmers can communicate intent and usage of complex graphs of objects.
- Code Complete 2nd Edition by McConnell While not C# or .NET specific, it delves into the deep nitty-gritty of the art of programming (and it's still very much an art/craft as opposed to a science). Too often, we lose sight of this core principle in our software construction process in our rush to "make it work", often leaving behind cryptic, unreadable, unmaintainable code. Some of the chapters in this book will definitely put you to sleep, but at the same time, it's filled with so much useful insight that it's worth trudging through this behemoth of a book.
- Pragmatic Unit Testing in C# by Hunt. This book, perhaps more than any of the ones listed above, gives a much more practical view of the how's and why's of good objected oriented design. Designing for testability intrinsically means creating decoupled modules, classes, and methods; it forces you to think about your object structure and interactions in a completely different mindframe. Test driven development/design is good to learn in and of itself, but I think the biggest thing I got from reading this book was insight into the small changes in code construction for the purpose of testability that yield big dividends in terms of decoupling your code modules. I think that once you read this book, you'll start to really understand what it means to write "orthogonal code".