SOLID principles in .NET revisited part 6: the Interface Segregation Principle

Introduction

In the previous post we continued to discuss the Liskov Substitution Principle. We saw a subtle example of breaking LSP by trying to force an object to implement an interface even though not all methods of the interface made sense for it. The client object, i.e. OnDemandAgentService cannot consume all implementations of IAuthorizationService without fully being able to carry out its tasks.

A possible solution comes in the form of letter ‘I’ in SOLID, which stands for the Interface Segregation Principle (ISP). ISP states that clients should not be forced to depend on interfaces and methods they do not use. Applying ISP correctly will result in a lot of small interfaces instead of handful of large ones with lots of methods. The more methods to an interface has the more likely it is that an implementation will not be able to fulfil all parts of the contract. The IAuthorizationService only has 2 methods and we immediately found an example where a class, the AuthorizationService only could implement one of them.

Applying ISP to the problem

Not all is lost with the AuthorizationService class. It can at least implement one of the methods of IAuthorizationService. We could remove the LockOut method from IAuthorizationService and then we’ll be fine. However, that will be problematic for DatabaseAuthorizationService and OnDemandAgentService. We can resolve the problem by breaking up IAuthorizationService into two interfaces. We’ll keep IAuthorizationService with only one method and put the LockOut method into another interface:

public interface IAuthorizationService
{
	bool IsAuthorized(string username, string password);
}

public interface IUnauthorizedAccessPunishmentService
{
	bool LockOut(string username);
}

AuthorizationService can safely implement IAuthorizationService:

public class AuthorizationService : IAuthorizationService
{
	public bool IsAuthorized(string username, string password)
	{
		return (username == "admin" && password == "passw0rd");
	}
}

DatabaseAuthorizationService can implement both:

public class DatabaseAuthorizationService : IAuthorizationService, IUnauthorizedAccessPunishmentService
{
	private List<string> users;

	public DatabaseAuthorizationService()
	{
		users = new List<string>();
	}

	public bool IsAuthorized(string username, string password)
	{
		return true;
	}

	public bool LockOut(string username)
	{
		return users.Remove(username);
	}
}

Then we’ll need to add the usual private field and public getter/setter to OnDemandAgentService:

private IUnauthorizedAccessPunishmentService _punisher;

public IUnauthorizedAccessPunishmentService Punisher
{
	get
	{
		if (_punisher == null)
		{
			_punisher = new DatabaseAuthorizationService();
		}
		return _punisher;
	}
	set
	{
		if (value != null)
		{
			_punisher = value;
		}
	}
}

The StartNewOnDemandMachine method can now call the appropriate IUnauthorizedAccessPunishmentService in StartNewOnDemandMachine():

public OnDemandAgent StartNewOnDemandMachine()
{
	EmailService emailService = new EmailService();
	LoggingService.LogInfo("Starting on-demand agent startup logic");
	try
	{
		if (AuthorizationService.IsAuthorized(Username, Password))
		{
			LoggingService.LogInfo(string.Format("User {0} will attempt to start a new on-demand agent.", Username));
			OnDemandAgent agent = CloudProvider.StartServer();
			emailService.SendEmail(string.Format("User {0} has successfully started a machine with ip {1}.", Username, agent.Ip), "admin@mycompany.com", "email.mycompany.com");
			return agent;
		}
		else
		{
			bool lockedOut = Punisher.LockOut(Username);
			LoggingService.LogWarning(string.Format("User {0} attempted to start a new on-demand agent. User locked out: {1}", Username, lockedOut));
			throw new UnauthorizedAccessException("Unauthorized access to StartNewOnDemandMachine method.");
		}
	}
	catch (Exception ex)
	{
		LoggingService.LogError("Exception in on-demand agent creation logic");
		throw ex;
	}
}

ISP violation in .NET

.NET has several large interfaces where it’s often difficult to implement all methods. One good example is the IConvertible interface which you can implement in your own classes so that they can converted into an integer, a double, a date etc. This interface comes with 17 methods like the following:

public bool ToBoolean(IFormatProvider provider)
{
	
}

public DateTime ToDateTime(IFormatProvider provider)
{
	
}

public double ToDouble(IFormatProvider provider)
{
	
}

I cannot really think of any object that can be converted to all other objects provided by the IConvertible interface. It is possible to provide some fake and bogus return values, like “return true” for the ToBoolean method but would it be truly meaningful for that object? Maybe, maybe not. However, it’s hard to think of an object that meaningfully implement all 17 members of the IConvertible interface.

So calm down, not even .NET is SOLID-proof.

In the next post we’ll look at the Dependency Inversion Principle.

View the list of posts on Architecture and Patterns here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

4 Responses to SOLID principles in .NET revisited part 6: the Interface Segregation Principle

  1. Ilkin says:

    Thanks.Does creating code very solid makes slow program?For example SRP so much classes,so much interfaces.

    • Andras Nemes says:

      Hello,
      No, don’t worry about that. If your code is slow then it’s usually due to below-optimal queries, HTTP calls, file I/O and not to a large number of small classes and interfaces.
      //Andras

  2. Pingback: Architecture and patterns | Michael's Excerpts

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: