BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Becoming SOLID in C#

Becoming SOLID in C#

This item in japanese

Brannon B. King, a software developer working for Autonomous Solutions Inc., has published an article entitled Dangers of Violating SOLID Principles in C# in MSDN Magazine, May 2014. The author outlines some of the mistakes developers can make in their C# code, breaking the SOLID principles and leading to code that is more difficult to extend or maintain.

King provides counter code samples and advice for all SOLID principles, but for the sake of brevity we have extracted just a few of them related to the Open-Closed Principle (OCP). OCP states that "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification". According to King the following piece of code breaks OCP

void DrawNerd(Nerd nerd) {
   if (nerd.IsSelected) DrawEllipseAroundNerd(nerd.Position, nerd.Radius);
   if (nerd.Image != null) DrawImageOfNerd(nerd.Image, nerd.Position, nerd.Heading);
   if (nerd is IHasBelt) // a rare occurrence
      DrawBelt(((IHasBelt)nerd).Belt);
   // Etc.
}

because “you’ll have to modify this method every time a customer needs new things displayed—and they always need new things displayed,”  proposing instead a general procedure for drawing:

readonly IList<IRenderer> _renderers = new List<IRenderer>();
void Draw(Nerd nerd) {
   foreach (var renderer in _renderers)
    renderer.DrawIfPossible(_context, nerd); }

The idea is to

… write drawing classes (or classes about drawing classes) that implement a well-known interface. The renderer must have the smarts to determine if it can or should draw anything based on its input. For example, the belt-drawing code can move to its own “belt renderer” that checks for the interface and proceeds if necessary.

Another example breaking OCP is that of a class referencing an inheritor class

class Nerd {
public void DanceTheDisco() {
if (this is ChildOfNerd)
throw new CoordinationException("Can't");
   ...
}

}
class ChildOfNerd : Nerd { ... }

the author’s advice being that “base classes should never directly reference their inheritors.” This problem can appear in peer classes as well:

class NerdsInAnArc {
public bool Intersects(NerdsInAnLine line) {
    ...
   }
   ...
}

King explains:

Arcs and lines are typically peers in the object hierarchy. They shouldn’t know any non-inherited intimate details about each other, as those details are often needed for optimal intersection algorithms. Keep yourself free to modify one without having to change the other. This again brings up a single-responsibility violation. Are you storing arcs or analyzing them? Put analysis operations in their own utility class.

While strictly applying SOLID principles may not be necessary for small projects, their importance becomes more obvious for larger codebases where avoiding “spaghetti” code is quite desirable.

Rate this Article

Adoption
Style

BT