Real-World Implementation of C# Design Patterns - Bruce M. Van Horn II - E-Book

Real-World Implementation of C# Design Patterns E-Book

Bruce M. Van Horn II

0,0
33,59 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

As a software developer, you need to learn new languages and simultaneously get familiarized with the programming paradigms and methods of leveraging patterns, as both a communications tool and an advantage when designing well-written, easy-to-maintain code. Design patterns, being a collection of best practices, provide the necessary wisdom to help you overcome common sets of challenges in object-oriented design and programming.
This practical guide to design patterns helps C# developers put their programming knowledge to work. The book takes a hands-on approach to introducing patterns and anti-patterns, elaborating on 14 patterns along with their real-world implementations. Throughout the book, you'll understand the implementation of each pattern, as well as find out how to successfully implement those patterns in C# code within the context of a real-world project.
By the end of this design patterns book, you’ll be able to recognize situations that tempt you to reinvent the wheel, and quickly avoid the time and cost associated with solving common and well-understood problems with battle-tested design patterns.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB
MOBI

Seitenzahl: 618

Veröffentlichungsjahr: 2022

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Real-World Implementation of C# Design Patterns

Real-World Implementation of C# Design Patterns

Overcome daily programming challenges using elements of reusable object-oriented software

Bruce M. Van Horn II

BIRMINGHAM—MUMBAI

Real-World Implementation of C# Design Patterns

Copyright © 2022 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

Group Product Manager: Gebin George

Publishing Product Manager: Gebin George

Senior Editor: Kinnari Chohan

Technical Editor: Jubit Pincy

Copy Editor: Safis Editing

Project Coordinator: Manisha Singh

Proofreader: Safis Editing

Indexer: Subalakshmi Govindhan

Production Designer: Roshan Kawale

Marketing Coordinator: Sonakshi Bubbar

First published: September 2022

Production reference: 1270922

Published by Packt Publishing Ltd.

Livery Place

35 Livery Street

Birmingham

B3 2PB, UK.

ISBN 978-1-80324-273-6

www.packt.com

For my beautiful wife Karina, and my children Kitty and Phoebe, who helped me truly understand Ruth 1:16. In memory and gratitude to my mother and father, who paid for my first three computers, back when normal people didn’t own them. In memory of Dr. Charles Gettys for motivating me by telling me I would probably fail, and then teaching me everything he knew about computers. For Van Symons, who saw past my wheelchair and gambled on me when nobody else would, and who gave me a place and the opportunity to do the best work of my career. For my students at Southern Methodist University and Richland College, from whom I’ve learned as much as I’ve taught. For my work family at Clear Technologies/Visual Storage Intelligence. In memory of my student, Tom, who really could type ActionScript code with his feet. These are the people who inspire me and for whom I am deeply grateful. Above all, I am thankful to my Lord and Savior Jesus Christ who makes all things possible (Philippians 4:13), along with His Father who invented all the electrons and silicon, without which none of this computer stuff would exist (Genesis 1:14–19).

Foreword

I have known and worked with Bruce M. Van Horn II for the past 10 years. Bruce has been the lead software developer for Visual Storage Intelligence, an analytical software technology for analyzing infrastructure hardware and software to ensure the optimum use of on-premises and cloud resources is maximized. Bruce is a leader in creating and leveraging innovative software technologies to meet demanding customer needs in a fast-paced IT environment.

In this book, Bruce teaches you how to leverage software engineering techniques known as design patterns to solve real-world problems in an efficient and effective manner. Using patterns will help you solve problems effectively without reinventing the wheel. It will also keep your code healthy and stable.

Learning patterns are a must-have requirement in the career of any software engineer that we’ve hired at our start-ups. There is no question as to whether you should learn patterns; the question is really, where can you find a resource that teaches patterns in a way that is easy to understand and apply? There are many books on patterns in the marketplace but most have a very academic focus. This book is very different and somewhat unique. Instead of a dry treatment that reads like a doctoral thesis, Bruce presents you with the story of two sisters who form a tech start-up. Problems are encountered, requirements change, and at one point, so does the direction of the business. These are all normal and frequent occurrences, and the software that runs the company must be able to adapt. Most books cover development topics in a vacuum. All the designs are perfect, and the code always runs on the first try. That isn’t real life.

The story in this book follows a more realistic arc. The characters get into jams and use patterns to get out of them. Oftentimes, knowing when, where, and how to make use of these patterns can be critical to business success, and that’s what you’re going to learn in this book.

Bruce is not only a brilliant software engineer but also one of the best technology educators I have met in my 45-year career. He has the unique ability to not only understand the technology but also understand both the best places to make use of it, and also the places where specific technologies are not appropriate for the issues being analyzed.

Bruce shows you how to leverage the most important Gang of Four patterns in simple-to-understand examples, as well as how to use the patterns to solve problems in your daily work. Reading this book made software design patterns come to life and helped me understand how to leverage patterns in a real-world business context.

Van Symons

CTO Visual Storage Intelligence

Contributors

About the author

Bruce M. Van Horn II is an architect and lead developer for Clear Technology’s Visual Storage Intelligence SaaS product. He has over 30 years’ experience writing software and over 25 years’ experience teaching software development at a university level. He currently teaches full stack software development at Southern Methodist University’s code boot camp. He is a Certified ScrumMaster (CSM). Ten years ago, he was diagnosed with dermatomyositis and was told he would never walk, speak, or eat nachos again. Through faith and hard work, he beat the odds and today enjoys riding bicycles with his daughters, Katherine (Kitty) and Phoebe. He eats nachos regularly with Karina, the love of his life.

About the reviewers

Alexej Sommer is a professional .NET developer with expertise in a variety of technologies, including ASP.NET Core, WPF, UWP, Xamarin, and Azure.

He is also MCP/MCSD- and Azure-certified. He’s a winner of Microsoft’s Most Valuable Professional 2016–2019 in the Windows Development category. At present, he sometimes participates in conferences as a speaker.

