SKIP THE SHIPPING
Use code NOSHIP during checkout to save 40% on eligible eBooks, now through January 5. Shop now.
Register your product to gain access to bonus material or receive a coupon.
This eBook includes the following formats, accessible from your Account page after purchase:
EPUB The open industry format known for its reflowable content and usability on supported mobile devices.
PDF The popular standard, used most often with the free Acrobat® Reader® software.
This eBook requires no passwords or activation to read. We customize your eBook by discreetly watermarking it with your name, making it uniquely yours.
Reengineer .NET Code to Improve Quality, Update Architecture, Access New Tools, and Accelerate Delivery of New Features
As software ages, it becomes brittle: difficult to understand, fix, manage, use, and improve. Developers working with many platforms have encountered this problem; now, developers working with Microsoft’s .NET are facing it as well. In Reengineering .NET, leading .NET architect Bradley Irby introduces proven best practices for revitalizing older .NET code and integrating new architectural and development advances into business-critical systems that can’t go offline. Using a step-by-step approach, .NET professionals can make legacy enterprise software more reliable, maintainable, attractive, and usable—and make it easier to upgrade for years to come.
Through real-world case studies and extensive downloadable sample code, Irby shows how to carefully plan a .NET reengineering project, understand the true current state of your code, introduce unit testing and other agile methods, refactor to services and controllers, and leverage powerful .NET reengineering tools built into Microsoft Visual Studio 2012.
This book is an indispensable resource for all developers, architects, and project managers responsible for existing .NET code bases and for a wide audience of non-technical managers and CTOs who want to understand the unique challenges faced by .NET teams involved in application or system reengineering projects.
Coverage includes
• Migrating legacy .NET software to more flexible, extensible, and maintainable architectures—without breaking it
• Reengineering web applications with the MVC pattern, Winforms software with MVP, and WPF/Silverlight systems with MVVM
• Asking the right questions to predict refactoring problems before they happen
• Planning and organizing reengineering projects to apply the right expertise to each task at the right time
• Using innovative Test Doubling to make unit testing even more effective
• Applying Dependency Inversion to break tight coupling and promote easier development and testing
• Leveraging source control, defect tracking, and continuous integration
• “Cleaning up” legacy solutions to improve them before you even touch business logic
• Establishing solid development infrastructure to support your reengineering project
• Refactoring to services—including advanced techniques using Repositories, Domain Models, and the Command Dispatcher
• Refactoring to controller/view or ViewModel/View pairs
Preface xiii
Acknowledgments xix
About the Author xxi
PART I Target Architecture
1 Implementing a Service-Oriented Architecture 3
An Overview of the Service-Oriented Architecture 4
Understanding Standardized Service Contracts 6
Interfaces 6
Understanding Coupling 12
Understanding Service Abstraction 15
Designing Reusable Services 18
Understanding Service Autonomy and Service Composability 18
Understanding Service Statelessness 19
A Service Example 24
Summary 26
2 Understanding Application Architecture 27
Working with Architectural Patterns 27
An Overview of Architectural Patterns 28
Differences Among MVP, MVC, and MVVM 29
Model Access 30
View Models 31
Handling UI Events 38
How Do the Patterns Work? 43
Which Pattern Should You Choose? 45
Summary 45
3 Unit Testing 47
An Example of Unit Testing 48
Creating Unit Tests 49
Writing a Test 52
Detecting Exceptions 58
Understanding the Power of Assert 61
Comparing Unit Tests to Integration Tests 61
Using the InternalsVisibleTo Attribute 62
Understanding Test Driven Development 65
Learning More About Unit Testing 65
Summary 66
4 Understanding the Dependency Inversion Principle 67
Understanding Tight Coupling 67
Implementing the Abstract Factory Pattern 74
Introducing Interfaces 79
Creating Unit Tests 82
Understanding Service Location 84
Inversion of Control Containers 84
Service Locator 88
A Real World Example 90
OnDemand Service Properties 96
Unit Testing Advantages 99
Final Tweaks 100
Using Dependency Injection 103
Why Is Service Location Better for Reengineering? 108
Summary 113
5 Using Test Doubles with Unit Tests 115
How Do Test Doubles Work? 115
What Need Do Test Doubles Satisfy? 116
Creating a Stub 119
Distinguishing Between Mocks and Stubs 123
Creating a Mock 124
A Second Mocking Example 128
A Third Mocking Example 129
Using Mocking System Services 130
Learning More About Test Doubles 133
Summary 133
PART II Reengineering
6 Initial Solution Review 137
Analyzing the Code 138
Basic Architecture 138
Code Structure 139
Database Access 140
Data Structures 140
External Interfaces 141
Application Controls Versus Form Controls 142
Analyzing the General Code Structure 142
Managing Language Migration 144
Removing Dead Code 145
Using Global Variables 145
Converting Code: It’s Not All or Nothing 149
Using an Automated Code Conversion Utility 150
Using Data Access Technologies 152
Detecting the Data Model 152
Detecting the Data Access Pattern 154
Summary 155
7 Planning the Project 157
Managing Expectations 157
Creating the Reengineering Team 158
Identifying Development Tools and the Build Process 159
Introducing Source Control 160
Introducing Defect Tracking 161
Installing and Using a Continuous Integration (CI) Server 161
Cleaning Up Legacy Solutions 162
Establishing the Foundation 163
Refactoring to Use Basic Services 164
Refactoring to Use Advanced Services 166
Reporting Progress to Stakeholders 166
Managing Communication and Training 167
Summary 168
8 Identifying Development Tools and the Build Process 169
Using Source Control 169
Types of Source Control 170
A Process Example: Using a Distributed System 171
A Second Process Example: Using a Distributed System 172
A Third Process Example: Using a Centralized System 173
Understanding the Pros and Cons of Centralized Systems and Distributed Systems 173
Consuming Shared Code from Others 173
Sharing Code with Others and Reviewing Changes 174
Backing up the Code 174
Managing Check-in Frequency 175
Managing Merge Conflicts 175
Managing Control 176
A Final Word About Pros and Cons 176
Evaluating a Hosting Service 176
Using Apache Subversion (SVN) 177
Using Microsoft Team Foundation Server (TFS) 177
Using Git 179
Managing Features and Defects 179
Managing Custom Workflow 180
Managing Agile Development 180
Managing Reporting 180
Using a Continuous Integration (CI) Build Server 181
Using Visual Studio 2010 Developer Tools 181
Refactoring Tools in Visual Studio 182
Third-Party Refactoring Tools 183
Summary 185
9 Cleaning Up Legacy Solutions 187
Organizing the File System 187
Structuring the Project 189
Working with Project Categories 190
Understanding Project Types 191
Application-Agnostic Projects 192
Generic UI Projects 192
Model-agnostic Projects 193
Model-specific Projects 193
Reengineering Project Recommendations 193
Constants 194
Data Transfer Objects (DTO) Projects 195
Interfaces 196
Services 197
Domain Model Projects 198
Repository Projects 199
Controllers, View Models, and Presenters 199
Refactoring to the Solution Structure 200
Remove Unnecessary Using Clauses 200
Separate Unit Tests and Integration Tests 201
Move Classes to Appropriate Projects 202
Move Shortcuts to Libraries 202
Refactorings that Affect Logic 203
Move Initialization Logic into the Constructor 204
Replace Nested IF Statements with Guards 205
Removing Access to Entity Class Constructors 210
Summary 211
10 Establishing the Foundation 213
Adding New Projects 213
Using Prism, Unity, and Enterprise Library Versions 214
Adapting the Shell 216
Creating the IBaseView 217
Adapting the Current Shell 218
Adding a Shell Controller 220
Creating the Service Locator 220
Setting Up the BootStrapper Class 223
Creating the Winforms BootStrapper 223
Updating the Winforms Program Class 226
Creating a WPF Application and Bootstrapper 228
Using Alternative Bootstrapper Configurations 232
Summary 236
11 Basic Refactoring to Services 237
Using DialogService 238
Unit Testing 242
Refactoring for DialogService 249
Adding Unit Tests 250
Using LogWriterService 251
Refactoring for LogWriterService 254
Tracking Session Information 257
Refactoring for Session Information 258
Accessing Resources the SOA Way 260
Refactoring for ResourceProvider 264
Using a Message Aggregator 265
Refactoring for MessageAggregator 266
Converting Static Classes 271
Refactoring Static Classes 272
Summary 273
12 Advanced Refactoring to Services 275
Using a Repository Pattern 275
Creating a Repository with a Domain Model 283
Reengineering Methods to a Repository 288
Converting Existing Code to Use a Domain Model 289
Adding Data Validations to the Domain Model 291
Reengineering Domain Models to Use Validations 296
Using a Generic Object Manager 296
Simplifying Complex Code with a Command Dispatcher Service 303
Refactoring for CommandLineInterpreter 313
Summary 314
13 Refactoring to a Controller 315
Using the Legacy Approach to Form Creation 316
Preparing the View 319
Introducing the Controller 320
Enhancing the Controller 322
Summary 325
Appendix Reengineering .NET Projects with Visual Studio 2012 327
Examining Source Control with Visual Studio 2012 327
Managing Parallel Development 330
Making Changes in Isolation 334
Unit Testing with Visual Studio 2012 337
Writing a Unit Test Method 338
Running the Unit Test 339
Using the Edit-and-Continue Feature 341
Using Continuous Test Runner 344
Using Fakes to Write Unit Tests for “Untestable” Code 346
Looking for Hard-to-Maintain Code Using Code Metrics 348
Looking for Code Duplicates 350
Summary 353
Index 355