New book: Adaptive Code via C#: Agile coding with design patterns and SOLID principles

Cover for Adaptive Code via C#We’re pleased to announce the availability of Adaptive Code via C#: Agile coding with design patterns and SOLID principles (ISBN 9780735683204), by Gary McLean Hall.

Purchase from these online retailers:

Microsoft Press Store
Barnes & Noble
Independent booksellers – Buy local

As every developer knows, requirements are subject to change. But when you build adaptability into your code, you can respond to change more easily and avoid disruptive rework. Focusing on Agile programming, this book describes the best practices, principles, and patterns that enable you to create flexible, adaptive code—and deliver better business value.

Expert guidance to bridge the gap between theory and practice

• Get grounded in Scrum: artifacts, roles, metrics, phases

• Organize and manage architectural dependencies

• Review best practices for patterns and anti-patterns

• Master SOLID principles: single-responsibility, open/closed, Liskov substitution

• Manage the versatility of interfaces for adaptive code

• Perform unit testing and refactoring in tandem

• See how delegation and abstraction impact code adaptability

• Learn best ways to implement dependency interjection

• Apply what you learn to a pragmatic, agile coding project

Get code samples at:

About the author
Gary McLean Hall lives in Manchester, England, with his wife, daughter, and dog. He is an experienced Microsoft .NET Framework developer specializing in patterns and practices. In his many years of contracting, he has worked on numerous Agile teams that have maintained a strict focus on creating code that is adaptive to change. He has worked for companies such as Eidos, Xerox, Nephila Capital Ltd., and The LateRooms Group. He has also run a software consultancy company for several years and lived and worked in Bermuda for three years. In each role, he excelled at balancing the delivery of a software product and the quality of its source code.


Here’s an excerpt from the book’s Introduction to share more details about the book, including a chapter-by-chapter description:


The title of this book, Adaptive Code, is a good description of the outcome of applying the principles in the book: the ability of code to adapt to any new requirement or unforeseen scenario while avoiding significant rework. The aim of this book is to aggregate many of the current best practices in the world of C# .NET programming into one volume. Although some of the content is covered in other books, those books either focus heavily on theory or are not specific to .NET development.

Programming can be a slow process. If your code is adaptive, you will be able to make changes to it more quickly, more easily, and with fewer errors than you would if you were working with a codebase that impedes changes. Requirements, as every developer knows, are subject to change. How change is managed is a key differentiating factor between successful software projects and those that founder on the rocks of scope creep. Developers can react in many ways to requirement changes, with two opposing viewpoints exemplifying the continuum that lies between.

First, developers can choose a rigid viewpoint. In this approach, from the development process down to class design, the project is as inflexible as if it were implemented 50 years ago by using punch cards. Waterfall methodologies are conspicuous culprits in ensuring that software cannot change freely. Their determination that the phases of analysis, design, implementation, and testing be distinct and one-way make it difficult—or at least expensive—for customers to change requirements after implementation has begun. The code, then, does not need to be built for change: the process all but forbids alterations.

The second approach, Agile processes, is not just an alternative to such rigid methodologies, but a reaction to them. The aim of Agile processes is to embrace change as a necessary part of the contract between client and developer. If customers want to change something in the product that they are paying for, the temporal and financial cost should be correlated to the size of the change, not the phase of the process that is currently in progress. Unlike physical engineering, software engineering works with a malleable tool: source code. The bricks and mortar that form a house are literally fused together as construction progresses. The expense involved in changing the design of a house is necessarily linked to the completion of the building phase. If the project has not been started—if it is still just in blueprints—change is relatively cheap. If the windows are in, the electricity wired up, and the plumbing fitted, moving the upstairs bathroom down next to the kitchen could be prohibitively expensive. With code, moving features around and reworking the navigation of a user interface should not be as significant. Unfortunately, this is not always the case. The temporal cost alone often prohibits such changes. This, I find, is largely a result of a lack of adaptability in code.

Who should read this book

