views:

426

answers:

5

Hey all. I'm coming across a weird design pattern using the repository and service model. The application constists of ASP.NET MVC, WCF, and some Windows services. My repositories are using LINQ DataContext. As my application evolves I'm finding myself passing references to IWhateverService service everywhere. For example, I have IAccountService which defines methods such as ChangePlan(Account account, Plan plan).

Now, it seems like IAccountService is the best place to put this method since we're servicing accounts here. However, the ChangePlan method needs to know several things before it can actually change the plan. It has to know the user's current usage, the list of available plans, an instance to an ecommerce service interface for billing, etc.

I thought having ChangePlan method accept all of the required services in the IAccountService interface. But the requirement of these other services is a matter of implementation and shouldn't be part of the interface definition.

So now I find myself creating a huge constructor for AccountService taking an instance of IAccountRepository, IPlanService, IUsageService, IEcommerceService, and IValidationDictionary. This doesn't feel right at all.

Now take this scenario. Obviously IAccountService contains a simple method to retrieve a user's account by ID: Account Get(int id) There are several times when I just need to call this method only. So, I go to create my AccountService, and it wants instances of all these other services (especially IValidationDictionary, I'm not needing validation for this). Again, this feels wrong. I could pass null, but that's only becuase I know the implementation doesn't use them for just this method.

Also, to avoid instantiating the services everywhere I need them, I created a static class called ServiceFactory, which has static methods, CreateAccountService, CreatePlanService, etc... I call these methods around the application. The seems OK but I can't shake the feeling that this is improper.

Where's my disconnect here? Anyone got any suggestions?

Thanks.

Andrew

A: 

Events could help you decouple at least some of that. You could have the other services that need to validate a plan change register to a ChangePlanRequestEvent, have each service perform the necessary validation, and throw an exception if the change shouldn't be allowed. Now you have the problem. The specifics of the plan should be encoded in the Plan object and no one should need a list of available plans unless you want to display them.

But why is there an AccountService at all ? To me, Why isn't ChangePlan a method of account ?

jfclavette
+5  A: 

The design you are describing seems to be pretty much in line with the SOLID principles. A lot of smaller components is also generally considered to be good design.

The SOLID principles would generally accept the denormalization you're describing in the implementation, and would rather focus on letting each external use-case of such a component have its own interface.

I think the main problem you have is that you're spending too much time wondering how to construct these objects. You should probably be looking at a dependency injection framework to handle this, like Castle Windsor. Then you'd just construct the object in its full state and not worry about all the dependencies not being used for every call.

krosenvold
I agree this is the exact problem dependency injection frameworks were created to solve (I would recommend Ninject but they any of them will help you solve this problem).
James Avery
A: 

I've been a little way down the same path as yourself on previous projects and I've yet to see a clean approach to solve the issue. I think the real answer is that SOA causes as many problems as it solves. The logic goes that by decoupling everything you can switch services and their implementations in/out easily. However, if the price that we pay for such a feature is code that turns into a spaghetti mess of interfaces, services, and injected dependencies then is the benefit worth the hassle - I say it's not.

My current approach to SOA is to approach with caution. We harvest services from conventionally written code once the the intent and implementation have settled down.

MrTelly
+1  A: 

So now I find myself creating a huge constructor for AccountService taking an instance of IAccountRepository, IPlanService, IUsageService, IEcommerceService, and IValidationDictionary. This doesn't feel right at all.

Dependencies like this should not be a huge concern. What you want to look out for are huge methods within your AccountService. If you have methods that are 100s of lines long then it might be time to look at refactoring and breaking AccountService up into a few smaller services.

Also, to avoid instantiating the services everywhere I need them, I created a static class called ServiceFactory, which has static methods, CreateAccountService, CreatePlanService, etc... I call these methods around the application. The seems OK but I can't shake the feeling that this is improper.

You can use an Inversion of Control container to remove the need for these factories.

Unless your objects are very large or are loading data during construction (which they typically should not be doing) then constructing new instances of a class takes an infinitesimal amount of time and should not be something to worry about.

Todd Smith
+1, the description of the problem sounds like precisely what DI and IoC were invented for.
Pavel Minaev
A: 

Can you create overloaded constructors that accept interfaces you need to perform the underlying operation? For example:

AccountService(IAccountRepository)
AccountService(IAccountRepository, IPlanService)
AccountService(IAccountRepository, IPlanService, IUsageService, IEcommerceService,IValidationDictionary)

The methods in the account service can then assert that a particular interface reference is not null before operting against it.