Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News New Directions in Framework Design Guidelines

New Directions in Framework Design Guidelines

This item in japanese

Microsoft's Framework Design Guidelines are the rules by which it expects both Microsoft libraries and those of individual developers to follow. As each version of .NET framework is released and tested in the field, their vision is refined. With the release of Cwalina and Abrams' second annotated book by the same name, we see the direction Microsoft is heading for the next couple of years.

Probably the most surprising revelation is the increased emphasis on test driven development and dependency injection. Test driven development, in the context of reusable frameworks, is seen as a way to design frameworks that are actually usable rather than simply speculative. They hope that this in turn will reduce the tendency to develop overly complicated designs that are never fully implemented.

While we are on this subject, it should be noted that Microsoft is now pushing for a minimalist designs in version 1 of any library. Instead of going all out in a vain attempt to do everything right the first time, Microsoft recommends starting with only the features absolutely needed to meet the requirements. Abrams and Cwalina recommend that extensibility not be added until later versions when it is clearer where they are needed. In some ways, this hails back the old Microsoft tradition of not offering a truly completive application until about the third version.

In other areas Microsoft hasn't changed at all. They are still emphasizing the "Pit of Success" as a design philosophy, especially when talking about developer productivity. For example, had the constructor of Exception been protected instead of public, developers would have been almost forced to do the right thing and throw an appropriate exception. Instead, we now have to rely on FxCop rules to check for this after the fact.

Another drum they keep beating is the "Power of Sameness", the desire to make new libraries work in ways that are intuitive to users of other .NET libraries. This applies to all aspects of the code including naming conventions, terminology, and design patterns.

A new area of emphasis for Microsoft is dependency injection. While they have always used it in their libraries, it was never formally considered to be a design pattern. Rather, it was an add hock affair done when the needs of the API demanded it. This has changed with .NET 3.0, where dependency injection and inversion of control containers are specifically called for.

The Framework Design Guidelines are agnostic when it comes to technology on top of the CLR. For example, Microsoft is not using it to push for adoption of their dependency injection library, the Managed Extensibility Framework. Rather, the emphasis is squarely placed on the goal, writing loosely coupled, testable code.

Some of the specific recommendations stressed at the PDC include:

Class constructors should be lazy. Essentially, they should do little more than just capture parameters as often the newly instantiated class won't even be used.

Properties should

  • Not throw an Exceptions (getter)
  • Not be used to perform a conversion (getter)
  • Not have side effects (setter)
  • Be fast regardless of the object's state
  • Never return an array or a cloned list (getter)

Extension methods should be used to "add" overloads to interfaces. They can also be used to manage dependencies between libraries. For example, if assembly B depends on assembly A, then classes in A cannot expose functionality from B. Classes in A can however be annotated with extension methods from B, giving the appearance of a dependency that doesn't actually exist.

For class hierarchies, there shouldn't be more than two or three total levels. Excessively deep hierarchies make it harder to ensure each implementation is abiding by the overall contract. While we are on that subject, it is vitally important that any overridable member have an explicit contract detailing what subclasses need to do in order to work correctly.

Interfaces should be small, preferably containing a single method. Each additional method increases the likelihood that the interface was designed incorrectly and that even more methods will be needed in the future. If an abstract base class is not appropriate, Interfaces can be chained together to build up functionality.

Rate this Article