3

We're developing a total solution, and we've chosen service-oriented architecture to loosen subsystems. However, now we have a problem.

When customer orders something, Order Subsystem is responsible to get that order, and register it. However, there are some other modules which are responsible too, in order registration process, and each module should do something on it:

  1. Customer Accounting module should check customer's balance, and prevent order registration if there is not enough money in customer's account.
  2. Asset Management module should increase/decrease customer's assets
  3. Rule Engine should apply some business rules dynamically on it (like preventing a specific customer, or notifying an operator, etc.)
  4. CRM should view customer's history, and give good customers some discount
  5. ...

Right now, we're doing it this way:

public void RegisterOrder(Order order) 
{
    RuleEngineService.ApplyBusinessRules(order);
    // some code here
    CrmService.GiveDiscountIfApplicable(order);
    // some code here
    CustomerAccountingService.CheckBalance(order);
    // some code here
    AssetManagementService.ChangeAssetCount(order);
    // some code here
}

This means that if we add another subsystem (module) that needs to do something on order, we have to recompile the code of our OMS (Order Management System) to support it. Also we're coupled to some extent to other subsystems here, and if one of them fail, this registration process fails.

One way of making this piece of code dynamic and loosely coupled is to use interfaces or contracts, like:

public void RegisterOrder(Order order)
{
   // Finding a list of all IOrderProcessors.
   // Looping over each, calling orderProcessor.Process(order);
}

However, it has two problems:

  1. We can't use interfaces over SOAP and HTTP (we don't have access to other subsystems' DLL files)
  2. Those need to run in a specified order (rule engine the first one)

What should we do here? What are the known patterns and practices?

  • Am I only one who thinks this "service-oriented architecture" is main problem and that with proper OOP design without premature abstractions, this would never happen? – Euphoric Aug 21 '13 at 15:05
  • i tend to agree somewhat. What is the stated goal of the strategy to 'loosen' the systems? I'm all for architecture , planning and future proofing but you have to weigh those 'projected' benefits with the pain you feel right now trying to get richness between your subsystems. – Andyz Smith Oct 9 '13 at 0:21
3

Take a look at the Pub-Sub pattern as it's well suited for providing that decoupling you're looking for. The observer pattern may have some applicability in your case as well.

In essence, the "main" application that handles the request will push a message to a queue that the other systems will pick up and handle as they need to. You'll need to define a standard interface or contract for the message format, but that's what will gain you the decoupling you're looking for. Adding and removing applications is as simple as adding and removing subscribers.

Another added benefit is a supporting system can go offline, and when it comes back it will pick up where it left off in the message queue.

If you have atomic transactions, you'll need to extend the pattern a little bit. Reply messages on another queue are one means of accomplishing that. Presumably you already have some logic in place to handle that transaction state, so you would just need to modify it to react to reply messages instead.

  • So, what about synchronous operations? How should we implement that? Also how can we create pub-sub pattern over HTTP? – Saeed Neamati Aug 21 '13 at 14:28
  • 2
    synchronous operations merely require more tiers within the pub-sub model. A pushes out; then B and C receive. B does work; pushes out; then B1 and B2 receive. B1 and B2 do not subscribe to A. Depending upon what message queue technology you're using (or are going to use), you shouldn't have any problems with HTTP communications. You're not the first with that requirement. – GlenH7 Aug 21 '13 at 14:41
  • Sequence should happen like this: A pushes out, B and C get the message, they do something on the message, then they should notify A back, which is waiting for all the responses. And to increase the difficulty, A does not know even who are acting no that message. – Saeed Neamati Aug 21 '13 at 17:28
  • @SaeedNeamati - that's fine. That's pub sub + reply. A needs some form of logic to validate the reply as well as timing out transactions that never complete. – GlenH7 Aug 21 '13 at 18:06
1

There are some way to solve your problems:

  1. As above ,use Message queue to loose all modules.You can use Pub/Sub model to loose requester and responser. MQ is a async architecture.

  2. Use SOA.SOA is a architecture that use SOAP and XML to export service.Every service supply a SOAP and xml segment. The registerOrder service can be implemented with a xml that combine some xml segment that supplied by other services. SOA is a xml file.You can easy edit it. SOA is a sync architecture.Sync architecture maybe have performance problem when request flood in.

  3. Use workflow(BPM).You can use some workflow engine to organize your bussiness logic.Workflow is also a XML file.You can easy edit it. I suggest that you use JBPM as your workflow engine. Workflow generally use a database recorder to track a workflow instance.So a workflow instance can be alive forever. If you have atomic transactions,you only need set some process in workflow.When workflow has finished,your atomic transactions always be consistency.
    Workflow is also a async architecture.

    I suggest that you use workflow(for example JBPM) to combine your services.As far as know,most of order system use workflow engine.

  • Is workflow considered some kind of service orchestration? – Saeed Neamati Aug 22 '13 at 7:40
  • Yes.Workflow support persistence. – Edward Shen Aug 22 '13 at 14:12
1

I would use some ServiceBus framework that supports Saga pattern.

Plus, you still can stick to your own solution with interfaces. I don't see any issue with having DI container to resolve your interfaces into a collection. Proxy classes that implement interfaces will talk to the actual services and these classes are local. You can have separate DLLs per proxy class and register it either by assembly scanning or by configuration. You can have a property for execution order in your interface that will easily allow you to sort your collection to run proxies in the proper sequence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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