This book is intended to bridge a gap between theory and practice. The reader I had in mind while writing this book is an experienced programmer who seeks more practical examples of design patterns, SOLID principles, unit testing and refactoring, and more.

Capable intermediate programmers who want to plug the gaps in their knowledge or have doubts and questions about how some of the industry’s best practices fit together will benefit most from this book, especially because the day-to-day reality of programming rarely matches simple examples or theory. Much of SOLID is now understood, but the intricacies of the open/closed principle (covered in Chapter 6) and Liskov substitution (covered in Chapter 7) are not fully comprehended. Even experienced programmers sometimes do not fully realize the benefits provided by dependency injection (covered in Chapter 9). Similarly, the flexibility—adaptability—that interfaces (covered in Chapter 3) lend to code is often overlooked.

This book can also help the more junior developer learn, from the ground up, which aspects of common patterns and practices are benevolent and which are, in the long term, malevolent. The code samples that I see from prospective employees have a lot in common. The general theme is that the candidate is almost there with respect to many skills but just needs a slight push in the right direction to become a significantly better programmer. Specifically, the Entourage anti-pattern (covered in Chapter 2) and the Service Locator anti-pattern (covered in Chapter 9) are very prevalent in sample code. Practical alternatives, and their rationales, are provided in this book.


Ideally, you should have some practical experience of programming in a language that is syntactically similar to C#, such as Java or C++. You should also have a strong foundation in core procedural programming concepts such as conditional branching, loops, and expressions. You should also have some experience of object-oriented programming using classes, and at least a passing familiarity with interfaces.

This book might not be for you if…

This book might not be for you if you are just starting out on a journey to learn how to program. This book covers advanced topics that assume a thorough understanding of fundamental programming concepts.

Organization of this book

This book is made up of three parts, each of which builds on the last. That said, the book can also be read out of order. Each chapter covers a self-contained subject in detail, with cross references included where appropriate.

Part I: An Agile foundation

This part lays the foundation for building software in an adaptive way. It covers the high-level Agile process known as Scrum, which is adaptability at the architectural level. The chapters in this part focus on details around interfaces, design patterns, refactoring, and unit testing.

  • Chapter 1: Introduction to Scrum This chapter sets the scene for the book by introducing Scrum, which is an Agile project management methodology. The chapter gives an in-depth overview of the artifacts, roles, metrics, and phases of a Scrum project. It also looks at developer tools such as source control, continuous integration, and the development environment. Finally, it shows how developers should organize themselves and their code when operating in an Agile environment.
  • Chapter 2: Dependencies and layering This chapter explores dependencies and architectural layering. Code can only be adaptive if the solution’s structure allows it to be. The different types of dependencies are described: first-party, third-party, and framework. The chapter describes how to manage and organize dependencies, from anti-patterns (which should be avoided) to patterns (which should be embraced). It also introduces advanced topics such as aspect-oriented programming and asymmetric layering, providing further depth.
  • Chapter 3: Interfaces and design patterns Interfaces are, by now, ubiquitous in modern .NET development. However, they are often misapplied, misunderstood, and misappropriated. This chapter shows some of the more common and practically useful design patterns, exploring how versatile an interface can be. Leading the reader beyond the simple extraction of an interface so that it exists in a one-to-one relationship with a single implementation, the chapter shows how interfaces can be elaborated in many different ways to solve a problem. Mixins, duck-typing, and interface fluency further underscore the versatility of this key weapon in the programmer’s arsenal.
  • Chapter 4: Unit testing and refactoring Two practices that are becoming prerequisite skills are unit testing and refactoring. The two are closely related and work in unison to produce adaptive code. Without the safety net of unit tests, refactoring is prone to error; without refactoring, code becomes unwieldy, rigid, and hard to comprehend. This chapter takes an example of unit testing from humble beginnings and expands it to use more advanced—but practical—features such as fluent assertions, test-driven development, and mocking. For refactoring, the chapter provides examples of real-world refactors that improve the readability and maintainability of the source code.

