2. Patterns vs. Idioms
Software
patterns indicate well-established solutions to recurring design
problems. This means that developers end up coding their way to a given
solution over and over again. And they might be repeatedly writing the
same boilerplate code in a given programming language.
Sometimes specific features of a given programming language can help
significantly in quickly and elegantly solving a recurring problem. That
specific set of features is referred to as an idiom.
An idiom is a pattern hard-coded in a programming language or implemented out of the box in a framework or technology.
Like a design pattern, an idiom represents a solution to a recurring
problem. However, in the case of idioms, the solution to the problem
doesn’t come through design techniques but merely by using the features
of the programming language. Whereas a design pattern focuses on the
object-oriented paradigm, an idiom focuses on the technology of the
programming language.
An idiom is a way to take advantage of the language capabilities and
obtain a desired behavior from the code. In general, an idiom refers to a
very specific, common, and eye-catching piece of code that accomplishes
a given operation—as simple as adding to a counter or as complex as the
implementation of a design pattern.
In C#, for example, the ++ operator can be considered a programming idiom for the recurring task of adding to a counter variable. The same can be said for the as keyword when it comes to casting to a type and defaulting to null in case of failure.
Let’s see some more examples of programming idioms in C#.
Events are the canonical example of a programming idiom. Behind
events, you find the Observer pattern. The pattern refers to a class
that has the ability to notify registered observers of some internal
states. Whenever a particular state is reached, the class loops through
the list of registered observers and notifies each observer of the
event. It does that using a contracted observer interface.
In languages such as C# or Visual Basic .NET that support
event-driven programming, you find this pattern natively implemented and
exposed through keywords. Consider the following code:
Button1.Click += new EventHandler(Button1_Click);
When it runs, a new "observer for the Click event" is added to the list maintained by object Button1. The observer in this case is a delegate—a special class wrapping a class method.
The interface through which observer and object communicate is the signature of the method wrapped by the delegate.
Similarly, the foreach keyword in C# (and For . . . Each
in Visual Basic .NET) is a hard-coded version of the Iterator pattern.
An iterator object accomplishes two main tasks: it retrieves a
particular element within a collection and jumps to the next element.
This is exactly what happens under the hood of the following code:
foreach(Customer customer in dataContext.Customers)
{
// The variable customer references the current element in the collection.
// Moving to the next element is implicit.
}
Finally, the most recent versions of C# and Visual Basic .NET—those
shipping with the .NET Framework 3.5—also support a set of contextual
keywords for Language Integrated Query (LINQ): from, select, in, orderby.
When you apply the set of LINQ keywords to a database-oriented object
model, you have LINQ-to-SQL. With LINQ-to-SQL, you ultimately use
language keywords to query the content of a database. In other words,
you programmatically define an object that represents a query and run
it. This behavior is described by the Query Object pattern. And
LINQ-to-SQL is a programming idiom for the pattern.
We spent a lot of time pondering OOD principles and showing their
benefits and applicability. We did it by reasoning in a general context
and looking at the OO paradigm rather than by examining the concrete
technology and platform. General principles are always valid and should
always be given due consideration.
However, when you step inside the design, at some point you meet the
technology. When this happens, you might need to review the way you
apply principles in the context of the specific technology or platform
you’re using. This is called idiomatic design.
As far as the .NET Framework is concerned, a set of idiomatic design
rules exists under the name of Framework Design Guidelines. You can
access them online from the following URL: http://msdn.microsoft.com/en-us/library/ms229042.aspx.
Idiomatic Design: Structures or Classes?
When defining a type in a C# .NET application, should you use struct or class? To start out, a struct
is not inheritable. So if you need to derive new classes from the type,
you must opt for a class rather than a structure. This said, a class is
a reference type and is allocated on the heap. Memorywise, a reference
type is managed by the garbage collector. Conversely, a struct
is a value type; it is allocated on the stack and deallocated when it
goes out of scope. Value types are generally less expensive than
reference types to work with, but not when boxing is required. In the
.NET Framework, boxing is
the task of storing a value type in an object reference so that it can
be used wherever an object is accepted. As an example, consider the ArrayList class. When you add, say, an Int32 (or a struct) to an ArrayList, the value is automatically boxed to an object. Done all the time, this extra work might change the balance between class and struct. Hence, the need of an official guideline on the theme shows up.
The guideline suggests that you always use a class unless the
footprint of the type is below 16 bytes and the type is immutable. A
type is immutable if the state of its instances never changes after
they’ve been created. (The System.String type in the .NET Framework is immutable because a new string is created after each modification.) However, if the struct
is going to be boxed frequently you might want to consider using a
class anyway. (If you’re looking for the list of differences between structs and classes go here: http://msdn.microsoft.com/en-us/library/saxz13w4.aspx.)
Idiomatic Design: Do Not Use List<T> in Public Signatures
Another guideline we want to point out has to do with the List<T> type. Their use in the signature of public members is not recommended, as you can see in this blog post: http://blogs.gotdotnet.com/kcwalina/archive/2005/09/26/474010.aspx.
Why is this so?
One of the reasons behind the guideline is that List<T> is a rather bloated type with many members that are not relevant in many scenarios. This means that List<T> has low cohesion and to some extent violates the Single Responsibility Principle.
Another reason for not using List<T>
in public signatures is that the class is unsealed, yes, but not
specifically designed to be extended. This doesn’t mean, though, that
the class is not LSP-safe. If you look at the source of the class, you
can see that using List<T>
is absolutely safe in any polymorphic context. The issue is that the
class has no protected and virtual methods for inheritors to do
something significant that alters the behavior of the class while
preserving the core interface. The class is just not designed to be
extended.
It is therefore recommended that you use IList<T>, or derived interfaces, in public signatures. Alternatively, use custom classes that directly implement IList<T>.
As
a design principle, DIP states that higher level modules should depend
on abstractions rather than on the concrete implementation of
functionalities. Inversion of control
(IoC) is an application of DIP that refers to situations where generic
code controls the execution of more specific and external components.
In an IoC solution, you typically have a method whose code is filled
with one or more stubs. The functionality of each stub is provided
(statically or dynamically) by external components invoked through an
abstract interface. Replacing any external components doesn’t affect the
high-level method, as long as LSP and OCP are fulfilled. External
components and the high-level method can be developed independently.
A real-world example of IoC is Windows shell extensions. Whenever the
user right-clicks and selects Properties, Windows Explorer prepares a
standard dialog box and then does a bit of IoC. It looks up the registry
and finds out whether custom property page extensions have been
registered. If any are registered, it talks to these extensions through a
contracted interface and adds pages to the user dialog box.
Another real-world example of IoC is event-driven programming as
originally offered by Visual Basic and now supported by Windows Forms
and Web Forms. By writing a Button1_Click method and attaching it to the Click event of, say, the Button1 control, you essentially instruct the (reusable and generic) code of the Button class to call back your Button1_Click method any time the user clicks.
What is dependency injection (DI), then?
From DIP to Inversion of Control
For the purpose of this discussion, IoC and DI are synonyms. They are
not always considered synonyms in literature, as sometimes you find IoC
to be the principle and DI the application of the principle—namely, the
pattern. In reality, IoC is historically a pattern based on DIP. The
term dependency injection was coined by Martin Fowler later, as a way to further specialize the concept of inversion of control.
IoC/DI remains essentially a pattern that works by letting you pass
high-level method references to helper components. This injection can
happen in three ways. One way is via the constructor of the class to
which the method belongs. We did just this in the implementation of the FinanceInfoService
class. Another way consists of defining a method or a setter property
on the class to which the method belongs. Finally, the class can
implement an interface whose methods offer concrete implementations of
the helper components to use.
Today, IoC/DI is often associated with special frameworks that offer a number of rather advanced features.
Table 1 lists some of the most popular IoC frameworks available.
Table 1. Main IoC Frameworks
Note that Ninject is also available for Silverlight and the Compact
Framework. In particular, Microsoft’s Unity Application Block (Unity
for short) is a lightweight IoC container with support for constructor,
property, and method call injection. It comes as part of the Enterprise
Library 4.0. Let’s use that for our demos.
All IoC frameworks are built around a container object that, bound to
some configuration information, resolves dependencies. The caller code
instantiates the container and passes the desired interface as an
argument. In response, the IoC/DI framework returns a concrete object
that implements that interface.
Suppose you have a class that depends on a logger service, such as the class shown here:
public class Task
{
ILogger _logger;
public Task(ILogger logger)
{
this._logger = logger;
}
public void Execute()
{
this._logger.Log("Begin method ...");
.
.
.
this._logger.Log("End method ...");
}
}
The Task class receives
the logger component via the constructor, but how does it locate and
instantiate the logger service? A simple and static new
statement certainly works, and so does a factory. An IoC container is a
much richer framework that supports a configuration section:
<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
</configSections>
.
.
.
<unity>
<containers>
<container>
<types>
<type type="ILogger, mdUtils"
mapTo="ManagedDesign.Tools.DbLogger, mdTools" />
</types>
</container>
</containers>
</unity>
</configuration>
The configuration file (app.config or web.config) contains mapping between interfaces and concrete types to be injected. Whenever the container gets a call for ILogger, it’ll return an instance of DbLogger:
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)
ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
ILogger logger = container.Resolve<ILogger>();
Task t = new Task(logger);
.
.
.
IoC/DI is extremely useful for testing purposes and for switching
between implementations of internal components. Frameworks just make it
simple and terrific.
To finish, here are a couple of brief remarks about IoC/DI
containers. Through the configuration script, you can instruct the
container to treat injected objects as singletons. This means, for
example, that the container won’t create a new instance of DbLogger every time, but will reuse the same one. If the DbLogger class is thread safe, this is really a performance boost.
In addition, imagine that the constructor of DbLogger
needs a reference to another type registered with the IoC/DI framework.
The container will be able to resolve that dependency, too.