Event Collaboration

Embed Size (px)

Citation preview

  • 7/28/2019 Event Collaboration

    1/16

    | EAA-dev Home |

    WORK-IN-PROGRESS: - this material is still under development

    Event Collaboration

    Multiple components work together by communicating with each other by sending events

    when their internal state changes.

    When we have components that collaborate with each other, whether they be as small

    objects in a single address space or as large as application communicating across theInternet, we commonly think of their style of collaboration as being driven by requests.One component needs information that another has, so the needier component requestsit, if then that component needs another to do something, out goes another request.

    Event Collaboration works differently. Instead of components making requests when theyneed something, components raise events when things change. Other components thenlisten to events and react appropriately. Event Collaboration leads to some very differentways of thinking about how parts need to think about their interaction with other parts.

    How it Works

    As with many things the easiest place to begin is with an example. Let's set it in my homein 2006 as it was probably imagined in the 70's. As such when I want to pop out I tell myhouse computer, which has a silly name like Zen, and considers the outside temperatureand tells my robot valet to fetch a down jacket for the cold New England winter's day.

    Figure 1: Collaboration using requests

    Sequence diagrams illustrate the difference quite well. Figure 1 uses the requestcollaboration style. When I tell Zen I'm going out it queries the temperature sensor for thetemperature, uses this information to figure out what coat I'll need and tells the valet to getthe down jacket.

    ntro Bliki Design Agile Refactoring NoSQL DSL Delivery About Me ThoughtWorks

    http://martinfowler.com/eaaDev/index.htmlhttp://martinfowler.com/intro.htmlhttp://martinfowler.com/bliki/index.htmlhttp://martinfowler.com/design.htmlhttp://martinfowler.com/agile.htmlhttp://refactoring.com/http://martinfowler.com/nosql.htmlhttp://martinfowler.com/dsl.htmlhttp://martinfowler.com/delivery.htmlhttp://martinfowler.com/aboutMe.htmlhttp://www.thoughtworks.com/http://www.twitter.com/martinfowlerhttp://martinfowler.com/feed.atomhttp://www.thoughtworks.com/http://martinfowler.com/aboutMe.htmlhttp://martinfowler.com/delivery.htmlhttp://martinfowler.com/dsl.htmlhttp://martinfowler.com/nosql.htmlhttp://refactoring.com/http://martinfowler.com/agile.htmlhttp://martinfowler.com/design.htmlhttp://martinfowler.com/bliki/index.htmlhttp://martinfowler.com/intro.htmlhttp://martinfowler.com/http://martinfowler.com/eaaDev/index.html
  • 7/28/2019 Event Collaboration

    2/16

    Figure 2: Collaboration using events

    There are two elements to the collaboration here: the query Zen issues to the temperaturesensor and the command Zen issues to the valet. Queries and commands are different(although they can be combined) and result in different effects on the communicationpatterns.

    The Event Collaboration of Figure 2 works differently and although the example has theusual whiff of an author's simplification I think it serves to bring out some of the importantdifferences between these two styles.

    One obvious difference is that the events are sent to everyone else, not just thosecomponents that are going to react. The point here is that the sender is just broadcasting

    the event, the sender does not need to know who is interested and who will respond. Thisloose coupling means that the sender does not have to care about responses, allowing usto add behavior by plugging new components onto the event bus. This flexibility has it'spros and cons, as we shall see.

    Commands

    The differences in the collaboration style manifest themselves in different ways forcommands and queries, so I'll look at them separately and in reverse order. In many waysthe command is the less altered of the two interactions, there's still a need to tell the valet

    to do what it needs to do. One difference is the way the event is named. Rather thanphrasing it the form that says it's telling the recipient to do something, it takes the form ofsaying that an event as happened - inviting those interested to respond. It's a subtledifference, and brings to mind the way my mother used to issue commands, but there issomething there. At times the distinction is little more than phrasing, but at other times itdoes open the mind to different ways of doing things.

    The 'unknown' recipients aspect of events now raises its head. What if the valet has beentold by Cindy replace the broken leg on the antique library chair. One presumes that thevalet is sufficiently intelligent to know that her commands are far more important thanmine, but how does Zen react to this? One could add further protocol with events foraccepting the task and finishing the task, for instance. In any case there is an impliedresponsibility here that if Zen wants to be really sure the job is done, it had better ensuresomeone agreed to carry out the command. J ust raising an event is not for a command,you have to know something's going to act.

    A related problem occurs if we splash out and get a second valet. Which one shouldrespond to the event? In a true decentralized, event driven world one would assume thatthe valet's would figure it out between themselves, but I can't rid myself the thought ofthem fighting over my poor jacket both desperate for the pleasure jolt the programmersset them to receive when I say 'thank you'.

  • 7/28/2019 Event Collaboration

    3/16

    Even in a world of event collaboration, there is a role for a centralized decision of who willcarry out commands. So Zen could broadcast the event as "A desire has occurred forValet George to get Martin's jacket". My mother would find this far too direct. In practicethis means that the difference between events and commands can easily fade into themist, just remember that it doesn't always do that.

    Queries

    The more interesting change occurs with queries. You'll notice that in the eventcollaboration case, Zen never asks the temperature sensor for a temperature. Instead thetemperature sensor broadcasts the temperature. Usually this kind of broadcast is donewhen the temperature changes, but it might also be on a regular schedule.

    The idea is that when the temperature is broadcast, then components that need that datamake a note of it. When I tell Zen I'm going out, it doesn't ask the temperature sensor forthe temperature because it's kept a note of the last event and thus knows thetemperature. I find this the most interesting difference in event collaboration, toparaphrase J on Udell: request driven software speaks when spoken to, event drivensoftware speaks when it has something to say.

    A consequence of this is that the responsibility of managing state shifts. In requestcollaboration you strive to ensure that every piece of data has one home, and you look itup from that home if you want it. This home is responsible for the structure of data, howlong it's stored, how to access it. In the event collaboration scenario the source of newdata is welcome to forget the data the second it's passed to its Message Endpoint.

    As a result the data has to be stored by its user, in this case Zen. If Zen needs a record ofpast temperatures, perhaps to guess how things might change as I go out, then it's up toZen to keep that history. Similarly it's up to Zen what data to keep and how to structure it.Zen is free to throw away anything in the temperature it doesn't need - not that a single

    value is much of an example for that, but clearly useful if you're sending out richer recordsof information.

    A good example of this difference are the siblings of XML processing: SAX and DOM.DOM uses request collaboration, you tell it to load up a document and then issue requeststo it to get information. With SAX you listen to various events as the parser reads the datasource. DOM holds data, but SAX is stateless - you have to choose what state to hold.

    The two result in a very different programming model. I find DOM far more convenientwhen my processing of elements depends a lot on the element's context - but SAX isbetter when I don't need that context. SAX is also far less overhead and often operatesmore quickly due to this. (I'll let you figure out which if these siblings is the boy and which

    the girl.)

    Another consequence of this is that the data's immediately replicated. Every user of thedata keeps his own copy. For many designers data replication is a terrible evil. After all ifyou have multiple sources of data you're like the man with two watches who never knowswhat time it is. But this is a very controlled replication. You only have one watch and it'sconstantly monitoring the ether to detect when things change. Of course if a connection isdown it will miss something, but then in a request scenario you can't issue a query withouta connection to the source. An event queue will usually ensure that messages wait untilyou come back online and then deliver them to you.

    http://www.enterpriseintegrationpatterns.com/MessageEndpoint.htmlhttp://www.enterpriseintegrationpatterns.com/MessageEndpoint.html
  • 7/28/2019 Event Collaboration

    4/16

    You can still control changes to the data to ensure there's only one source for each bit ofdata. However instead of doing this by saying only one component stores data, you do itby allowing one component to post update events about that bit of data.

    So if you imagine a scenario where you want all your customer data to be managed by acentral customer management application. In particular it manages the customeraddresses. You also have a frequent imbiber program that rewards people who believethat its important to keep their single malt tasting skills up by practical means. When I usethe frequent imbiber website to order a special offer bottle of Lagavulin it sends a query tothe customer management system to get my shipping address during my session with thewebsite. If during this session I wish to update my address, the frequent imbiberapplication will take my request and send a command message to the customermanagement system to do the update.

    If we take this scenario to an event driven world, now all applications that need customerdata keep their own, read-only, copies of the customer data that they need. So during myorder for the Islay nectar the frequent imbiber application only consults its own replica ofcustomer addresses (it would only need to store addresses for people in the frequentimbiber program). If I request a change of address, the scenario is pretty much the sameas the request driven case. The frequent imbiber app sends a command message to thecustomer management application. The only difference is that the customer managementapplication then posts an event saying my address has changed which will then cause thefrequent imbiber application to update its record of my address.

    This example brings out the point that if you want central management of data, you'll needtwo kinds of event - requests to update data, which should be ignored by everything butthe managing application, and confirmed updates which everyone acts on. This may alsolead you to using a separate channel for update requests.

    Event Cascade

    When you're using Event Collaboration you need to be aware the consequences ofcascades. Event cascades are seen by some as the monster in the lake, others delight inthem.

    An event cascade is what happens when you get a sequence of events triggering otherevents. Unusually I'll illustrate this with an abstraction. Imagine three events A, B, and C.When you are working on event A you can comprehend that B is a consequence (A -> B)and that is good. Someone else is working on B and can comprehend that C is aconsequence (B -> C) and that is good. However there is now a cascade of A -> B -> C,which may be hard to see because you need to bridge both contexts to see it; while you're

    thinking of A you don't think about C and while you're working on B you don't think of A. .As a result this cascade can result in unexpected behavior which may be a good thing, butalso can be a problem. A three step cascade like this is the simple case, but obviouslycascades can become arbitrarily long - and the longer they are the more surprising theycan be.

    Let's looks at a rather more realistic example. Consider a management system foroperating rooms in a hospital. Operating rooms are scarce and expensive resources, sothey have to managed carefully to get the most use out of them. Operations are booked inadvance, sometimes weeks in advance (such as when I had the pins taken out of myhealed arm), sometimes rather more rapidly (such as when I had my broken arm in the

  • 7/28/2019 Event Collaboration

    5/16

    first place where I was operated on within hours).

    Since operating rooms are scarce resources it makes sense that if an operation iscanceled or postponed the room should be released so that it can be scheduled forsomething else. So the room scheduling system should listen for operation-postponedevents and release the room where the operation was scheduled to take place.

    When a patient comes in for a procedure, the hospital will run a series of pre-opevaluations. If one of these evaluations contra-indicates the operation, the operation

    should be postponed - at least until a clinician has a chance to look at it. So an operationscheduling system should listen for pre-op contra-indications and postpone any operationthat is contra-indicated.

    Both of these event causations are sensible, yet together they can have an unintendedeffect. Should someone come in and get a contra-indication, the operation is postponedand the room released. The problem is that a clinician might review the pre-op evaluationswithin a few minutes and decide to go ahead anyway, but in the meantime the room gotbooked by another operation. This can be very inconvenient to the patient, who even for astraightforward operation would have to prepare and fast for the operation.

    Event cascades are good because something happens and as a result of a string of locallogical event connections something indirect happens. Event cascades are bad becausesomething happens and as a result of a string of local logical event connectionssomething indirect happens. Event cascades usually look pretty obvious when they aredescribed like this, but until you see them they can be very hard to spot. This is an areawhere visualization systems that can build a graph of event chains by querying meta-datafrom the systems themselves could be very handy.

    When to use it

    The great strength ofEvent Collaboration is that it affords a very loose coupling betweenits components; this, of course, is also its great weakness.

    With Event Collaboration you can easily add new components to a system without existingcomponents needing to know anything about the new arrivals. As long as the newcomerslisten to the events, they can collaborate.

    Event Collaboration helps keep each component simple. All they need to know of theworld is the events they listen to. Whenever anything interesting happens they emit anevent - they don't even need to care if anyone else is listening. This allows developers tofocus on one component at a time - a component with very well controlled inputs.

    Event Collaboration is a great environment for Event Sourcing. If all communication usesEvent Collaboration then that removes the need for an event sourced application to usegateways on its inputs to mimic event communication.

    A system that uses Event Collaboration is more resilient to breakdowns. Since eachcomponent has all it needs to operate it can continue working even if communication tothe outside world is lost. But this is a two-edged sword. A component may continueoperating, but it will be working on out of date information if it's not receiving events asthings change. It may therefore initiate actions based on out of date information. Withrequest collaboration, it would just not work - which in some scenarios may be preferable.

    http://martinfowler.com/eaaDev/EventSourcing.htmlhttp://martinfowler.com/eaaDev/EventSourcing.htmlhttp://martinfowler.com/eaaDev/EventSourcing.html
  • 7/28/2019 Event Collaboration

    6/16

    Although each individual component is simpler, the complexity of the interactions willincrease. This is made worse because these interactions are not clear by reading thesource code. With request collaboration it's easy to see that a call from one componentleads to a reaction from another component. Even with polymorphism it's not difficult tolook things up and see the results. With Event Collaboration you don't know who islistening to the events until run-time - which in practice means you can only find the linksbetween the components in configuration data - and there may be multiple areas ofconfiguration data. As a result these interactions are hard to find, understand and debug.

    It is very helpful here to use automated tools that can display the configuration ofcomponents at run time so you can see what you have.

    Since each participant stores all the data that it needs, a lot of data will get replicated.This may not be as much as you think, since systems only need to store the data theyneed, so will only take a subset. Events themselves will also need to be stored, to act asan audit trail, help with error recovery, and the like. With very large datasets this may bean issue - although storage costs in particular are declining faster than most other thingsthese days.

    Acknowledgements

    My colleague Ian Cartwright helped he a great deal with his experience with this pattern.Doug Marcey helped me with a realistic example on event cascades.

    Example: Trading (C#)

    (with Ian Cartwright)

    We decided to use a stock trading example to help illustrate Event Collaboration and how

    it differs from the request-response style. We'll start with a base example and highlighthow a couple of modifications to the system work differently due to the collaboration style.

    The basic setup we begin with is that we have traders who make trades, which are thensent to a stock exchange. These trades are unconfirmed until the exchange notifies thatthey have been executed. Here's a simple test for this:

    [Test]publ i c voi d Nar r at i veOf Or der Li f eCycl e( ) {

    t r aderA. Pl aceOr der( "TW" , 1000) ;Assert . Ar eEqual ( 1, t r ader A. Out st andi ngOr der s. Count ) ;Execut eAl l Or der s( ) ;Assert . Ar eEqual ( 0, t r ader A. Out st andi ngOr der s. Count ) ;

    }

    To show how this works in the two styles we'll explore both styles of interaction as C# in-memory objects. The same principles would apply with multiple machines operating overa network. In each case we'll have multiple trader objects and multiple stock exchangeobjects.

    We'll start with how this might work in a request/response style. There are two interactionswe have to consider: placement and execution. For placement the trader object needs totell the stock exchange that the trade has been made.

  • 7/28/2019 Event Collaboration

    7/16

    cl ass Trader . . .publ i c voi d Pl aceOr der ( st r i ng symbol , i nt vol ume) {

    StockExchange exchange =Ser vi ceLocator . St ockExchangeFor ( symbol ) ;

    Or der or der = new Or der( symbol , vol ume, t hi s) ;exchange. Submi t Or der ( order ) ;

    }

    We're assuming here that each stock is traded in a single exchange and we find thecorrect exchange via a look-up. Our Orders are very simple, all we need is a symbol, avolume, and the trader who made it.

    The stock exchange object reacts by simply adding the new order to its list of outstandingorders.

    cl ass St ockExchange. . .publ i c voi d Submi t Or der ( Or der or der ) {

    out st andi ngOr der s. Add( or der ) ;}pr i vat e Li st out st andi ngOr der s = new Li st ( ) ;

    Submitting the order to the stock exchange object is an example of a command operation.

    We tell the exchange what we want to do, we don't really care about any results unlessanything goes wrong (in which case we get an exception). The command is alsosynchronous, in that we wait for the stock exchange to answer before we continueprocessing. That answer may only mean the exchange has received the submission, itmay mean validation has occurred. Since we've provided a reference to the caller (in theorder) the exchange may later contact the trader about the order.

    Now let's look at the code for execution.

    cl ass St ockExchange. . .publ i c voi d Execut e( Or der o) {

    out st andi ngOr der s. Remove(o) ;}

    As far as the exchange object all it needs to do is to remove the order from its list ofoutstanding orders as a record that the real exchange did whatever it needed to do.Should a trader need to see what orders were outstanding it does so by asking theexchanges.

    cl ass Trader . . .publ i c Li st Out st andi ngOr der s {

    get {Li st r esul t = new Li st ( ) ;Servi ceLocat or . For EachExchange(del egate(St ockExchange ex) {

    r esul t . AddRange( ex. Out st andi ngOr der sFor ( t hi s) ) ;}) ;r et ur n r esul t ;

    }}

  • 7/28/2019 Event Collaboration

    8/16

    Figure 3: Sequence diagram summarizing the interactions for placement, executions, andtrader query.

    Now lets look at this same scenario using Event Collaboration, starting again withplacement.

    cl ass Trader . . .publ i c voi d Pl aceOr der ( st r i ng st ock, i nt vol ume) {

    Or der order = new Or der ( st ock, vol ume) ;out st andi ngOr der s. Add( or der ) ;MessageBus. Publ i shOr der Pl acement ( order ) ;

    }

    A first thing to note here is that this time the trader keeps a note of what orders are

    outstanding - this is part of the shift in responsibility for keeping state. Since the traderneeds some state, it's up to the trader to keep that state.

    The second shift is the nature of the outward communication to the stock exchange. Herethe trader notifies a general message bus, which can pass the event onto anyone who isinterested. For the stock exchange to see the event it needs to subscribe to that kind ofevent, which it does in its constructor.

    cl ass St ockExchange. . .publ i c St ockExchange( ) {

    MessageBus. Subscr i beToOr ders( del egate( Or der o) {or der Recei vedCal l back(o) ;

    }) ;}

    cl ass MessageBus. . .publ i c st at i c voi d Subscr i beToOr der s( Or derPl acedDel egate method) {

    i nst ance. Or der Pl aced += method;}publ i c event Or derPl acedDel egat e Or derPl aced;publ i c del egat e voi d Or der Pl acedDel egat e( Or der or der ) ;

    Here we've wrapped the C# eventing mechanism inside publish and subscribe methods.This isn't strictly necessary, but we feel it makes it easier for non-C# people to follow.

  • 7/28/2019 Event Collaboration

    9/16

    When the trader publishes the placement event, the message bus then just pushes thatinformation out to subscribers.

    cl ass MessageBus. . .publ i c st at i c voi d Publ i shOr der Pl acement ( Or der or der ) {

    i f ( i nst ance. Or der Pl aced != nul l ) {i nst ance. Or der Pl aced( or der ) ;

    }}

    cl ass St ockExchange. . .

    pr i vat e voi d or der Recei vedCal l back(Or der or der ) {i f ( or der For Thi sExchange( or der ) )

    out st andi ngOr der s. Add( or der ) ;}

    Now lets look at execution. This begins again with the stock exchange object.

    cl ass St ockExchange. . .publ i c voi d Execut e ( Or der o) {

    MessageBus. Publ i shExecut i on( o) ;out st andi ngOr der s. Remove(o) ;

    }

    Here it removes the order from its list of outstanding, as it does in the request/responsecase. However it also publishes an event, which is picked up by the trader.

    [TBD: Add something on consumer driven interfaces here?]cl ass Trader . . .

    publ i c Tr ader ( ) {MessageBus. Subscr i beToExecut i ons( del egat e(Or der o) {

    or der Execut edCal l back(o) ;}) ;

    }

    pr i vat e voi d or der Execut edCal l back(Or der o)

    {i f ( out st andi ngOr der s. Cont ai ns( o) )

    out st andi ngOr der s. Remove( o) ;}

    (We've spared you the publish/subscribe implementation in the message bus, it's just thesame as the previous case.)

    The trader now updates its internal state in response to the events from the stockexchange. So to determine outstanding orders, it just checks its own internal state ratherthan issuing queries to other objects.

    cl ass Trader . . .publ i c I Li st Out st andi ngOr ders {

    get { r et ur n out st andi ngOr der s. AsReadOnl y( ) ; }}

  • 7/28/2019 Event Collaboration

    10/16

    Figure 4: Sequence diagram summarizing the interactions for placement, executions, andtrader query using events.

    Adding a risk tracking component

    So far we've looked at the different ways our trader and stock exchange collaborate withthese two styles. We can further see the differences by seeing how adding a thirdcomponent is different in the two styles.

    The third component we'll add is a risk management component. It's job is to look at thetotal volume outstanding across all traders with a particular stock.

    cl ass St ockRr Ri skTest er . . .[Test]publ i c voi d Shoul dTr ackTotal Out st andi ngVol umeFor Or der s( ) {

    Ri skTr acker t r acker = new Ri skTr acker ( nul l ) ;t r aderA. Pl aceOr der( "TW" , 1000) ;t r ader A. Pl aceOr der ( "I CMF", 7000) ;

    Trader t r aderB = new Trader ( ) ;t r ader B. Pl aceOr der ( "TW" , 500) ;Assert . Ar eEqual ( 1500, t r acker . Tot al Exposur e( "TW") ) ;

    }

    Furthermore the risk management system needs to send out an alert message if the totaloutstanding goes above a preset limit, and cancel alerts should it fall below.

    cl ass St ockRr Ri skTest er . . .[Test]publ i c voi d Shoul dTr ackAl er t WhenOver Li mi t For St ock( ) {

    st r i ng symbol = "TW" ;

  • 7/28/2019 Event Collaboration

    11/16

    Ser vi ceLocat or . Ri skTr acker . Set Li mi t ( symbol , 2000) ;t r aderA. Pl aceOr der( symbol , 2001) ;Asser t . Ar eEqual ( 1, Ser vi ceLocat or . Al er t Gat eway. Al er t sSent ) ;

    }

    In order for this to work the risk management system needs to involved in both the placingof orders (which increases exposure) and the execution of orders (which reduces it).

    We'll start by looking at the request/response scenario, starting with placement. We've

    chosen to modify the stock exchange object's submit method to alert the risk managerwith each order submission.

    cl ass St ockExchange. . .publ i c voi d Submi t Or der ( Or der or der ) {

    out st andi ngOr der s. Add( or der ) ;Ser vi ceLocat or . Ri skTr acker . CheckFor Al er t sOnOr der Pl acement ( or der . St ock) ;

    }

    We could make this change on the trader, but we chose the exchange because it willneed this dependency anyway for execution, so we're able to avoid making a dependencyfrom the trader to the risk tracker.

    In order for the risk tracker to determine the total exposure, it issues a query against therelevant stock exchange.

    cl ass Ri skTr acker . . .publ i c i nt Tot al Exposur e( st r i ng symbol ) {

    returnSer vi ceLocator . St ockExchangeFor ( symbol ) . Out st andi ngVol umeFor St ock( symbol ) ;

    }

    So when told about a new placement, the risk tracker tests the result of this query againstthe limit that it holds.

    cl ass Ri skTr acker . . .publ i c voi d CheckFor Al ert sOnOr derPl acement ( St r i ng symbol ) {

    i f ( Over Li mi t ( symbol ) )gateway. Gener ateAl ert ( symbol ) ;

    al er t edSt ocks. Add( symbol ) ;}

    pr i vat e bool Over Li mi t ( St r i ng symbol ) {r et ur n st ockLi mi t . Cont ai nsKey(symbol ) &&

    Tot al Exposur e(symbol ) > st ockLi mi t [ symbol ] ;}

    When a trade is executed, again the risk tracker needs to be called by the stockexchange. The tracker again checks to see the current total exposure and determineswhether it should cancel the alert.

    cl ass St ockExchange. . .publ i c voi d Execut e( Or der o) {

    out st andi ngOr der s. Remove(o) ;Ser vi ceLocat or . Ri skTr acker . CheckFor Cancel l edAl er t s( o. St ock) ;

    }cl ass Ri skTr acker . . .

    publ i c voi d CheckFor Cancel l edAl er t s( St r i ng symbol ) {

  • 7/28/2019 Event Collaboration

    12/16

    i f ( al er t edSt ocks. Cont ai ns( symbol ) && ! Over Li mi t ( symbol ) )gateway. Cancel Al er t ( symbol ) ;

    }

    Figure 5: Sequence diagram that shows how placing an order that goes above the risklimits triggers an alert using request/response.

    Now let's take a look at the case where we are using Event Collaboration. A keydifference is that adding a risk tracker does not require us to make any changes to theexisting components. Instead we build the risk tracker to listen to the events that theexisting components publish.

    cl ass Ri skTr acker . . .publ i c Ri skTr acker ( ) {

    st ockPosi t i on = new Di ct i onar y( ) ;st ockLi mi t = new Di ct i onar y( ) ;MessageBus. Subscr i beToOr ders( del egate( Or der o) {

    handl eOr derPl aced( o) ;}) ;

    MessageBus. Subscr i beToExecut i ons( del egat e(Or der o) {

    handl eExecut i on( o) ;}) ;

    }

    The tracker also needs data structures to keep track of positions, as it won't query thestock exchange in order to determine the exposure.

    When a trade is placed, the tracker picks up the event. In response it updates its copy ofthe positions and checks for going over the limit.

    cl ass Ri skTr acker . . .pr i vat e voi d handl eOr der Pl aced( Or der or der ) {

    i f ( ! st ockPosi t i on. Cont ai nsKey( or der . St ock) )st ockPosi t i on[ or der . St ock] = 0;

    st ockPosi t i on[ or der . St ock] += or der . Vol ume;checkFor Over Li mi t ( or der ) ;

    }

    pr i vat e voi d checkFor Over Li mi t ( Or der or der ) {i f ( Over Li mi t ( or der ) ) MessageBus. Publ i shAl er t Post ed( or der ) ;

    }pr i vat e bool Over Li mi t ( Or der or der ) {

    r et ur n st ockLi mi t . Cont ai nsKey(order . St ock) &&st ockPosi t i on[ or der . St ock] > st ockLi mi t [ or der . St ock] ;

  • 7/28/2019 Event Collaboration

    13/16

    }

    To continue to use Event Collaboration, it raises an event when an alert appears. If wethen want to send an email in response we can write an email gateway to listen to thatevent.

    On execution events, it again updates its copy of the positions and checks to see if itneeds to raise a cancellation.

    cl ass Ri skTr acker . . .pr i vat e voi d handl eExecut i on( Or der o) {bool wasOver Li mi t = Over Li mi t ( o) ;st ockPosi t i on[ o. St ock] - = o. Vol ume;i f ( wasOver Li mi t && ! Over Li mi t ( o) )

    MessageBus. Publ i shAl er t Cancel l ed( o) ;}

    Figure 6: Placing an order triggers an alert using events.

    This modification brings out some important differences between the two interactionstyles.

    We didn't need to modify existing components for Event Collaboration while we did forRequest-Response Collaboration. It's worth noting that this was in large part becausethe existing components broadcast all relevant change informationWe didn't add any dependencies to the new component for Event Collaboration.

    The Event Collaboration risk tracker was able to determine alerts without furthercommunication with other components since it already contained the necessary state.

    This lowered the amount of inter-component calls - which could be important if thecomponents were in separate processes. You could achieve the same effect withRequest-Response Collaboration by passing the current total exposure as part of thecall - but this mean the stock exchange object needs to know what data the risktracker needs to do its work - a further coupling between the two components.As we added the risk tracker, we ensured we used events to broadcast it's newlyadded information so that it could be a good citizen in the general collaboration. (Andindeed we used it to trigger the email gateway.) Note that the events published by therisk tracker weren't tied to changes in state of the tracker (as we didn't broadcast thechanges to positions) but to the new information that the tracker added to the globalknowledge - whether or not the exposure was over the limits.

    http://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.html
  • 7/28/2019 Event Collaboration

    14/16

    Many people would consider that these differences are fundamentally about a system withless coupling for Event Collaboration than for Request-Response Collaboration. We're notso sure. In Request-Response Collaboration components are coupled to each otherthrough their interfaces, expressed as a menu of possible requests. But the same basiccoupling exists in Event Collaboration, it's just that the interfaces have changed fromrequest calls to events. If I change a component's event, it will still have repercussions onother components.

    The crucial difference is that the communication flows between the components are nolonger contained inside the components. Using Event Collaboration we don't have to getthe stock exchange to tell the risk tracker when it should check its alerts. This behavioroccurs implicitly through the evening model.

    But this implicit behavior brings with it a dark side. Let's imagine another change to ourcomponents. So far we've assumed that orders are executed in total. Let's alter our stockexchange to handle partial execution.

    [Test]publ i c voi d Shoul dCancel Al er t I f Par i t al Execut i onTakesBel owLi mi t ( ) {

    StockExchange exchange = Ser vi ceLocat or . StockExchangeFor ( "TW") ;Ser vi ceLocat or . Ri skTr acker . Set Li mi t ( "TW", 2000) ;t r aderA. Pl aceOr der( "TW" , 3000) ;Asser t . Ar eEqual ( 1, Ser vi ceLocat or . Al er t Gat eway. Al er t sSent ) ;Or der t heOr der = exchange. Outst andi ngOr der s[ 0] ;exchange. Execut e( t heOr der , 1000) ;Assert . Ar eEqual ( 1, Ser vi ceLocat or . Al er t Gat eway. Cancel sSent ) ;

    }[Test]publ i c voi d Shoul dNot Cancel Al er t I f Par i t al Execut i onSt i l l AboveLi mi t ( ){

    StockExchange exchange = Ser vi ceLocat or . StockExchangeFor ( "TW") ;Ser vi ceLocat or . Ri skTr acker . Set Li mi t ( "TW", 2000) ;t r aderA. Pl aceOr der( "TW" , 3000) ;

    Asser t . Ar eEqual ( 1, Ser vi ceLocat or . Al er t Gat eway. Al er t sSent ) ;Or der t heOr der = exchange. Outst andi ngOr der s[ 0] ;exchange. Execut e( t heOr der , 999) ;Assert . Ar eEqual ( 0, Ser vi ceLocat or . Al er t Gat eway. Cancel sSent ) ;

    }

    Now lets look at the modifications we need to make to do this. For Request-ResponseCollaboration, we need to modify the stock exchange to record a partial execution.

    cl ass St ockExchange. . .publ i c voi d Execut e( Or der o, i nt vol ume) {

    o. Execut edAmount += vol ume;i f ( o. I sFul l yExecut ed) out st andi ngOr der s. Remove( o) ;

    Ser vi ceLocat or . Ri skTr acker . CheckFor Cancel l edAl er t s( o. St ock) ;}publ i c voi d Execut e( Or der o) {

    Execut e(o, o. Vol ume) ;}

    cl ass Or der . . .publ i c i nt Execut edAmount {

    get { return executedVol ume; }set { execut edVol ume = val ue; }

    }publ i c bool I sFul l yExecut ed {

    get { r et urn execut edVol ume == vol ume; }

    http://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.htmlhttp://martinfowler.com/eaaDev/RequestResponseCollaboration.html
  • 7/28/2019 Event Collaboration

    15/16

    Guides

    IntroDesignAgileNoSQLDSLDeliveryAboutMe

    Popular Articles

    New MethodologyDependency InjectionMocks arent StubsIs Design Dead?Continuous Integration

    Books

    NoSQL DistilledDomain-Specific LanguagesRefactoringPatterns of Enterprise Application ArchitectureUML DistilledAnalysis PatternsPlanning Extreme ProgrammingSignature Series

    Site Sections

    FAQContent IndexBlikiBooksDSL CatalogEAA CatalogEAA DevPhotos

    }pr i vat e i nt execut edVol ume;

    Because there's a reference to the risk tracker right there, this helps remind us to considerto modify the risk tracker to take into account the partial execution case. However sincethe tracker gets the total outstanding by querying the stock exchange, we don't actuallyhave to modify the risk tracker at all.

    When we look at the Event Collaboration case, things are a bit more tricky. The basic

    modification to the stock exchange object is similar.

    cl ass St ockExchange. . .publ i c voi d Execut e( Or der o, i nt amount ) {

    o. Execut edAmount += amount ;MessageBus. Publ i shExecut i on( o) ;i f ( o. I sFul l yExecut ed) out st andi ngOr der s. Remove( o) ;

    }publ i c voi d Execut e( Or der o) {

    Execut e(o, o. Vol ume) ;}

    However since there's no indication of the link to the risk tracker, there's nothing to

    suggest that we should consider modifying it. Since the executed amount is a property ofthe order, everything will still compile cleanly, even with a statically typed system. But therisk tracker will now start giving out incorrect information, without any more obvious signsof failure, since it isn't properly capturing the data changes.

    This, of course, is the inherent weakness of any system with implicit behavior - since youcan't see it, you don't see what changes need to be made when you modify it. It can alsobe hard to debug, again because the flow of logic isn't made explicit in code.

    What this shows is that using Event Collaboration makes some changes easier, butothers harder. It's not easy to get a fair picture of the trade-offs, since we haven't seen

    much that really captures experience based on a real understanding of the two differentstyles.

    Signif icant Revisions

    19 Jun 06: Published version with example.

    08 Mar 06: Added stock trading example

    21 Dec 05: First draft

    http://martinfowler.com/intro.htmlhttp://martinfowler.com/design.htmlhttp://martinfowler.com/agile.htmlhttp://martinfowler.com/nosql.htmlhttp://martinfowler.com/dsl.htmlhttp://martinfowler.com/delivery.htmlhttp://martinfowler.com/aboutMe.htmlhttp://martinfowler.com/aboutMe.htmlhttp://martinfowler.com/articles/newMethodology.htmlhttp://martinfowler.com/articles/injection.htmlhttp://martinfowler.com/articles/mocksArentStubs.htmlhttp://martinfowler.com/articles/designDead.htmlhttp://martinfowler.com/articles/continuousIntegration.htmlhttp://martinfowler.com/books/nosql.htmlhttp://martinfowler.com/books/dsl.htmlhttp://martinfowler.com/books/refactoring.htmlhttp://martinfowler.com/books/eaa.htmlhttp://martinfowler.com/books/uml.htmlhttp://martinfowler.com/books/ap.htmlhttp://martinfowler.com/books/pxp.htmlhttp://martinfowler.com/bookshttp://martinfowler.com/faq.htmlhttp://martinfowler.com/tagshttp://martinfowler.com/blikihttp://martinfowler.com/bookshttp://martinfowler.com/dslCataloghttp://martinfowler.com/eaaCataloghttp://martinfowler.com/eaaDevhttp://martinfowler.com/photoshttp://martinfowler.com/photoshttp://martinfowler.com/eaaDevhttp://martinfowler.com/eaaCataloghttp://martinfowler.com/dslCataloghttp://martinfowler.com/bookshttp://martinfowler.com/blikihttp://martinfowler.com/tagshttp://martinfowler.com/faq.htmlhttp://martinfowler.com/bookshttp://martinfowler.com/books/pxp.htmlhttp://martinfowler.com/books/ap.htmlhttp://martinfowler.com/books/uml.htmlhttp://martinfowler.com/books/eaa.htmlhttp://martinfowler.com/books/refactoring.htmlhttp://martinfowler.com/books/dsl.htmlhttp://martinfowler.com/books/nosql.htmlhttp://martinfowler.com/articles/continuousIntegration.htmlhttp://martinfowler.com/articles/designDead.htmlhttp://martinfowler.com/articles/mocksArentStubs.htmlhttp://martinfowler.com/articles/injection.htmlhttp://martinfowler.com/articles/newMethodology.htmlhttp://martinfowler.com/aboutMe.htmlhttp://martinfowler.com/aboutMe.htmlhttp://martinfowler.com/delivery.htmlhttp://martinfowler.com/dsl.htmlhttp://martinfowler.com/nosql.htmlhttp://martinfowler.com/agile.htmlhttp://martinfowler.com/design.htmlhttp://martinfowler.com/intro.html
  • 7/28/2019 Event Collaboration

    16/16

    houghtWorks

    BlogsCareersMingle

    TwistGo

    Martin Fowler | Privacy Policy | Disclosures

    http://thoughtworks.com/blogshttp://thoughtworks.com/careershttp://www.thoughtworks-studios.com/mingle-agile-project-managementhttp://www.thoughtworks-studios.com/agile-test-automationhttp://www.thoughtworks-studios.com/go-agile-release-managementhttp://www.thoughtworks.com/privacy-policyhttp://martinfowler.com/aboutMe.html#disclosureshttp://martinfowler.com/aboutMe.html#disclosureshttp://www.thoughtworks.com/privacy-policyhttp://www.thoughtworks-studios.com/go-agile-release-managementhttp://www.thoughtworks-studios.com/agile-test-automationhttp://www.thoughtworks-studios.com/mingle-agile-project-managementhttp://thoughtworks.com/careershttp://thoughtworks.com/blogs