Developing Extensible Software

This course will teach you patterns that allow you to build your software out of swappable building blocks, as well as allow future developers to extend it easily. You'll learn how to make your applications easier to maintain even while constantly changing and evolving, all while maintaining complete testability.

Course info

Rating

(506)

Level

Intermediate

Updated

Feb 5, 2014

Duration

3h 46m

Description

In today's competitive world of software development, using methodologies such as Agile lets us get products to market quicker and in a controlled fashion, but that's not enough. Applications need to be able to grow without being totally rewritten. Sure, there eventually comes a time when every app needs a major overhaul, but if applications are written to be extensible in the first place, the overhaul can be performed in pieces; and in the meantime, new features can be added or existing features changed without bringing the app down. This "extensibility" in our design is becoming more and more important every day as software shops compete with each other for work and even with other countries. There have been many articles and design documents written on things like inversion of control in the UI tiers. Many books have dedicated chapters to injecting objects into MVC controllers or WPF ViewModels, but not many have focused on the meat of a system, the business tiers. These are the tiers that are accessible to the UI of a system, more than one in many cases. And these are the tiers that can be most volatile and subject to change and enhancement. In this course, I'll show you some of my favorite extensibility designs and techniques which will let you write software in building blocks that can be connected and interconnected in different ways. I'll keep most of my focus on the business tiers, which despite the lack of user-centric visual glamour, is where you get to exercise the most creativity. You'll be able to roll out applications and continuously add or change things without affecting the core infrastructure in place. To me, this not only makes the software better, but more fun to write!

About the author

Whether playing on the local Radio Shack’s TRS-80 or designing systems for clients around the globe, Miguel has been writing software since he was 12 years old. He keeps himself heavily involved in every aspect, layer, nook, and cranny of app development and would not have it any other way.

Section Introduction Transcripts

Importance of ExtensibilityHi. This is Miguel Castro, and welcome back to Developing Extensible Software. Extensibility is no longer one of those topics that can be ignored in many apps. For too long, developers have thought of it as, well, if I don't need to support plugins, I don't need to worry about it. The end result is apps get torn open constantly just to change the way something gets done, or to add new functionality. Tearing open an app means recompiling it. It means retesting it, usually pretty extensive testing, and then of course, it means redeploying, which may, or may not be a bit of a headache, depending on your corporate scenario. With current market competition the way it is, and with that market being global, this is something we can no longer afford to keep doing. We need to write apps today in a way that they cannot only be maintained easier, but also enhanced, or have their functionality changed without the need for any kind of large scale redeployment each time. Apps and components today need to be written with more extensibility kept in mind at the forefront. This means many different things at different layers of an application. The layers that we'll concentrate on in this course are on the middle tier, which is where the meat of an app's functionality, and its processing takes place. But there are many UI-oriented patterns that can also be applied to an app, or a UI component, and many of them overlap with what I'm going to teach you here. Now, if you're already using things, like dependency injection, and programming new abstractions, and applying various design patterns in your applications, you're not only probably already writing much more testable code, but you are also on your way to writing more extensible apps.

Abstraction and Dependency InjectionHi, this is Miguel Castro, and welcome back to Developing Extensible Software. It's my opinion that no well-written system today should be developed without using some form of dependency injection. This is what gives us the basis for testability, and decoupledness with, or without the use of an actual container product. Now, of course, doing dependency injection without an actual container is going to be a lot more difficult. To be honest, I couldn't give any talk, session, or course on the topic of extensibility and leave out the topic of DI. Now, to implement dependency injection in my CommerceEngine, I first need to start abstracting things out. This means embracing the use of interfaces. Gone are the days when interfaces were only used in specific cases that needed more than one implementation of a class. Today, it's very normal to use interfaces for almost any class you write, since in many systems, almost every class is subject to dependency injection. In fact, abstraction, and interface usage will be key in all of the extensibility patterns I'm going to teach you. If you're already really familiar with how DI works, you already have a really good head start, because what varies between conventional DI, and all the other patterns I'm going to add later, is pretty much how the interface types get defined, resolved, and how they get changed out. Throughout the rest of this course, you'll see that DI will be intertwined with all my other patterns to achieve maximum testability in all cases. So next I'm going to implement dependency injection into the CommerceEngine I showed you earlier, and you'll see how this first step will make it completely testable, and set me on the road to further extending it later.

Implementing ProvidersHi. This is Miguel Castro, and welcome back to Developing Extensible Software. Provider is a pretty overloaded term, but only in implementation. Almost everyone's flavor of a provider model is some kind of implementation of a strategy pattern. This includes Microsoft's ASP. NET providers. Basically, it's all about defining multiple implementations of an abstraction, and deciding at some later point in time which one to use in an application, or a component. Now if this sounds familiar, it should. I just finished doing something similar to the repository, and the other helper classes in the last module by subjecting them to dependency injection. But, as I stated in the end of the last module, if I wanted to change out implementations later, I'd have to provide a different registration into the client. I want to be able to do this through configuration. In fact, I also want to be able to configure any additional pieces of information that a provider may need without having to go back into the code. Not only that, I want to keep it all centralized in an easy to manage location so that's no configuration for each provider scattered in different parts of the config file. The idea is that later, if I want to provide the CommerceEngine with a different implementation of a provider, I can write it externally as a new project, and simply deploy that component, needing to only change the configuration, and never having to touch the CommerceEngine, nor the client. So first, I'm going to convert the usage of the PaymentProcessor and the Mailer components to be provider based. I'm going to leave the Repository class alone throughout the rest of this course. Now this first step is going to hard lock my CommerceEngine into how it obtains providers, losing a little testability. But afterward, I'm going to incorporate DI in conjunction with my providers to make it all completely testable once again.