Sarita Nag was born in India and she earned her master's degree in computer science from KIIT University, Bhubaneswar, Orissa.

Sarita began her career as Software Engineer from Thomson Reuters and since then, she worked on many multinational companies and is currently working at FISERV.

She is an experienced software engineer with passion for developing innovative programs that expedite the efficiency and effectiveness of organizational success. Well-versed in technology and writing code to create systems that are reliable and user-friendly.

She has 10+ years of experience in various phases of Software Development Life cycle (SDLC) and Agile methodologies such as Analysis, Design, Development, Testing, Deployment, and Maintenance in various domains like Tax and accounting, Financial, Communication Media, and Customer relationship.

Table of Contents

Preface

Part 1: Introduction to Patterns (Pasta) and Antipatterns (Antipasta)

1

There’s a Big Ball of Mud on Your Plate of Spaghetti

Technical requirements

No battle plan survives first contact with the enemy

The Stovepipe system

The Big Ball of Mud

Time

Cost

Experience

Skill

Visibility

Complexity

Change

Scale

The Golden Hammer

A throwaway code example

How can patterns help?

Summary

Questions

Further reading

2

Prepping for Practical Real-World Applications of Patterns in C#

Becoming a prepper

Technical requirements

Spaghetti < lasagna < ravioli – software evolution explained with pasta

Spaghetti code

Lasagna code

Ravioli – the ultimate in pasta code

The foundational principle – writing clean code

You should write code that is readable by humans

Establishing and enforcing style and consistency

Limiting cognitive load

Terse is worse

Comment but don’t go overboard

Creating maintainable systems using SOLID principles

The Single Responsibility principle

The Open-Closed Principle

The Liskov Substitution principle

The Interface Segregation principle

The Dependency Inversion principle

Measuring quality beyond the development organization

Code reviews

Overall design

Functionality

Summary

Further reading

Part 2: Patterns You Need in the Real World

3

Getting Creative with Creational Patterns

Technical requirements

The following story is fictitious

The initial design

No pattern implementation

The Simple Factory pattern

The Factory Method pattern

The Abstract Factory pattern

The Builder pattern

The Object Pool pattern

The Singleton pattern

Summary

Questions

Further reading

4

Fortify Your Code With Structural Patterns

Technical requirements

B2B (back to bicycles)

The Decorator pattern

The Façade pattern

The Composite pattern

The Bridge pattern

Summary

Questions

Further reading

5

Wrangling Problem Code by Applying Behavioral Patterns

Technical requirements

Meanwhile, back at the bicycle factory

The Command pattern

Applying the Command pattern

Coding the Command pattern

Testing the Command pattern’s code

The Iterator pattern

Applying the Iterator pattern

Coding the Iterator pattern

Trying out the new iterator

The Observer pattern

Applying the Observer pattern

Coding the Observer pattern

The Strategy pattern

Applying the Strategy pattern

Coding the Strategy pattern

Summary

Questions

Part 3: Designing New Projects Using Patterns

6

Step Away from the IDE! Designing with Patterns Before You Code

Technical requirements

A bad day at the agency

Bumble Bikes factory – Dallas, Texas

A physical rehabilitation clinic – Dallas, Texas

Designing with patterns

The first pass

The seat

The frame

Wheels and casters

The motor for the powered chair

The steering mechanism for the powered chair

The battery for the powered chair

The track drive system for the Texas Tank

Adding patterns

The first design meeting

The second pass

The Builder pattern

The Singleton pattern

The Composite pattern

The Bridge pattern

The Command pattern

Summary

Questions

Further reading

7

Nothing Left but the Typing – Implementing the Wheelchair Project

The crack of noon

Setting up the project

Wheelchair components

Finishing the wheelchair base classes

Finishing up the composite

Implementing the Builder pattern

Another refactor

Adding concrete component classes

Wrapping up the Builder pattern

Adding the Singleton pattern

Painting the chairs with the Bridge pattern

Summary

Questions

Further reading

8

Now You Know Some Patterns, What Next?

Patterns we didn’t discuss

Prototype

Adapter

Flyweight

Chain of Responsibility

Proxy

Interpreter

Mediator

Memento

State

Template Method

Visitor

Patterns beyond the realm of OOP

Software architecture patterns

Data access patterns

Creating your own patterns

Name and classification

The problem description

The solution description

Consequences of using the pattern

Not everybody likes patterns

Summary

Sundance Square – Fort Worth, Texas

Further reading

Appendix 1

A Brief Review of OOP Principles in C#

Technical requirements

A quick background of C#

C# is a general-purpose language

C# is purely and fully object-oriented

C# uses a static, strong type system

C# has automatic bounds checking and detection for uninitialized variables

C# supports automated garbage collection

C# code is highly portable

Language mechanics in C#

Variables in C#

Classes

Encapsulation

C# auto-implemented properties

Accessor logic with backing variables

Inheritance

Interfaces

Defining interfaces

Implementing interfaces

IDEs for C# development

Visual Studio

VS Code

Rider

Summary

Further reading

Appendix 2

A Primer on the Unified Modeling Language (UML)

Technical requirements

The structure of a class diagram

Classes

Interfaces

Enumerations

Packages

Connectors

Inheritance

Interface realization

Composition

Association

Aggregation

Directed association

Dependency

Notes

Best practices

Less is more – don’t try to put everything in one big diagram

Don’t cross the lines

The most direct path for lines leads to a mess

Parents go above children

Keep your diagrams neat

Summary

Further reading

Index

Other Books You May Enjoy

Preface

This is a book about design patterns written in the context of the C# coding language. I know what you’re probably thinking. What does that even mean? Well, I could tell you but I’d spoil the rest of the book, and trust me, it’s a doozy!

Design Patterns are a codified set of best practices for software problems that come up so often that we can learn to recognize them and immediately know how to solve them. The solutions for these recurring problems found in patterns have been used for decades and they have proven to be effective.

