ENTERPRISE

Microsoft .NET : Design Principles and Patterns - From Principles to Patterns (part 1)

2/21/2013 8:29:22 PM

It is guaranteed that by fulfilling all the OOD principles just discussed, you can craft a good design that matches requirements and is maintainable and extensible. A seasoned development team, though, will not be limited to applying effective design principles over and over again; members of the team, in fact, will certainly draw from the well of their experience any solutions for similar problems that worked in the past.

Such building blocks are nothing more than hints and the skeleton of a solution. However, these very same building blocks can become more refined day after day and are generalized after each usage to become applicable to a wider range of problems and scenarios. Such building blocks might not provide a direct solution, but they usually help you to find your (right) way. And using them is usually more effective and faster than starting from scratch.

By the way, these building blocks are known as patterns.

1. What’s a Pattern, Anyway?

The word pattern is one of those overloaded terms that morphed from its common usage to assume a very specific meaning in computer science. According to the dictionary, a pattern is a template or model that can be used to generate things—any things. In computer science, we use patterns in design solutions at two levels: implementation and architecture.

At the highest level, two main families of software patterns are recognized: design patterns and architectural patterns. You look at design patterns when you dive into the implementation and design of the code. You look at architectural patterns when you fly high looking for the overall design of the system.

Let’s start with design patterns.

Note

