Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

We're currently in the early stages of building a substantial system, aiming to do much of what several existing systems do, in a flexible, extensible, maintainable way. It will support multiple complete instances for different customers. One of the things which keeps coming up across the whole system is: where should [component x] sit?

We could:

  • (A) completely centralise it into a single separate web service, shared by all instances; configuration would be held centrally so that it could give each instance what it needed, and may include instance-specific plugins
  • (B) have it as a separate service, but install it multiple times, configured individually for each main instance of the solution; the service might be used by several co-operating components within one instance
  • (C) create the functionality as a library and incorporate it directly into the other components

For each there are some clear pros and cons:

A is resource-efficient, and easily allows e.g. monitoring of activity across the whole solution. Making a single service sufficiently configurable/flexible will create additional development challenges. Upgrades to the code might have an impact across the whole solution both in terms of down-time and testing/deployment planning, whether or not the code change is intended to improve every instance.

B uses more resources, but localises configuration, which may be less complex. Code changes can be rolled out in a more manageable way, but more effort will be required to do the roll-out in more than one place.

C removes the need for a separate service at all, and offers the potential for maximum flexibility if calling code doesn't have to be restricted to carrying out all functions via the web service API; upgrades to the code would require redeployment of DLLs everywhere they were used, which could be in every component of an instance rather than just once per instance as in B.

I'm specifically thinking about it from a functionality PoV not, worrying about e.g. where the data is actually stored. I've ignored option D, "copy and paste code all over the place, or reimplement willy nilly".

I'm wondering how it applies to a whole range of components, from specific business functions, to broader things like logging, error-handling, data-access, etc etc. I realise that the final answer will always depend heavily on each example, but are there considerations I haven't mentioned which could have a big impact? Are there examples where it's an absolute no-brainer? Is there some systematic way to help make this decision? Have I completely missed an entire option?

EDIT (a little more detail just in case it makes a difference): Historically, because of a lack of forethought, we have catered to the needs of several similar but also substantially different customers by basically forking the entire codebase apart from a handful of trivial libraries. We are definitely committed to some kind of SOA approach with the rewrite, and certainly a dramatically more shared codebase, but there may still be some benefit or requirement to maintaining some separation to each "instance", by which I mean an entire collection of services providing everything needed for one customer: the customer may require their own logically or physically or even geographically separate install; one customer's instance may consist of modules A and B, another B and C and D and E. I feel instinctively that there are sort of two ways to be "SOA" here: one to have literally one of everything, and let them all work together in different ways for different customers, or alternatively to have one of each of the needed modules within a customer, but the loosely coupled nature of the services would still allow you to add one more module to an existing customer easily, or move a resource-intensive module to its own hardware for only one customer.

Don't get me wrong, I appreciate all the points made, but I think I'm not quite in a mental place where merely the fact that doing something a certain way, which could definitely offer some benefit in some situations, could also lead to problems if managed poorly, is wholly unacceptable. So it's best just to not even let the possibility exist even if that leads to more complexity/effort/etc. Kind of like not allowing booze in the house, because you know that if it's there you might drink it all yourself and run out into the street in your underpants, even though a quiet drink to unwind after work might be nice. I should probably stop waffling now...

share|improve this question
    
Hi, do you have an expection to scale certain instances independent of others? If you do, 'B' will afford you much flexibility, even if the maintenance overhead of seperate services is higher. –  christofr Jul 22 '11 at 10:56

3 Answers 3

up vote 4 down vote accepted

My advice is to "keep IT simple (KISS)". That said, I think the centralized service's advantages far outweigh the costs. You state that configuration might become more complex. I doubt it's more complex than herding multiple instances with separate consumers and configurations. Why not have a single service consume multiple configurations? It's easier to deploy and maintain in my humble opinion, but then again I don't know the technical details. Go for option A.

http://en.wikipedia.org/wiki/Service-oriented_architecture

It's widely used and very popular for numerous reasons.

B) will inevitable cause headaches for your support department. Multiple instances, multiple processes, each with a corresponding client process. How will you troubleshoot that? It's more complicated to identify the culprit process and difficult during rollout and installation. But these things should be simple, as simple as possible! You write:

Code changes can be rolled out in a more manageable way

And I read: Version Chaos!

C) seems like a good option, but it isn't generally employable. You should modularize and create libraries in the first place. You do not necessarily need to update all the applications when the libraries change. In fact, this would be quite dangerous. Just freeze them regulary and when you update the application, ship it as a whole with all libraries, after integration tests for the specific application have been passed. Yet, this approach can cause a version chaos as well.

Concluding, I'd like to state that a fundamental challenge for keeping control over your environment is to freeze specs and versions regulary and thus enabling backwards compatibility.

share|improve this answer
2  
+1: Except for "B) is likely to cause headaches". Option B is a disaster. A total and epic fail from day one. Each installation will be slightly different. One will not get updated properly and that will be the mystery bug. One day, some useless drone will insist that their new feature requires that one of the separately installed versions not be upgraded because they rely on an old feature. Now what? Don't start down the road to option B at all. You're answer made it sound merely "likely" when it's inevitable. –  S.Lott Jul 22 '11 at 11:15
    
You're right, I should emphasize the troubles of option B. –  Falcon Jul 22 '11 at 11:24
    
+1: You might also say that option A is called a Service Oriented Architecture, and everyone is doing it. Why is everyone doing it? Because it really works. –  S.Lott Jul 22 '11 at 11:27
    
@S.Lott: Feel free to add your remarks as an answer of yours or edit my post. You'll get at least one upvote :) –  Falcon Jul 22 '11 at 11:32
    
OK, this is helpful, thanks, and I'm close to clicking the tick! But I suppose I'm not quite convinced that there would never ever be a case where B were the sensible choice? S.Lott says B would be an epic fail, but is the implication that C is just as bad, or are you "allowed" multiple library versions but not multiple service versions? Obviously one can include, say, different versions of a logging framework with different apps one develops but if, for some reason one promoted it from a library to a service, would one instantly have failed if it wasn't a single service shared by all? –  frumious Aug 4 '11 at 22:53

I second Falcon with option A, but with this caveat:

You should handle complexity and difficulty by moving it to the location where you have the tools to deal with it.

If your systems administrators are god-like masters-of-nagios, and your programmers mewling neophytes, then it is probably a good idea to go for solutions that simplify the programming task at the expense of additional systems administration overhead. If the converse is true, of course, then that pulls you in a different design direction.

share|improve this answer

C) Will only work if your services implement some kind of logic or calculation and do not rely on some database or other persistent data. Even if the service is implementing a calculation you will run into a problem when a change is needed.

For example, if your service performs some pricing calculation, then you will have a problem when the pricing calculation formula needs to changed (because of a change in the business) because you won't be able to update all of the applications that use that library all at the same time.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.