Patterns also become a battle language for developers because they are so pervasive. This idea comes from the popular television and movie franchise, Star Trek. In Star Trek, the warrior race known as the Klingons has two languages. They have the regular Klingon language that they learn in Klingon kindergarten and an abbreviated version they use during combat. The phrase “Load torpedo tubes 1 and 2 and fire a full spread” can be reduced to one or two words. All Klingons know what that phrase means, and they win battles because they are a few seconds faster than their linguistically-challenged foes. Similarly, you can say “Just use the decorator pattern.” Any developer who has studied patterns will understand what to do next.

Patterns are not specific to the C# language. However, in order to learn patterns effectively, you need an implementation language. The original book on patterns was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, collectively known as the Gang of Four, or GoF for short. Their book, Design Patterns: Elements of Reusable Object-Oriented Software, is often referred to as the GoF book.

The GoF book was published in 1994, which makes it a technological dinosaur. While it may be old, the patterns explained within its pages are still very relevant. My criticism of the GoF book is it is written in a very academic format, and its implementation language is one you don’t really see anymore. The implementation language is an important detail. The GoF book covers 23 patterns, which is the same number of herbs and spices found in KFC’s original recipe. That can’t be a coincidence. This book doesn’t cover all 23 patterns, which is fine, because too much fried chicken isn’t very good for you. I’ve focused on patterns you’ll need every day in most of the projects you work on. I cover the remainder briefly in Chapter 8 at the end of the book.

There are some books out there that try to use pseudocode in order to be generic. I posit that such books are not useful to most people. If you’re like me, and you probably are in this regard, you’d wish for a code example that is easy to read, isn’t overly clever, and has a firm basis in the real world. Books and blog sites that try to teach you patterns with phrases such as “Class A inherits from Class B, which depends on Class C” are too vague to be useful. Equally annoying are books and sites that try to show you the pattern in 20 languages. They usually do a poor job with all 20 instead of focusing on doing a good job in just one. I am only using C# and the Unified Modeling Language (UML).

If you’ve never heard of UML before, don’t let it scare you. UML is a convention used to create diagrams. There are 14 types of UML diagrams. I only use one diagram type: class diagrams. I’ve included a primer in Appendix 2 to help you if you are new to UML.

This book is about the real world, or at least a close facsimile. I’ve written this book using the same techniques that are used in real software projects. There’s realistic code in the book that solves legitimate business problems. There are also design mistakes included, along with thoughtful ways out of trouble.

Another issue with academic books is that they are wordy and hard to read. I have strived to take a dry subject and avoid being boring. I realize that nobody intentionally writes a boring book. Unfortunately, many have succeeded. I think the main cause of this boredom is how a lot of authors in technology view the task of writing a book. I think a lot of authors write books to prove how smart they are. These tend to be very academic. They are built to impress other academics. That’s great! The world needs academics. Most developers are not professional academics. I dare say, a great many developers have never taken a formal CS course. My aim in writing this book isn’t to prove I’m smart or capable. My wife would tell you that I am obnoxiously self-deprecating. Instead, my aim is to help you over the wall that is keeping you from moving to the next level in your coding. I had to climb this wall by myself, and for me, it wasn’t easy. However, if I can do it, you can too, with my help.

Instead of a dry academic treatment, this book presents a story that could actually happen in the real world. There’s just enough light science fiction involved to make it “just a story.” The circumstances in the story, though, are very real, and you’ll recognize them, even if you have a few years in the field.

On that point, I want to make a few things clear. The story in this book is fiction. While I am a fantastic software engineer, I am not a roboticist or a mechanical engineer, nor am I a qualified bicycle mechanic. At several points in the coming story, you may need to suspend your disbelief if these subjects are in your wheelhouse.

Who this book is for

This book is for anyone who wants to become a better software developer. I wish I could get away with just saying that, but I probably can’t. Let me add a few thoughts on who will benefit from this book.

The easy answer is what I would call mid-level developers. These are developers who have a few years of experience with C# and are very comfortable with the basic principles of object-oriented programming. Ideally, you’ve seen a few UML class diagrams.

Another beneficiary of this book is a student who is learning C#. If you’re even remotely comfortable with basic OOP concepts, such as inheritance and composition, and you know your way around an integrated development environment (IDE), I want you to read this book. Sure, the mid-level developer might have an easier time, but learning patterns and SOLID principles will give you a strong foundation. You might avoid picking up some bad habits, or correct those you’ve already learned.

I also encourage you to read this book if you’re a recent graduate of either a university or a code boot camp. If you haven’t done a lot of C# work, but you’ve worked in other languages such as Java, C++, Python, or JavaScript, you are invited to read this book as well. I’ve tried to give you a bit of a boost by including a lengthy primer on C# and object-oriented programming concepts in Appendix 1 of this book.

There is one group I want to reach most of all.

I especially want to encourage self-taught developers like myself. Those in this camp tend to have learned only what is absolutely necessary as a means of surviving your current sprint. If your teachers are YouTube and the blogosphere, chances are you will readily recognize the anti-patterns found in Chapter 1, because by now, you’ve probably committed every sin relevant to software engineering. I only know this because I have too. As such, I know you stand to benefit the most from reading this book.

As I said, this book is for anyone who wants to become a better software developer. I guess I should have just stuck with that.

What this book covers

Chapter 1, There’s a Big Ball of Mud on Your Plate of Spaghetti: Before we dive into patterns, let’s dive into why we need them. The world of software development is very messy, but it doesn’t have to be. The mess comes from a set of degenerative forces in our work that you will surely recognize.

Chapter 2, Prepping For Practical Real-World Applications of Patterns in C#: To defeat the degenerative forces mentioned in Chapter 1, you’re going to have to step up your game. This chapter presents some rules and principles. If you can adhere to them, you will have the discipline needed to use design patterns to their greatest effect.

Chapter 3, Getting Creative with Creational Patterns: Now that you are thoroughly prepared, this chapter introduces our story. It covers patterns designed to make the instantiation of your classes more robust and more flexible. After reading this chapter, you’ll never look at the new keyword the same way.

