How to gather data from multiple services?

Hi there! I’m going through workshop exercise files, Workshop/exercises/04-integration at master · Particular/Workshop · GitHub. Why is calling _shippingProvider.GetPackageInfo and _customerProvider.GetCustomerInfo? how is that better than just calling those services via http? I remember Udi was talking about services should not expose their data, i.e instead of providing all order history for a specific customer, the OrderHistory microservice will implement IProvideFraudScore and will modify the default score based on the internal data it has. And another question is why ShipWithFedexCommandHandler is placed under ITOPs project? Why it is not part of shipping project? Thanks, and have a great day)

Hi Dimitri,

  1. The idea of using the IProvide pattern is to allow what Udi describes as “engine” components, components that are composing activities and data across domain services boundaries, to use this data to provide capabilities of the likes of search, invoicing…

  2. ShipWithFedexCommandHandler belongs in ITOPs namespace as it is an integration component (does not belong in any domain boundary)

Does that make sense?

Hi @dmitribodiu,

In the end it’s not really that different, the main adavantage is that it masquerades away implementation details.

The use case modeled in that part of the workshop is intended to demonstrate integration with 3rd parties. In which case services one way or another must expose data. On one hand there are your well designed services and boundaries on the other hand there is one service, the 3rd party one, that simply doesn’t speak your language. Also your well defined information are crossing a boundary leaving your world for something you have no control over.

Mainly because Shipping should not be responsible to talk, from the technical perspective, to the 3rd party. Shipping owns the intent to ship with FedEx, not the technical details about how to talk to FedEx. Given that multiple services are involved in talking to the 3rd party it makes more sense top host it under the ITOps umbrella.

Going back to the interface implementation details, there nothing wrong in reversing the responsibilities, by doing something like:

class ShipWithFedExCommandHandler : ....
{
   public ShipWithFedExCommandHandler( IEnumerable<IProvideFedExInfo> providers)
   {
      ....
   }

   public async Task Handle( msg, context )
   {
      //create empty xml doc
      foreach( var provider in providers )
      {
         await provider.AppendInfo( /* previously created xml doc */ );
      }

      //send doc to FedEx
   }
}

In the above sample the shipment process knows nothing about info providers, this approach requires, for example, that the order in which providers are invoked is not important.

Thoughts?

.m

Sorry to tack on to the end of this thread but it’s an interesting topic.

Let’s say we have a Finance service that needs to communicate with a 3rd party payment provider, say Stripe for example, to perform a few functions such as authorizing credit cards, charging an amount to them, tracking a Stripe customer Id to a Finance BuyerId, etc. Given that no other service other than Finance is likely to want to communicate with the 3rd party’s api, is it still good SOA to only put 3rd party integration under ITOPS?

I guess I’m searching for a definitive statement that says, “all 3rd party web api call integrations are the responsibility of an ITOPS service”

Assuming ITOPS is responsible for 3rd party api call implementations, does this also mean we should always deploy the handler that injects the implementation behind an ITOPS endpoint? Or is it okay for say a Finance service to have a command handler that injects the ITOPS implementation’s interface abstraction?

Hi Mark,

You could think about it from two point of views: Logical and Physical so in reference to your questions:

From the Logical point of view I think the answer is YES. The ITOPS should be responsible for all 3rd party integrations. In your specific scenario with 3rd party payment provider.

From phisical point of view I would say that both approaches are OK. For example:

Finance Service
    public class Handler
        IStripePaymentProvider stripePaymentProvider
        pubic Handle(..., context)
            this.stripePaymentProvider.AuthorizeCreditCard(...)

or

Finance Service:
    public class Handler
        pubic Handle(..., context)
            context.Send(new AuthorizeCreditCardByStripe(...)

ITOPS Service
    public class Handler
        pubic Handle(AuthorizeCreditCardByStripe message, context)
        // call stripe api

In the first example the ITOPS code (IStripePaymentManger and impelentation) is running in the same physical process (run-time) as Finance code. In the second example the ITOPS code might by run in the same run-time as Finance or could have separate physical process with own deployment lifecycle.

Which approach to choose? It depends as always :wink: For example from the deployment point of view the first opiton is simpler because you have only one physical unit to deployment. On the other side if you want to deploy changes only for IStripePaymentProvider implementation then you have to deploy all Finance code so in this case the second option will be better but then you have two physical units of deployment.

It could be also depends on how big is your product/organization/…

Because from the logical point of view 3rd party integration belongs to ITOPS Service for sure the final solution should be flexible enough that it can be relatively easy to move between the different physical approaches.

Hi Michal,

Thank you for the update and clarification. That’s the answer I was hoping for really. I think I was initially getting trapped into the logical == physical mindset when it clearly isn’t necessarily the same thing.

Thanks again.