Refactoring with C#....2
Foreword....7
Contributors....8
About the author....8
About the reviewers....9
Preface....26
Who this book is for....27
What this book covers....28
To get the most out of this book....29
Download the example code files....30
Conventions used....30
Get in touch....31
Share Your Thoughts....31
Download a free PDF copy of this book....32
Part 1: Refactoring with C# in Visual Studio....33
Chapter 1: Technical Debt, Code Smells, and Refactoring....34
Understanding technical debt and legacy code....34
Where technical debt comes from....35
Identifying code smells....36
Introducing refactoring....37
Refactoring tools in Visual Studio....38
Case study – Cloudy Skies Airlines....39
Summary....40
Questions....41
Further reading....41
Chapter 2: Introduction to Refactoring....42
Technical requirements....42
Refactoring a baggage price calculator....42
Converting properties to auto properties....44
Introducing locals....45
Introducing constants....48
Introducing parameters....49
Removing unreachable and unused code....51
Extracting methods....54
Refactoring manually....56
Testing refactored code....57
Refactoring in other editors....58
Refactoring in Visual Studio Code with the C# Dev Kit....59
Refactoring in JetBrains Rider....60
Refactoring in Visual Studio with ReSharper....60
Summary....61
Questions....61
Further reading....62
Chapter 3: Refactoring Code Flow and Iteration....63
Technical requirements....63
Refactoring the boarding app....63
Controlling program flow....64
Inverting if statements....66
Dropping else statements after return statements....67
Restructuring if statements....68
Using ternary operators....70
Converting if statements into switch statements....71
Converting to switch expressions....75
Instantiating objects....77
Replacing var with explicit Types....77
Simplifying creation with target-typed new....78
Using object initializers....79
Iterating over collections....81
Introducing foreach....82
Converting to for loops....83
Converting to LINQ....84
Refactoring LINQ statements....85
Choosing the correct LINQ method....86
Combining LINQ methods....87
Transforming with Select....88
Reviewing and testing our refactored code....89
Summary....90
Questions....90
Further reading....91
Chapter 4: Refactoring at the Method Level....92
Technical requirements....92
Refactoring the flight tracker....92
Refactoring methods....94
Changing method access modifiers....94
Renaming methods and parameters....95
Overloading methods....97
Chaining methods....98
Refactoring constructors....99
Generating constructors....100
Chaining constructors....102
Refactoring parameters....103
Reordering parameters....103
Adding parameters....105
Introducing optional parameters....108
Removing parameters....109
Refactoring to functions....110
Using expression-bodied members....111
Passing functions as parameters with actions....112
Returning data from Actions with Funcs....114
Introducing static methods and extension methods....116
Making methods static....116
Moving static members to another type....117
Creating extension methods....119
Reviewing and testing our refactored code....121
Summary....122
Questions....122
Further reading....122
Chapter 5: Object-Oriented Refactoring....123
Technical requirements....123
Refactoring the flight search system....123
Organizing classes via refactoring....124
Moving classes to individual files....124
Renaming files and classes....126
Changing namespaces....127
Avoiding partial classes and regions....128
Refactoring and inheritance....130
Overriding ToString....130
Generating equality methods....134
Extracting a base class....137
Moving interface implementations up the inheritance tree....140
Controlling inheritance with abstract....144
Communicating intent with abstract....144
Introducing abstract members....144
Converting abstract methods to virtual methods....147
Refactoring for better encapsulation....149
Encapsulating fields....149
Wrapping parameters into a class....150
Wrapping properties into a class....153
Favoring composition over inheritance....155
Improving classes with interfaces and polymorphism....157
Extracting interfaces....157
Providing default interface implementations....159
Introducing polymorphism....160
Reviewing and testing our refactored code....163
Summary....164
Questions....164
Further reading....164
Part 2: Refactoring Safely....165
Chapter 6: Unit Testing....166
Technical requirements....166
Understanding testing and unit tests....166
Types of tests and the testing pyramid....167
Unit tests....169
Testing code with xUnit....171
Creating an xUnit Test Project....171
Connecting the xUnit Test Project to your main project....173
Writing your first unit test....174
Organizing tests with Arrange/Act/Assert....175
Understanding tests and exceptions....177
Adding additional test methods....178
Refactoring unit tests....178
Parameterizing tests with Theory and InlineData....179
Initializing test code with constructors and fields....180
Sharing test code with methods....182
Exploring other testing frameworks....184
Testing with NUnit....184
Testing with MSTest....185
Adopting a testing mindset....186
Incorporating testing into your workflow....186
Isolating dependencies....187
Evaluating good and bad tests....188
Thoughts on code coverage....189
Summary....191
Questions....191
Further reading....191
Chapter 7: Test-Driven Development....193
Technical requirements....193
What is Test-Driven Development?....193
Test-Driven Development with Visual Studio....195
Setting the starting balance....195
Adding miles and generating methods....200
Redeeming miles and refactoring tests....201
When to use Test-Driven Development....204
Summary....205
Questions....205
Further reading....205
Chapter 8: Avoiding Code Anti-Patterns with SOLID....206
Identifying anti-patterns in C# code....206
Writing SOLID code....207
Single Responsibility Principle....208
Open-Closed Principle....210
Liskov Substitution Principle....211
Interface Segregation Principle....212
Dependency Inversion Principle....214
Considering other architectural principles....215
Learning the DRY principle....215
KISS principle....217
Understanding high cohesion and low coupling....217
Summary....218
Questions....218
Further reading....218
Chapter 9: Advanced Unit Testing....220
Technical requirements....220
Creating readable tests with Shouldly....220
Installing the Shouldly NuGet package....221
Writing readable assertions with Shouldly....223
Writing readable assertions with FluentAssertions....225
Testing performance with Shouldly....226
Generating test data with Bogus....228
Mocking dependencies with Moq and NSubstitute....231
Understanding the need for mocking libraries....231
Creating mock objects with Moq....233
Programming Moq return values....234
Verifying Moq calls....235
Mocking with NSubstitute....236
Pinning tests with Snapper....237
Experimenting with Scientist .NET....238
Summary....241
Questions....241
Further reading....242
Chapter 10: Defensive Coding Techniques....243
Technical requirements....243
Introducing the Cloudy Skies API....243
Validating inputs....244
Performing basic validation....245
Using the nameof keyword....246
Validation with guard clauses....247
Guard clauses with the GuardClauses library....247
Using CallerMemberInformation attributes....248
Protecting against null....250
Enabling nullability analysis in C#....251
Using nullability operators....252
Moving beyond classes....253
Preferring immutable classes....253
Using required and init-only properties....255
Primary constructors....256
Converting classes into record classes....257
Cloning objects using with expressions....258
Advanced type usage....259
Exploring pattern matching....259
Using generics to reduce duplication....260
Introducing type aliases with the using directive....262
Summary....263
Questions....264
Further reading....264
Part 3: Advanced Refactoring with AI and Code Analysis....265
Chapter 11: AI-Assisted Refactoring with GitHub Copilot....266
Technical requirements....266
Introducing GitHub Copilot....266
Understanding GitHub’s predictive model....267
Starting the conversation with GitHub Copilot Chat....268
Getting started with GitHub Copilot in Visual Studio....270
Installing and activating GitHub Copilot....271
Getting access to GitHub Copilot....272
Generating suggestions with GitHub Copilot....272
Interacting with GitHub Copilot Chat....273
Refactoring with GitHub Copilot Chat....276
GitHub Copilot Chat as a code reviewer....278
Targeted refactoring with GitHub Copilot Chat....278
Drafting documentation with GitHub Copilot Chat....280
Generating test stubs with GitHub Copilot Chat....283
Understanding the limits of GitHub Copilot....286
Data privacy and GitHub Copilot....286
Concerns around GitHub Copilot and public code....287
Case study: Cloudy Skies Airline....288
Summary....289
Questions....289
Further reading....289
Chapter 12: Code Analysis in Visual Studio....290
Technical requirements....290
Calculating code metrics in Visual Studio....290
Performing code analysis in Visual Studio....293
Analyzing your solution using the default ruleset....294
Configuring code analysis rulesets....297
Responding to code analysis rules....299
Treating warnings as errors....302
Exploring advanced code analysis tools....303
Tracking code metrics with SonarCloud and SonarQube....303
In-depth .NET analysis with NDepend....305
Case study – Cloudy Skies Airline....309
Summary....310
Questions....310
Further reading....310
Chapter 13: Creating a Roslyn Analyzer....312
Technical requirements....312
Understanding Roslyn Analyzers....312
Installing the extension development workload and DGML editor....313
Introducing Syntax Visualizer....314
Creating a Roslyn Analyzer....317
Adding the analyzer project to our solution....317
Defining a code analysis rule....319
Analyzing symbols with our Roslyn Analyzer....321
Tips for writing Roslyn Analyzers....322
Testing Roslyn Analyzers with RoslynTestKit....323
Adding a Roslyn Analyzer test project....323
Creating AnalyzerTestFixture....324
Verifying that our Roslyn Analyzer doesn’t flag good code....325
Verifying that our Roslyn Analyzer flags bad code....326
Debugging Roslyn Analyzers....326
Sharing analyzers as Visual Studio extensions....327
Creating a Visual Studio extension (VSIX) for your Roslyn Analyzer....327
Summary....331
Questions....331
Further reading....331
Chapter 14: Refactoring Code with Roslyn Analyzers....332
Technical requirements....332
Case study – Cloudy Skies Airlines....332
Building a Roslyn Analyzer code fix....333
Creating a CodeFixProvider....333
Registering a code fix....334
Modifying the document with a code fix....335
Testing Code Fixes with RoslynTestKit....337
Publishing Roslyn Analyzers as NuGet packages....339
Understanding NuGet package deployment....339
Building a NuGet package....340
Deploying the NuGet package....343
Referencing the NuGet package....344
Packaging a CodeFixProvider as an extension....346
Summary....347
Questions....347
Further reading....347
Part 4: Refactoring in the Enterprise....349
Chapter 15: Communicating Technical Debt....350
Overcoming barriers to refactoring....350
Urgent deadlines....351
“Don’t touch high-risk code”....351
“This code is going away, don’t spend time on it”....352
End-of-life applications....353
“Just do the minimum required”....354
“Refactoring doesn’t provide business value”....355
Communicating technical debt....356
Technical debt as risk....356
Creating a risk register....357
Alternatives to a risk register....358
Prioritizing technical debt....358
Calculating risk priorities with a risk score....358
The “gut feeling” approach....359
Getting organizational buy-in....360
Setting up the conversation....360
Anticipating questions and objections....361
Different approaches for different leaders....362
The importance of communication....363
Case study – Cloudy Skies Airlines....363
Summary....365
Questions....366
Further reading....366
Chapter 16: Adopting Code Standards....367
Technical requirements....367
Understanding code standards....367
Establishing code standards....369
Formatting and code cleanup in Visual Studio....373
Applying code standards with EditorConfig....377
Reviewing our starter code....378
Adding an EditorConfig....379
Customizing EditorConfigs....379
Summary....381
Questions....381
Further reading....381
Chapter 17: Agile Refactoring....383
Refactoring in an agile environment....383
Key elements of agile teams....383
Understanding obstacles to refactoring....384
Succeeding with agile refactoring strategies....385
Dedicated work items for refactoring efforts....385
Refactoring code as it changes....386
Refactoring sprints....387
Refactoring sabbaticals....388
Accomplishing large-scale refactorings....389
Why large refactorings are difficult....389
The rewrite trap....390
Lessons from the ship of Theseus....390
Upgrading projects with.NET Upgrade Assistant....391
Refactoring and the strangler fig pattern....393
Recovering when refactoring goes wrong....394
The impact of failed refactorings....395
Establishing safety in agile environments....395
Deploying large-scale refactorings....396
Using feature flags....396
Phased rollouts and blue/green deployments....397
The value of continuous integration and continuous delivery....399
Case study – Cloudy Skies Airlines....400
Summary....401
Toward more sustainable software....401
Questions....402
Further reading....402
Index....403
Why subscribe?....425
Other Books You May Enjoy....425
Packt is searching for authors like you....429
Share Your Thoughts....429
Download a free PDF copy of this book....429
Software projects start as brand-new greenfield projects, but invariably become muddied in technical debt far sooner than you’d expect. In Refactoring with C#, you'll explore what technical debt is and how it arises before walking through the process of safely refactoring C# code using modern tooling in Visual Studio and more recent C# language features using C# 12 and .NET 8. This book will guide you through the process of refactoring safely through advanced unit testing with XUnit and libraries like Moq, Snapper, and Scientist .NET. You'll explore maintainable code through SOLID principles and defensive coding techniques made possible in newer versions of C#. You'll also find out how to run code analysis and write custom Roslyn analyzers to detect and resolve issues unique to your code.
The nature of coding is changing, and you'll explore how to use AI with the GitHub Copilot Chat to refactor, test, document, and generate code before ending with a discussion about communicating technical debt to leadership and getting organizational buy-in to refactor your code in enterprise organizations and in agile teams.
By the end of this book, you'll understand the nature of refactoring and see how you can safely, effectively, and repeatably pay down the technical debt in your application while adding value to your business.
This book is for any developer familiar with C# who wants to improve the code they work with on a day-to-day basis. While this book will be most beneficial to new developers with only a year or two of experience, even senior engineers and engineering managers can make the most of this book by exploring not just the process of refactoring, but advanced techniques with libraries like Moq, Snapper, Scientist .NET, and writing custom Roslyn analyzers.