Chapter 4, Fortify Your Code with Structural Patterns: This chapter covers techniques you can use to structure your classes for maximum flexibility while honoring the SOLID principles covered in Chapter 2.

Chapter 5, Wrangling Problem Code by Applying Behavioral Patterns: Got algorithms? You need a flexible set of patterns in order to maximize their effectiveness and flexibility. You need behavioral patterns.

Chapter 6, Step Away from the IDE! Designing with Patterns Before You Code: In this chapter, we consider ways to design our code with patterns before we write a single line in our IDE. After an unfortunate turn of events in our story, we find our company drastically and rapidly changing direction. We need a new product design, and we need it last week! Let’s draw our designs in UML first! This saves a lot of time and energy and prevents the possibility of some pointy-haired boss telling us to ship a prototype.

Chapter 7, Nothing Left but the Typing – Implementing the Wheelchair Project: In the last chapter, we came up with an elegant set of design diagrams. In this chapter, we do the typing. You’ll implement the same patterns you learned earlier in the book, but this time, you’ll use them in concert with each other on a real-world project.

Chapter 8, Now You Know Some Patterns. What Next?: We’ve had a lot of fun learning patterns so far, but this is only the tip of the iceberg. There are patterns everywhere! They aren’t limited to the practice of OOP. In this chapter, we cover the GoF patterns we didn’t cover in our story.

Chapter 9, Appendix 1 – A Brief Review of OOP Principles in C#: This appendix is designed for those who are new to C# or maybe haven’t used it in a while, or are coming from another language.

Chapter 10, Appendix 2 – A Primer on the Unified Modeling Language: The Unified Modeling Language is a documentation convention used by software developers. It defines the structure of the pattern design diagrams used throughout the book. While UML has 14 different diagram types, we really only use class diagrams. Most presentations on patterns have two diagrams. I draw a generic one, and a second diagram that mirrors the project code. This appendix shows you the conventions used in the diagrams.

To get the most out of this book

To get the most out of this book you should be familiar with C#. You need to be competent in using one of the three popular IDEs: Visual Studio, Rider, or Visual Studio Code. You should also understand basic object-oriented programming principles such as abstraction, inheritance, encapsulation, and composition.

I don’t spend very much time covering how to use your IDE in this book. However, I do include Appendix 1, which covers how to create a project just in case you’re rusty. This book isn’t designed to be a step-by-step guide through a set of projects. The code in the sample projects doesn’t matter. We’re focusing on the structure of the code, rather than the content of the classes.

The projects in this book are all either command-line or library projects. We won’t be working with any frontend or user interface code. This is done to reduce the level of noise in the projects. I want you focused on the structure of the classes, not what is inside them, nor even what the program is really doing.

I used Windows 10 to create the code in this book. If you want to follow along with the code in the book, you can probably use macOS or Linux. However, I don’t cover those operating systems explicitly, nor do I test the sample code in operating systems other than Windows.

If you intend to code along with our book’s heroes, you’ll need to set up your computer with an appropriate IDE, and .NET Core 6 or later. I used Rider as my IDE, but I verified the code in Visual Studio 2022 and Visual Studio Code.

Software/hardware covered in the book

Operating system requirements

C# 10

Windows

.NET Core 6

Windows

Rider, Visual Studio, or Visual Studio Code

Windows

