mentis vulgaris
simple thoughts | jason smith
Is Your Code SOLID: The Interface Segregation Principle
Posted by Jason Smith - 12/01/10 at 07:01:02 pmSimplicity is the ultimate sophistication. ~ Leonardo da Vinci

Robert Martin, in his 1996 article says:
When clients are forced to depend upon interfaces that they don’t use, then those clients are subject to changes to those interfaces. This results in an inadvertent coupling between all the clients. Said another way, when a client depends upon a class that contains interfaces that the client does not use, but that other clients do use, then that client will be affected by the changes that those other clients force upon the class. We would like to avoid such couplings where possible, and so we want to separate the interfaces where possible.
An example of this problem can be seen in the following interface:
/// An interface that converts IIdentities into an IMyIdentity (i.e., an identity with Roles and properties)
public interface IAuthorizationProvider
{
IMyIdentity GetRolesFor(IIdentity identity);
MembershipInfo GetRoleMembershipInfo(string role);
IEnumerable<string> Roles { get; }
void AddRole(RoleInfo roleInfo);
void AddSubjectToRole(string role, IIdentity identity);
}
No one would argue that an interface with 5 methods isn’t manageable. But as we look at the code from a client perspective, it’s flabby. Reading through the body of code this sample was lifted from, there are two consumers of this interface:
- Users who are simply interested in determining whether an Identity is authorized to do something.
- Someone who needs to manage authorizations/role memberships, and what roles are associated with an identity.
The most common user is only interested in reading whether an identity is in a role. For that user, the rest of the interface is completely unnecessary, and unnecessarily coupled (to say nothing of the security risk having authorization management api’s available to the average user).
The ISP driven improvement for this design might look something like:
/// An interface that converts IIdentities into an IMyIdentity (i.e., an identity with Roles and properties)
public interface IAuthorizationProvider
{
IMyIdentity GetAuthorizations(IIdentity identity);
}
/// An interface that converts IIdentities into an IMyIdentity (i.e., an identity with Roles and properties)
public interface IRoleManager
{
MembershipInfo GetRoleMembershipInfo(string role);
IEnumerable<string> Roles { get; }
void AddRole(RoleInfo roleInfo);
void AddSubjectToRole(string role, IIdentity identity);
}
If you’re wondering why I didn’t derive IRoleManager from IAuthorizationProvider, consider this: if we’re going to all this effort to reduce coupling, then inheritance is the last thing we want. Inheritance is the strongest form of coupling you can have between two types (outside of C++’s concept of “friend”). Interface segregation is about making the surface area of our dependencies smaller. Because inheritance exposes derived classes to protected data in bases, by definition, we increase that dependency surface.
Keep your interfaces demure. You’ll sleep better. I promise.
No Comments yet »
RSS feed for comments on this post. TrackBack URI
Leave a comment
Powered by WordPress with GimpStyle Theme design by Horacio Bella.
Entries and comments feeds.
Valid XHTML and CSS.