Part II: Writing SOLID code

This part builds on the foundation laid in Part I. Each chapter is devoted to examining one principle of SOLID. The emphasis in these chapters is on practical examples for implementing the principles, rather than solely on the theory of why. By placing each example in a real-world context, the chapters in this part of the book clearly demonstrate the utility of SOLID.

  • Chapter 5: The single responsibility principle This chapter shows how to implement the single responsibility principle in practice by using the Decorator and Adapter patterns. The outcome of applying the principle is an increase in the number of classes and a decrease in the size of those classes. The chapter shows that, in contrast with monolithic classes that provide extensive features, these smaller classes are more directed and focused on solving only a small part of a larger problem. It is in their aggregation that these classes then become more than the sum of their parts.
  • Chapter 6: The open/closed principle The open/closed principle (OCP) is simply stated, but it can have a significant impact on code. It is responsible for ensuring that code that follows SOLID principles is only appended to and never edited. This chapter also discusses the concept of predicted variation in relation to OCP and explores how it can help developers identify extension points for further adaptability.
  • Chapter 7: The Liskov substitution principle This chapter shows the positive effects that result from applying the Liskov substitution principle on code, particularly the fact that the guidelines help enforce the open/closed principle and prevent the unintended consequences of change. Contracts—through preconditions, postconditions, and data invariants—are covered by using the Microsoft Code Contracts tooling. The chapter also describes subtyping guidelines such as covariance, contravariance, and invariance, along with the negative impact of breaking these rules.
  • Chapter 8: Interface segregation Not only should classes be smaller than they commonly are, this chapter shows that interfaces are, similarly, often too big. Interface segregation is a simple practice that is often overlooked; this chapter shows the benefits of limiting interfaces to the smallest size possible, along with the benefits of working with smaller interfaces. It also explores the different reasons that might motivate the segregation of interfaces, such as client need and architectural need.
  • Chapter 9: Dependency injection This chapter contains the cohesive glue that allows the rest of the features in the book. Without dependency injection (DI), there is a lot that would not be possible—it is really that important. This chapter contains an introduction to DI and a comparison of the different methods of implementing it. The chapter includes discussions on managing object lifetimes, working with Inversion of Control containers, avoiding common anti-patterns relating to service location, and identifying composition roots and resolution roots.

Part III: Adaptive sample

This part uses a sample application as a way of tying together the rest of the book. Although there is a lot of code in these chapters, there is ample accompanying explanation. Because this book is about working in an Agile environment, the chapters map to Scrum sprints, and all work is the result of backlog items and client change requests.

  • Chapter 10: Adaptive sample: Introduction This first chapter describes the application that is to be developed: an online store web application using Asp.Net MVC 5, with a desktop administrative application using WPF. A brief design is provided as a guideline for the planned architecture, in addition to an explanation of the features on the backlog.
  • Chapter 11: Adaptive sample: Sprint 1 Using a TDD approach, the first features of the application are developed, including product listing and administration.
  • Chapter 12: Adaptive sample: Sprint 2 The client, inevitably, makes some changes to the requirements of the application, and we roll with the punches.


Some reference material is available in the appendices, specifically for working with Git source control and to explain how the code for this book is organized on GitHub.

    • Appendix A: Adaptive tools This is a very brief introduction to Git source control that should, at the very least, allow you to download the code from GitHub and compile it in Microsoft Visual Studio 2013. It is not intended as a thorough guide to Git—there are some excellent sources already out there, such as the official Git tutorial:

A quick web search will find other sources.

This appendix also looks at other developer tools such as continuous integration and the development environment.

    • Appendix B (available online only): GitHub code samples By putting the code for this book on GitHub, I am able to make changes in a centralized location. The repository is read-only, but Appendices A and B together show you how to find the code for a listing, download it, compile it, run it, and make local changes. If you think you have found a defect or want to suggest a change, you can issue a pull request to the main AdaptiveCode repository and I will gladly take a look. You can find Appendix B via this book’s page at
Skip to main content