A third family of software patterns is also worth a mention—refactoring patterns. You look at these patterns only when you’re engaged in a refactoring process. Refactoring is the process of changing your source code to make it simpler, more efficient, and more readable while preserving the original functionality. Examples of refactoring patterns are "Extract Interface" and "Encapsulate Field." Some of these refactoring patterns have been integrated into Visual Studio 2008 on the Refactor menu. You find even more patterns in ad hoc tools such as Resharper. (For more information, see http://www.jetbrains.com/resharper.)

Design Patterns

We software professionals owe design patterns to an architect—a real architect, not a software architect. In the late 1970s, Christopher Alexander developed a pattern language with the purpose of letting individuals express their innate sense of design through a sort of informal grammar. From his work, here’s the definition of a pattern:

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core solution to that problem, in such a way that you can use the solution a million times over, without ever doing it the same way twice.

Nicely enough, although the definition was not written with software development in mind, it applies perfectly to that. So what’s a design pattern?

A design pattern is a known and well-established core solution applicable to a family of concrete problems that might show up during implementation. A design pattern is a core solution and, as such, it might need adaptation to a specific context. This feature becomes a major strength when you consider that, in this way, the same pattern can be applied many times in many slightly different scenarios.

Design patterns are not created in a lab; quite the reverse. They originate from the real world and from the direct experience of developers and architects. You can think of a design pattern as a package that includes the description of a problem, a list of actors participating in the problem, and a practical solution.

The primary reference for design patterns is GoF. Another excellent reference we want to recommend is Pattern-Oriented Software Architecture by Frank Buschmann, et al. (Wiley, 1996).

How to Work with Design Patterns

Here is a list of what design patterns are not:

  • Design patterns are not the verb and should never be interpreted dogmatically.

  • Design patterns are not Superman and will never magically pop up to save a project in trouble.

  • Design patterns are neither the dark nor the light side of the Force. They might be with you, but they won’t provide you with any special extra power.

Design patterns are just helpful, and that should be enough.

You don’t choose a design pattern; the most appropriate design pattern normally emerges out of your refactoring steps. We could say that the pattern is buried under your classes, but digging it out is entirely up to you.

The wrong way to deal with design patterns is by going through a list of patterns and matching them to the problem. Instead, it works the other way around. You have a problem and you have to match the problem to the pattern. How can you do that? It’s quite simple to explain, but it’s not so easy to apply.

You have to understand the problem and generalize it.

If you can take the problem back to its roots, and get the gist of it, you’ll probably find a tailor-made pattern just waiting for you. Why is this so? Well, if you really reached the root of the problem, chances are that someone else did the same in the past 15 years (the period during which design patterns became more widely used). So the solution is probably just there for you to read and apply.

What we normally do is stop reading after the first few pages precisely where most books list the patterns they cover in detail inside. Next, we put the book aside and possibly within reach. Whenever we encounter a problem, we try to generalize it, and then we flip through the pages of the book to find a pattern that possibly matches it. We find one much more often than not. And if we don’t, we repeat the process in an attempt to come to a better generalization of the problem.

When we’ve found the pattern, we start working on its adaptation to our context. This often requires refactoring of the code which, in turn, might lead to a more appropriate pattern. And the loop goes on.

Note

If you’re looking for an online quick reference about design patterns, you should look at http://www.dofactory.com. Among other things, the site offers .NET-specific views of most popular design patterns.

Where’s the Value in Patterns, Exactly?

Many people would agree in principle that there’s plenty of value in design patterns. Fewer people, though, would be able to indicate what the value is and where it can be found.

Using design patterns, per se, doesn’t make your solution more valuable. What really matters, at the end of the day, is whether or not your solution works and meets requirements.

Armed with requirements and design principles, you are up to the task of solving a problem. On your way to the solution, though, a systematic application of design principles to the problem sooner or later takes you into the immediate neighborhood of a known design pattern. That’s a certainty because, ultimately, patterns are solutions that others have already found and catalogued.

At that point, you have a solution with some structural likeness to a known design pattern. It is up to you, then, to determine whether an explicit refactoring to that pattern will bring some added value to the solution. Basically, you have to decide whether or not the known pattern you’ve found represents a further, and desirable, refinement of your current solution. Don’t worry if your solution doesn’t match a pattern. It means that you have a solution that works and you’re happy with that. You’re just fine. You never want to change a winning solution!

In summary, patterns might be an end when you refactor according to them, and they might be a means when you face a problem that is clearly resolved by a particular pattern. Patterns are not an added value for your solution, but they are valuable for you as an architect or a developer looking for a solution.

Applied Design Patterns

We said a lot about design patterns, but we haven’t shown a single line of code or a concrete example. Patterns are everywhere, even if you don’t realize it. As we’ll see in a moment, sometimes patterns are buried in the language syntax—in which case, we’ll call them idioms.

Have you ever needed to use a global object (or a few global objects) to serve all requests to a given class? If you have, you used the Singleton pattern. The Singleton pattern is described as a way to ensure that a class has only one instance for which a global point of access is required. Here’s an example:

public class Helpers
{
  public static Helpers DefaultInstance = new Helpers();

  protected Helpers() {}

  public void DoWork()
  {
    .
    .
    .
  }

  public void DoMoreWork()
  {
    .
    .
    .
  }
}

In a consumer class, you take advantage of Helpers through the following syntax:

Helpers.DefaultInstance.DoWork();

Swarms of Visual Basic 6 developers have used the Singleton pattern for years probably without ever realizing it. The Singleton pattern is behind the default instance of Visual Basic 6 forms, as shown here:

Form1.Show()

The preceding code in Visual Basic 6 invokes the Show method on the default instance of the type Form1. In the source, there’s no explicit mention of the default instance only because of the tricks played by the Visual Basic runtime.

Tip

Admittedly, the Singleton pattern on a class is similar to defining the same class with only static methods. Is there any difference?

With a Singleton pattern, you can actually control the number of instances because you’re not actually limited to just one instance. In addition, you can derive a new (meaningful) class because the Singleton pattern has some instance-level behavior and is not a mere collection of static functions. Finally, you have more freedom to control the creation of the actual instance. For example, you can add a static method, say, GetInstance, instead of the static field and add there any logic for the factory.

Another interesting pattern to briefly mention is the Strategy pattern. The pattern identifies a particular functionality that a class needs and can be hot-plugged into the class. The functionality is abstracted to an interface or a base class, and the Strategy-enabled class uses it through the abstraction, as shown here:

public class MyService
{
  // This is the replaceable strategy
  ILogger _logger;

  public MyService(ILogger logger)
  {
    this._logger = logger;
  }

  public void DoWork()
  {
    this._logger.Log("Begin method ...");
    .
    .
    .
    this._logger.Log("End method ...");
  }
}

The Strategy pattern is the canonical example used to illustrate the power of composition. The class MyService in the example benefits from the services of a logger component, but it depends only on an abstraction of it. The external logger component can be changed with ease and without risking breaking changes. Moreover, you can even change the component (for example, the strategy) on the fly. Try getting the same flexibility in a scenario where the implementation of the strategy object is hard-coded in the MyService class and you have to inherit a new class to change strategy. It’s just impossible to change strategy in that case without recompilation and redeployment.

Architectural Patterns

Architectural patterns capture key elements of software architecture and offer support for making hard-to-change decisions about the structure of the system. Software architecture is mostly about decisions regarding design points that, unlike code design, are not subject to refactoring.

Architectural patterns are selected and applied very early in the course of design, and they influence various quality characteristics of the system, such as performance, security, maintenance, and extensibility.

Examples of architectural patterns are Layers and SOA for modeling the application structure, Model-View-Controller for the presentation, Domain Model and Service Layer for the business logic, and Peer-to-Peer for the network topology.

Antipatterns

In physics, we have matter and antimatter. Just as matter is made of particles, antimatter is made of antiparticles. An antiparticle is identical to a particle except for the charge—positive in the particles of normal matter, and negative in an element of antimatter.

Likewise, in software we have patterns made of solutions, and antipatterns made of antisolutions. What’s the difference? It is all in the "charge" of the solution. Patterns drive us to good solutions, whereas antipatterns drive us to bad solutions. The clearest definition for antipatterns we could find comes (again) from Ward Cunningham’s wiki, at http://c2.com/cgi/wiki?AntiPattern:

An anti-pattern is a pattern that tells how to go from a problem to a bad solution.

Put this way, one could reasonably wonder why antipatterns are worth the effort of defining them. For matter and antimatter, it’s all about the thirst for knowledge. But developers and architects are usually more pragmatic and they tend to prefer knowledge with a practical application to their everyday work. What’s the link that relates antipatterns to the real-world of software development?

The keystone of antipatterns is that they might, at first, look like good ideas that can add new power and effectiveness to your classes. An antipattern, though, is devious and insidious and adds more trouble than it removes. From Cunningham’s wiki again:

In the old days, we used to just call these bad ideas. The new name is much more diplomatic.

Designers and antipatterns, in some way, attract each other, but the experienced designer recognizes and avoids antipatterns. (This is definitely a characteristic that marks the difference between expert and nonexpert designers.) Because of the fatal attraction designers generally have toward antipatterns, a catalog of antipatterns is as valuable as a catalog of good design patterns.

A long list of antipatterns can be found at http://c2.com/cgi/wiki?AntiPatternsCatalog and also at http://en.wikipedia.org/wiki/anti-pattern. We like to briefly address a couple of them—one relates to architecture and the other relates to development.

The Architecture-As-Requirements antipattern refers to situations where a prominent and influential member of the design team has a pet technology or product and absolutely wants to use it in the project—even when there is no clear evidence of its usefulness and applicability in the customer’s context.

The Test-By-Release antipattern refers to releasing a software product without paying much attention to all those boring and time-consuming chores related to unit and integration testing. Are users the final recipients of the product? Great, let’s give them the last word on whether the software works or not.

Other  
 
Most View
Microsoft SharePoint 2010 Web Applications : Presentation Layer Overview - Ribbon (part 1)
The Cyber-athletic Revolution – E-sports’ Era (Part 1)
Windows Server 2003 : Implementing Software Restriction Policies (part 4) - Implementing Software Restriction Policies - Creating a Path Rule, Designating File Types
Sql Server 2012 : Hierarchical Data and the Relational Database - Populating the Hierarchy (part 1)
Two Is Better Than One - WD My Cloud Mirror
Programming ASP.NET 3.5 : Data Source-Based Data Binding (part 3) - List Controls
Windows 8 : Configuring networking (part 5) - Managing network settings - Understanding the dual TCP/IP stack in Windows 8, Configuring name resolution
Nikon Coolpix A – An Appealing Camera For Sharp Images (Part 2)
Canon PowerShot SX240 HS - A Powerful Perfection
LG Intuition Review - Skirts The Line Between Smartphone And Tablet (Part 2)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS
Top 10
Review : Acer Aspire R13
Review : Microsoft Lumia 535
Review : Olympus OM-D E-M5 Mark II
TomTom Runner + MultiSport Cardio
Timex Ironman Run Trainer 2.0
Suunto Ambit3 Peak Sapphire HR
Polar M400
Garmin Forerunner 920XT
Sharepoint 2013 : Content Model and Managed Metadata - Publishing, Un-publishing, and Republishing
Sharepoint 2013 : Content Model and Managed Metadata - Content Type Hubs