Implementing ModulesHi. This is Miguel Castro, and welcome back to Developing Extensible Software. Obviously, the term module can be applied to many things in software development. The way I use it is to describe a class that satisfies an interception point exposed by some kind of hosting code. These are classes that are written externally of the hosting app to either extend, or replace functionality. The pattern is based on the Gang of Four's Chain of Responsibility pattern, and many of you have seen it before. ASP. NET's pipeline is based on HTTP modules, and some of you may have written these type of modules before. If you have, you're going to feel right at home, because the pattern I'm going to be using is practically identical to that used by ASP. NET. In ASP. NET, you can write an HTTP module to tap into an extensibility point of the ASP. NET pipeline, and either replace, or add functionality that acts upon an HTTP request, or an HTTP response. Later, I'm actually going to go into pipelines, and we'll even implement one here. But first, I'm going to show you how you can write modules that add functionality to the CommerceEngine, functionality that I may not have thought of when I first wrote this simple engine. A module can be written similarly to a provider, then dropped into the execution folder of an application, or the component hosting it. It can then be configured along with any additional information it requires to work. Once again, similarly to providers. And like in the provider model, all without any change of the hosting application, so no recompilation, and no redeployment.

PipelinesHi. This is Miguel Castro, and welcome back to Developing Extensible Software. A pipeline is nothing more than a component that exposes a series of interception points that act upon a chunk of data. This component's job is simply to fire off events, each representing an interception point. The pattern behind it in fact is exactly the same module pattern I taught you in the previous course module. A client kicks off the process, and data just moves from one point to the next. Each point is designed to check for, and/or do something different to the data. The code that executes at each point of interception is typically swappable in some way. In this case, using the module pattern. This design is at the very heart of both ASP. NET and WCF.

Procedural OverridingHi. This is Miguel Castro, and welcome back to Developing Extensible Software. Okay, so this is not the most creative name for a pattern. Sorry. Couldn't think of anything better to be honest with you. The first thing I want to say about this pattern is that it is not, neither an evolution of any previous pattern, or technique that I've shown you, nor is it a regression. This is merely an alternative, and it is especially useful when you have an existing application, or component, whose flexibility you want to improve without a lot of work, and also without any configuration. You'll see that the project starter for this module does not even use any of the providers. Instead, the task of processing a payment and sending out an email is all a core piece of the CommerceEngine. So there really isn't a lot of flexibility. I'm going to start by isolating the pieces of functionality that are currently hardcoded, and whose flexibility I want to improve. In this case, the payment processing and notification section. This functionality will be pulled out into its own classes, but still maintained as part of the core application. However, I will adjust the CommerceManager class so that the client invoking it will have the ability to replace this functionality, and all of this will be done procedurally, not declaratively. So again, there will be no configuration. This is a very easy pattern to implement, and I've used it in many, many different places, and it's always proven its usefulness.

Using MEFHi. This is Miguel Castro, and welcome back to Developing Extensible Software. I struggled a bit with the decision to include, or not include MEF coverage in this course. But, to be honest, I can't in good conscience discuss extensibility in. NET applications and not talk about MEF. The Manage Extensibility Framework, or MEF, as it is called, is Microsoft's answer to an easy to use plugin framework. Because it's from Microsoft, a lot of times that's reason enough for a lot of companies to want to adopt it, and want to use it. MEF is based on the idea of decorating classes with certain attributes, and letting it go out and find things, discover things. Because of the attributes that it uses, evidence of its usage is scattered throughout the application. MEF makes it very easy to instantiate classes based on abstraction. In fact, its approach is one of dependency injection. For that reason, MEF is often used as a DI container as well. But like my solution for dropping modules into folders, and having the ConfigurationFactory go find them, MEF also eliminates the ability to define configuration parameters that your providers, or modules can use, because there is no configuration. I personally prefer raw extensibility patterns in most cases, because I can customize, and tweak them to my taste depending on my application needs. Now, that being said, MEF works just fine in simple cases where you need a fast solution, and not a lot of customization ability. I'll be taking the solution that I finished with in the Advanced Module Usage course module, and modifying it so that it uses MEF instead.

ConclusionHi. This is Miguel Castro, and welcome back to Developing Extensible Software. The patterns I've shown you in this course will help give your applications, and components some tremendous flexibility. Flexibility and enhancements that can be provided by you, or whatever developer comes in later. That's the power here, to write applications that embrace the idea that you might not have thought of everything, but someone else can also improve on it. These improvements can be performed using patterns that do not require application recompiling, nor redeployment. Now, don't go picking a pattern and try to shove it down an application's throat. Think about how you want to break up an app, or a component, and let the needs, and requirements help steer you. The separation of concerns these patterns provide, also provides some great manageability for your code. And remember, configuration is not a bad thing. It helps you execute changes in behavior without changing code. I hope you've enjoyed the course. I promised you a shorter course than the last one, but hopefully one as enjoyable as I've been told my first course was. If you haven't watched my first course, please visit Pluralsight. com and remember to watch Building End-to-End Multi-Client Service Oriented Applications. Now, I must leave you and get to work on part two of my first course. So, until we meet again, thank you so much for watching, and please do not hesitate to use the course discussion board for any questions, or general comments you have. If you've used it for my previous course, you know that I personally monitor it closely, and answer each and every posting you hit me with. Take care.