If you are using the digital version of this book, we advise you to type the code yourself or access the code from the book’s GitHub repository (a link is available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.

I strongly encourage you to type the code from the book by hand. You’ll learn more by typing it out, by making mistakes, and then fixing them yourself.

Download the example code files

You can download the example code files for this book from GitHub at https://github.com/Kpackt/Real-World-Implementation-of-C-Design-Patterns. Please note that GitHub won’t allow us to use the # character in C# so the name of the repository is slightly misleading. If there’s an update to the code, it will be updated in the GitHub repository.

We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

This book has a companion website developed by the author. You can find it at https://csharppatterns.dev.

Download the images

We also provide a PDF file that has color images of the screenshots and diagrams used in this book. You can download it here: https://packt.link/3KWzG.

Conventions used

There are a number of text conventions used throughout this book.

Code in text: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: “Kitty starts by creating an abstraction for what the builders will be producing – that is, the product. She creates an interface called IBicycleProduct.”

A block of code is set as follows:

public interface IBicycleProduct

{

public IFrame Frame { get; set; }

public ISuspension Suspension { get; set; }

public IHandlebars Handlebars { get; set; }

public IDrivetrain Drivetrain { get; set; }

public ISeat Seat { get; set; }

public IBrakes Brakes { get; set; }

}

When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:

namespace WheelchairProject; public abstract class WheelchairComponent {

Any command-line input or output is written as follows:

$ dotnet build

$ dotnet run hillcrest

Tips or important notes

Appear like this.

Get in touch

Feedback from our readers is always welcome.

General feedback: If you have questions about any aspect of this book, email us at [email protected] and mention the book title in the subject of your message.

Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata and fill in the form.

Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.

If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

Share Your Thoughts

Once you’ve read Real-World Implementation of C# Design Patterns, we’d love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.

Your review is important to us and the tech community and will help us make sure we’re delivering excellent quality content.

Part 1: Introduction to Patterns (Pasta) and Antipatterns (Antipasta)

We will begin Part 1 by describing what patterns are and where they came from and giving an overview of how they work and why you’d want to learn them.

This part covers the following chapters:

Chapter 1, There’s a Big Ball of Mud on Your Plate of SpaghettiChapter 2, Prepping for Practical Real-World Applications of Patterns in C#

1

There’s a Big Ball of Mud on Your Plate of Spaghetti

Welcome to what is potentially your last day on the job. Your project is about to be canceled. Your customers are angry. Your boss is freaking out. Your boss’s boss is in Antigua, but when she comes back next week, heads will probably roll. There’s no way to sugar-coat it. You might want to update your résumé and brush up on your algorithms, so that you’re ready for an imminent job search.

How did it come to this? We had a plan. The hardware architecture was simple. The first few releases went off without a hitch and our users were delighted. Our client even presented a whole new set of feature requests and signed a contract extension. How have we found ourselves at the precipice of sure and sudden doom?

The situation we have found ourselves in here is far from unique. According to many academic accounts, five out of six software projects are canceled. Others fail by running behind schedule or over budget. Software projects are hard. There’s no such thing as a simple program. There’s really no project that you can knock out in a week, then ship, and that’s the end. It doesn’t work that way. This phenomenon is unique to the software industry. Structural engineers who design bridge are pretty much done when the bridge opens for public traffic. Electrical engineers design and test circuits on breadboards, then hand those designs off to be manufactured. Aeronautical engineers, such as my grandfather, who designed power plants (as in, engines) for Beechcraft, generally designed and prototyped engines, but didn’t do much beyond that. It was up to others to manufacture the engine, mount it on the aircraft, and others to maintain the engine.

In contrast, software engineers must design, build, test, and often maintain the systems that they develop in a continuous delivery environment. Many projects are never “done.” I’ve been working on the same software project for the last 9 years. We certainly haven’t built the perfect project with perfect architecture, but the project has endured. New features are produced, and bugs are discovered and fixed.

What differentiates projects that run continually for many years from the vast majority that get canceled? While there are many ways this can happen, we’re going to focus solely on the design and architecture of our software. I’ll start with how it very often goes wrong. In keeping with the title of this book, we’ll spend some time in this chapter discussing a set of antipatterns. While I haven’t directly introduced the concept of patterns yet, I suspect that you can make an educated guess about what they are, along with what their antithesis is. A pattern, for now, is simply a formally explained, abstract, best practice solution to a common development requirement. An antipattern is a formal example of what you shouldn’t do. Patterns are arguably good. Antipatterns are inarguably bad.

This chapter will present some of the most common antipatterns, including the following:

Stovepipe systemsThe Big Ball of MudThe Golden Hammer

Once we’ve learned about a few antipatterns, we’ll focus in later chapters on principles and patterns designed to combat and correct the circumstances where antipatterns have either taken hold or might soon take hold. In Chapter 2, Prepping for Practical Real-World Applications of Patterns in C#, I will prepare you for your work with patterns. Software development is an odd business in that we all come to it traveling different roads. I am personally self-taught. I started when I was 12 years old. The only books about computer programming were available for purchase at Radio Shack. There were about a dozen. We didn’t have resources such as Packt Publishing plying the market with fascinating and useful books on every facet of software development. In 1991, the year that I graduated from university, a computer science degree would have focused on software development for mainframes using FORTRAN, which is a far cry from the work I do now. The mainframe programming course I took in 1987 was the last class to use punch cards. If you’re not sure what they are, go look them up. I’ll wait. Are you back? Are you horrified? Me too. The point is, there are a lot of people such as me out there who learned programming out of necessity, and they learned informally.  

There are many university-trained software developers out there, but not all software development programs are the same. Computer science programs focus on elements such as mathematical theory and algorithm development but teach only a minimal amount of practice. Software engineering programs, boot camps, and trade schools have more of an engineering focus, where you learn to build software with less of a focus on the theory. Regardless of where you started, Chapter 2 aims to ensure that you understand the most important formal engineering concepts needed in order to work with patterns. Patterns were created using a set of rules and Chapter 2 covers those rules.

In Chapters 3, 4, and 5, we cover patterns in earnest using a story format. I’ve done this in the hope of creating a learning experience very different than my own, having read some of the more heavy-handed academic treatments of design patterns. The patterns that I have selected for this book come from what is perhaps the seminal work on patterns in the software industry, Design Patterns: Elements of Reusable Object-Oriented Software, by Eric Gamma, Richard Helm, Ralph Johnson, and John Vlissides. These four authors are known collectively as The Gang of Four (GoF), and the book that they wrote is colloquially referred to as The GoF book or just GoF. The GoF book contains 23 patterns, broken down into three categories:

Creational patterns deal with the creation of objects beyond simply using the new keyword.Structural patterns deal with the way that you structure your classes to maximize flexibility, reduce tight coupling, and help you focus on reusability.Behavioral patterns deal with how objects interact with one another.

The creational patterns I’ll be covering in Chapter 3include the following:

The Simple Factory (technically not a pattern)The Factory Method patternThe Abstract Factory patternThe Builder patternThe Object Pool patternThe Singleton pattern

Within the realm of structural patterns, in Chapter 4, I’ll be covering the following:

The Decorator patternThe Façade patternThe Composite patternThe Bridge pattern

Practical pattern coverage will conclude in Chapter 5 with this set of behavioral patterns:

The Command patternThe Iterator patternThe Observer patternThe Strategy pattern

Again, I’ll point out that this book is designed to focus on real-world software development. In the real world, we don’t always perfectly follow the rules presented in Chapter 2. Many books present a perfect experience. Expert authors always present all of their examples as perfect on the first try. I won’t be doing that because that isn’t in keeping with reality. As we flow through Chapters 3, 4, and 5, we will find ourselves faced with “gotchas” that you will find in actual practice. There’s no way around them. Even if you execute the patterns and strategies in these chapters perfectly, nobody can foretell the future. In Chapter 6, a plot twist in our story arises and we have a chance to rethink everything that we’ve done up to that point. In Chapter 6, we’ll design a new system based on an old one using the patterns that we’ve learned so far. Chapter 6 is all about creating a design and a plan. In Chapter 7, we implement that plan.  

I won’t be covering every pattern covered by the GoF. Instead, I’ll be focusing on the patterns you are most likely to need as a C# .NET software developer working in the field. I’ve selected my list of patterns based on popularity, usefulness, and complexity. Complex patterns that are not often seen in the wild have been omitted from the main text of the book. That said, I do circle back in Chapter 8 to give you a rundown on the patterns that I didn’t cover, and the usual advice on where to go from there.

This book assumes that you have a few years of experience working with C#. In addition to my day job, I have taught software development at colleges for the last 25 years. I presently teach at Southern Methodist University’s Full Stack Code Bootcamp. Some of the programs I taught focused on C#, while others haven’t. At SMU we teach JavaScript. If you’re coming to this book without recent C# experience, or perhaps with none at all, I’ve added Appendix 1 at the end of the book. It is designed to give you what I hope is enough orientation in the C# language to make the rest of the book useful. The truth about patterns is they are language-agnostic. They apply to any object-oriented language, and I’ve even seen some of them shoehorned into languages that are not object-oriented with arguable levels of success.

Technical requirements

This chapter presents some code examples. Most books always present exemplary code that makes sense for you to follow in the creation of the project. The code in this chapter is terrible on purpose. It isn’t strictly necessary that you follow along by creating the project, but you’re welcome to do so if you’d like.

If this is the case, you’ll need the following:

A computer running the Windows OS. I’m using Windows 10. Since the projects are simple command-line projects, I’m pretty sure everything here would also work on a Mac or Linux, but I haven’t tested the projects on these operating systems.A supported IDE, such as Visual Studio, JetBrains Rider, or Visual Studio Code with C# extensions. I’m using Rider 2021.3.3.Some version of the .NET SDK. Again, the projects are simple enough that our code shouldn’t be reliant on any particular version. I happen to use the .NET Core 6 SDK and my code’s syntax may reflect that.An instance of SQL Server and basic knowledge of SQL. I want to restate that the code in this chapter is designed to be a realistic example of throwaway code. C# and SQL Server go together as peanut butter and jam do, which adds to the realism. Some readers may not be comfortable working in SQL Server, especially without Entity Framework (EF) used for its presentation. This is the only place in this book where a database is even mentioned. If you have no experience with databases, don’t worry. The example is really meant to be read more than tried. If you want to try it, any version of SQL Server should work. I’ll be using SQL Server 2019.

You can find the code files for this chapter on GitHub at https://github.com/Kpackt/Real-World-Implementation-of-C-Design-Patterns/tree/main/chapter-1/.

No battle plan survives first contact with the enemy

There’s an old saying: if you fail to plan, you plan to fail. Only the rankest amateur would dive into a project IDE-first without at least considering how the project ought to be structured. The typical first steps might involve roughing out a package and object structure, or maybe designing the structure of a relational database that will persist the data used by our software. Someone who’s got a few projects under their belt might even draw some diagrams using the Unified Modeling Language (UML).

We begin by taking a set of user stories and we shape our code into something that on the surface meets the requirements in front of us. Soon, we’re in an agile groove swing. We’ve achieved velocity! We create a feature, show it to the customer, get feedback, revise, and continuously deliver. That’s usually how the troubles begin.

Our first major anti-pattern, the stovepipe system, comes from the seminal book on the subject, AntiPatterns, by Brown, et al., which I’ve listed as suggested reading at the end of this chapter.

The Stovepipe system

Once upon a time, in just about any industrialized society, people heated their homes and cooked using a cast-iron potbelly stove. These stoves burned coal or wood for fuel. Over time, the exhaust vent for the stove, called the stovepipe, since it was literally a pipe sticking out of the stove, would build up with corrosive deposits, which led to leaky stovepipes. The fumes from a burning stove are potentially life-threatening within a small, enclosed space.

Here’s what an actual stovepipe looks like:


Figure 1.1 – A stove with a stovepipe.

The stovepipe required constant maintenance to prevent asphyxiation. This was usually done by the owner of the stove, who was unlikely to be a stove repair professional. The stove was repaired using tools and materials that were readily available. This made for very ad hoc patch jobs, rather than clean, well-thought-out repairs done with original equipment manufacturer (OEM) grade materials and the proper tools.

Now, think about how this might relate to a software project. The initial release is designed with great care, with an implementation that perfectly matches the design. The natural tendency during software maintenance is to fix things quickly and get the patched version released and out the door. As with our amateurish stove repairs, our analysis of the holes in the software design and implementation are perfunctory and incomplete. There is pressure to solve this quickly. Everybody is watching you. Every minute the application is down costs the company money and you risk losing the employee of the month parking spot.

This happens to everyone and everyone generally caves to human frailties. You then implement the quickest, easiest thing you can think of – it’s done and the patch is out the door. The crisis is over.

Or is it? Dun dun dun! Small ad hoc fixes have a negative cumulative effect over time, referred to as technical debt, just as the corrosive deposits on a stovepipe do. How can you tell whether the systems that you’re working on are stovepipe systems? Let’s explore the following:

Stovepipe systems are monolithic by their very nature. It is not easy to get data in or out of this kind of system, and integrating software built this way into a larger enterprise architecture is cumbersome or impossible.Stovepipe systems are very brittle. When you make one of these small ad hoc repairs, you generally find that the fix breaks other parts of the application.  Usually, this isn’t discovered until after the breaking fix has been released.Stovepipe systems can’t be easily extended as new business requirements emerge. When a project starts, you’re given a set of requirements. You build the software that meets those requirements. After it’s released, a new feature is requested that you couldn’t possibly have predicted. You realize that there’s no way to implement that feature without redesigning the whole app. Anytime you’re tempted to throw out the baby with the bathwater and just start over, you’re working on a stovepipe system.Stovepipe systems built on component architectures are generally incapable of sharing those components with other enterprise applications. The level of code reuse between projects is very low.Stovepipe systems are often found on projects with high turnover. This makes sense. You start a new job, replacing the last developer, and you feel pressure to get something working quickly to show your new boss that hiring you wasn’t a huge mistake. You do your best to piece something together to fix a problem. You have no knowledge of the existing architecture or what’s been tried, and perhaps failed, in the past. Now amplify this by considering two or three further re-staffing efforts, with several months between each new hire’s start dates.Stovepipe systems are often indicated when the development team is using new or unfamiliar technologies, stacks, or languages. Given that the same pressure to produce something quickly exists, while the team is simultaneously required to work with tools and languages that they’ve never used before, this leads to the same pattern of just getting something working and released. You will also encounter stovepipe systems in start-ups, corporate acquisitions, and mergers for these same reasons.

Does any of this sound familiar? Naturally, we’re not talking about anything you’ve ever written! Isn’t this just a little bit reminiscent of code you’ve seen other people write? Maybe your competitors? Maybe your students? Even if you own up to writing a stovepipe system, don’t beat yourself up. It is far and away the most popular pattern in software development today. Sometimes, a stovepipe system is fine. Remember, not every physical edifice needs to be supported by fluted ivory columns, and there’s a very legitimate argument to be made for getting the software to market and worrying about the rest later. However, if your objective is to build software that’s still useful and profitable 10 years or more down the road, keep reading. We’ll have those stovepipes replaced with functional, modular, well-constructed systems in no time.

The Big Ball of Mud

Around the same time Brown, et al. were writing their book on antipatterns, another research team was engaged in a similar effort. The product of their work was titled Big Ball of Mud, by Foote and Yoder (1997), which I’ve listed in the Further reading section at the end of this chapter. It’s their work that inspires the title of this chapter.

The Big Ball of Mud antipattern is remarkably similar to our outline of stovepipe systems. However, the authors go into greater depth on how these systems understandably come to be.

They often start with throwaway code. I think this is self-explanatory. It’s code that you knock out in a few hours, or even a few weeks, that serves as a rough prototype. It proves to you and perhaps your stakeholders that the problem in front of you is soluble. It might even be good enough to demonstrate to the client. This is where the trap is sprung. The prototype is good enough to publish, so, at the behest of your boss, you do. We’ll simulate this later in this chapter in a section titled A throwaway code example by intentionally building a prototype that is good enough to ship, but not good enough to survive extension. This rough prototype will do everything asked of us. Right after this imaginary software project ships its first release, we’ll then find ourselves faced with a second factor in the construction of a Big Ball of Mud: piecemeal growth. A project manager might refer to this pejoratively as scope creep. I have been a consulting software engineer and a corporate software engineer. I can tell you the project management view of scope creep as being something negative is misinformed. While it is a source of frustration from a planning and billing perspective, new requirements coming in after the initial release are the hallmark of a successful system. It is my strongest advice that you begin every project with the idea that it will be wildly successful. This may seem overly optimistic, but it is in fact the worst-case scenario if you have published throwaway code.

Piecemeal growth leads to a strategy called keeping it working. Again, this needs little explanation. As bugs and new features are identified, you just fix the offending bits and make the program satisfy the new set of requirements. And, oh, by the way, we need this done by next week.

After the second release, keeping it working becomes your daily job description. If your program is really successful, you will start to hire people to help you with keeping it working, which naturally amplifies the problems and technical debt as the project continues to grow.

To reiterate, this sounds very similar to our elucidation of a stovepipe system. Foote and Yoder consider in more detail the forces that lead to our unfortunate muddy circumstances. Forces, as in nature, are outside actors that you can rarely ever control. These forces consist of the following:

TimeCostExperienceSkillVisibilityComplexityChangeScale

Let’s talk a little more about each.

Time

You may not be given enough time to seriously consider the long-term ramifications of the architectural choices that you’re currently making. Time also limits your project by limiting what you can accomplish with what you’re allotted. Most developers and project managers try to get around this by padding their estimates. In my experience, Parkinson’s law is true: projects where time estimates are padded, or even doubled, usually expand to fill or exceed the time allotted.

Cost

Most projects don’t have an infinite budget. Those that do are open source projects that have no monetary budget at all, instead substituting it with the time of volunteers, which is itself a cost. Architecture is expensive. The people with the knowledge and experience to develop a sound architecture are rare, though slightly less inaccessible given that you are reading this book. They tend to draw higher salaries, and the expense involved in the effort to create and maintain proper architecture doesn’t pay off immediately in the minds of your stakeholders, bosses, or customers.

Good architecture requires time, both on the part of the development staff and the architect, but also domain experts who know the business behind the software. The domain experts are rarely dedicated to the software development effort. They have regular jobs with real requirements and deadlines outside the software project. Involving a business consultant who bills at $250 USD per hour is eating up time that could be billable, but you honestly can’t complete the project without this access.

Experience

Software developers are experts in software development. They rarely have expertise in the business domain where they are building solutions. For example, it’s rare that someone building a system that quotes insurance policies has worked as an actuary or even an adjuster. Lack of experience in the business domain makes the job of modeling software a process of trial and error, which naturally affects the program’s architecture.

Skill

Not all software developers have equal levels of skill. Some are new to the field. Some are slower learners than others. Some learned to use a few golden hammers (more on this later) and refuse to upskill any further. And there’s always a superstar on the project that makes everybody else feel as though they’re a poser.

Visibility

You can’t see inside a working program. Sure, you can fire up a debugger, but normal people can’t look around the architecture of your code the same way that they can inspect the architecture of a physical structure such as an office building. For this reason, architecture is neglected. Your boss will not likely give you a fat bonus for your amazing abstractions and interface structures. They will, however, reward you for shipping early. This leads to a very human, lackadaisical attitude toward how your code is structured.

Complexity

Complex problem domains beget muddy architectures. Imagine modeling a collection of modern light bulbs. That’s pretty easy. Properties such as wattage, light output in lumens, and input voltage jump out at you as if they are second nature. Now, imagine modeling a light bulb in 1878. You’re in uncharted territory. Thomas Edison patented his first light bulb in 1879 and is famously quoted as saying that he had discovered two thousand ways to not build a light bulb. If the domain is complex or unexplored, you should expect a bumpy ride as far as your architecture is concerned.

Change

Change is the one thing that always remains constant. Foote and Yoder wrote that when we devise an architecture, it is based entirely upon a supposition: a set of assumptions about the future wherein we expect changes and extensions to that architecture to be bound only to the realm of possibilities that we have considered so far. This is all well and good, except another truism invariably surfaces: no battle plan survives first contact with the enemy. The change requests will come in the most inconvenient form, at the most inconvenient time, and it’s your job to deal with that. The easy way out is always the most palatable to the stakeholders but it is what leads to a Big Ball of Mud.

Scale

Creating a system to be used by 100 people in total is a very different problem than creating a system that can process 10,000 requests per second. The style in which you write your code is different. Your reliance on highly performant algorithms is largely absent in a small system, but vital to the success of a large one. Rarely do projects start at the scale typically considered by Google or Amazon. Successful projects must be able to scale up according to how successful they become.

The Golden Hammer

Another important antipattern you should learn to recognize is generally a product of some marketing organization or salesperson in a company outside your own. It happens when some killer app, framework, infrastructure component, or tool is presented as the panacea for all your software development woes. It slices, it dices, it makes julienne fries, and it automatically refactors itself while speeding up the execution of your code.

The antipattern is described as the Golden Hammer. Behold a fully-rendered CGI representation in Figure 1.2:

Figure 1.2 – When you’re given a golden hammer, everything is a nail.

Silicon snake oil salespeople will visit you, take you out to someplace fancy, and try to convince you that the database tool, platform, or whatever-as-a-service (WaaS) that they’re selling can be the entire basis for your company’s software. Consider Microsoft SQL Server for a minute. At its most basic, SQL Server is a relational database. It stores your data in tables that you can query. Related tables of data can be joined and filtered allowing a developer who understands the Structured Query Language (SQL) to produce reporting data in any format or configuration. This is a common functionality found in every relational database tool from Microsoft Access and SQLite to Oracle and Microsoft SQL Server. Since SQL is a standardized language, offering this basic functionality is little more than table stakes. Just so we understand each other, all puns are intended.

So, how could Microsoft expect to charge money for something that you can get for free in open source offerings such as MySQL and PostgreSQL? Granted, SQL Server got started before they did when there were fewer rivals in the marketplace, but SQL Server is one of the most popular platforms for managing data today. This is because SQL Server’s value contribution doesn’t end with tabular data storage. As the product has grown over the years, new features and ancillary tools have been added. You have the ability to load and analyze data in novel and sophisticated ways using SQL Server Analysis Services. SQL Server Reporting Services allows you to create reports using SQL and then present those reports graphically to whoever might need them by emailing the reports as PDFs. It also allows users to access the report on the server and play around with the data without needing to know SQL or have access to the underlying code.

There are supported workflows for working with AI and machine learning projects using R and Python, and you can make bits of code in C# that process in the database such as a native stored procedure. SQL Server Integration Services allows you to ingest and publish data to a variety of different databases, software services, and industry formats. This leads to the ability to integrate your software and services with your business partners and customers.

In short, if you tried hard enough, you could probably write a great deal of an application, if not an entire one, solely using SQL Server’s ecosystem. SQL Server is the Golden Hammer. Every problem now looks as if it’s something that can be solved with SQL Server. I want to point out that I am not vilifying SQL Server. It’s a reliable and cost-effective set of tools. I go out of my way to recommend it at parties and my advice is always well received. Note to self: find better parties. I picked on SQL Server because I’ve seen it happen with this particular tool. If you spend too much time reading the marketing material for SQL Server, it would be easy for you to walk away with the same conclusion: that SQL Server is all you need. Maybe it is, but you should only make that decision after you understand the Golden Hammer antipattern, lest you wind up painting yourself into a technological corner.

The Golden Hammer also emerges when a developer learns about some technology that was unknown to them before. They use it. They like it. They’re rewarded for it in the form of fast or novel solutions to a problem. Since that worked out so well, and since they’ve gone to the effort of adding a new skill to their skill set, they try to use that tool or technique to solve every problem that they encounter.

Once, I took over a project that was in trouble. The lead programmer on a small team was being let go and most of his team left shortly after I replaced him. Interpersonal drama aside, I set out to understand the new project and the business domain by going through the existing code base.

I asked around and, as it turned out, the original staff on the project were with a consulting firm. The firm sent a couple of their ace developers over to meet and gather requirements. Upon seeing the prototypes that the client had themselves produced in Excel, using Visual Basic for Applications (VBA), the consultants concluded that they could produce real code in a real language and have a fully converted program running in under a month.

Two years went by with no usable deliverables. The ace developers either grossly underestimated the prototype they were working with or overestimated their capabilities. I think it was a little of both. Most developers look down their noses at VBA. I’ll admit that I used to, even though I’ve written quite a bit of VBA code. The consultants erroneously concluded that VBA is simplistic. They believed anything written in VBA would involve a trivial amount of effort to convert to a language as powerful as C#, backed by the equally powerful .NET Framework and SQL Server.

After a few months with very little progress, the consulting firm pulled their ace developers off the project to work on something else and the project was staffed entirely by junior developers.

Given the antipatterns we’ve covered so far, you can already see where this story is headed. I inherited this code after two and half years without a viable release. As I went through the existing code, I was able to see where the junior developers had encountered some tool or technique. It was as if I was looking at rings on a tree:

Figure 1.3 – The effects of new developers discovering a golden hammer are analogous to tree rings in their code.

You can tell exactly where they have learned that a stored procedure can be used in SQL Server because, from that point forward, the business logic suddenly moved out of the code and into the database. This is usually a bad idea. It’s often done because you can change the business rules without compiling and publishing a new executable, allowing you to make minor or major adjustments. This is roughly akin to working on the engine of an airplane while it’s flying at 1,261 knots (about 1,453 mph or 2,336 km/h) at 30,000 feet (9,144 m).

Somewhere else, you can tell they have read a book on patterns because the code changes. Suddenly, everything has interfaces and uses the factory pattern, which we’ll cover later in Chapter 3