NotImplementedException and the Interface Segregation Principle

This week, Derrick Bailey will be in town (Austin) to talk about the SOLID principles.  One of the hardest ones to talk about, and find examples for, is the Interface Segregation Principle.  The ISP states:

CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE

While this may be more difficult to recreate in software we both create and consume, you’ll see it pop up more in libraries meant for mass consumption, such as ASP.NET or NHibernate.  I think I’m starting to notice a trend in the .NET space that provides us a bright flashing blue light to indicate violations of the ISP: usage of NotImplementedException.

When talking about ISP in the .NET space, one of the more widely-used targets is the massive MembershipProvider class.  It has dozens of members, of which only a handful are used in custom implementations.  The MembershipProvider allows just about every possible membership feature under the sun to be used, but you’re still stuck with providing implementations to everything.  Don’t want to allow users to be locked out?  Too bad, provide an implementation.  Can’t figure out how many users are online?  Too bad, provide an implementation.

Even ALT.NET-y frameworks like NHibernate (though ALT.NET is NOT NOT NOT about tools) has its own issues with ISP.  In one recent project, we interacted with a legacy database to read about 80% of our entities as read-only.  That is, a large portion of the tables we read from were never written to, and we turned off the ability to write back to from NHibernate.  As it was a legacy database, we made extensive use of NHibernate’s custom user types, which allowed us to encapsulate the…more interesting parts of the database.  Instead of “Y” and “N” in our system, we wanted booleans.  Instead of integer dates (20080904), we wanted actual DateTime types.  Custom user types allowed us to translate from the database to our types, completely transparent to our actual entities.  Our entities were built with “real” types, and NHibernate took care of the translation.

Unfortunately, we still had quite a few of these around:

public override Type ReturnedClass
{
    get { throw new NotImplementedException(); }
}

public override void Set(IDbCommand cmd, object value, int index)
{
    throw new NotImplementedException();
}

public override Type PrimitiveClass
{
    get { throw new NotImplementedException(); }
}

public override object DefaultValue
{
    get { throw new NotImplementedException(); }
}

A bunch of features we didn’t need to support, all throwing NotImplementedExceptions.  Instead of providing an empty implementation, we wanted to make sure these areas were never called, and if they did, something else was wrong.

These NotImplementedExceptions are pretty strong smells for ISP violations.  We were forced to provide an implementation, but the exception shows a refusal on our part to do so.  Part of this is a design issue, and part of it is the unfortunate side-effect of designing an API that is used in a variety of situations.  The NotImplementedExceptions are noisy, and I’d rather never see one in code (even temporarily in a test).  In both the MembershipProvider and the NHibernate case, we were using 3rd-party libraries which we had no control over.  It’s not like we could try and do something about the ISP violations.  But in our client software, we can look out for NotImplementedExceptions, and examine the underlying type to see if there aren’t more concerns that need to be split out.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Code smells, Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • smaclell

    It always makes me chuckle but .NET actually provides an exception specifically intended for this case, where you want to implement something but don’t want to support specific functionality. System.NotSupportedException.

  • http://www.lostechies.com/blogs/derickbailey Derick Bailey

    “The NotImplementedExceptions are noisy, and I’d rather never see one in code (even temporarily in a test). ”

    amen to that! I can’t stand the default “throw NotImplementedException” that Resharper puts into generated code. The first thing I do after generating any method or property is get rid of this and put in code that I know will run, but fail.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Derick

    Yeah I hate that. I want it to fail because the assertion fails, not because of some garbage in the SUT.

  • http://bloggingabout.net/blogs/ramon/ Ramon Smits

    That’s why you should use NotSupportedException instead of NotImplementedException.

    You start with NotImplemented and when you decide that a certain method/feature is not needed then make the decision to not support the feature at all thus throwing NotSupportedException together with the reason for that.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Ramon

    That still doesn’t solve the ISP problem. If I have to throw exceptions to ensure certain features aren’t used, by definition, it’s an ISP violation.

  • etro

    So the real compliant here is the way interfaces work in the first place? You want to implement an interface, not implement all of it, not tell anyone you are not implementing it, and then expect every consumer to understand that…

    I suppose an argument could be made that the default behaivor of an non-fully-implemented interface could be to “softly” back out of the call and make everyone play nice… but isn’t this sort of the POINT of interfaces? So that everyone is assured that they know all the calls to get something done, just not the implementation?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @etro

    This isn’t necessarily tied to the .NET version of an interface. It applies to abstract classes as well.

    If an interface has a bunch of methods that I don’t want to implement, doesn’t that mean that the interface doesn’t apply to me?