My colleague and I have dispute. We are writing a .NET application that processes massive amounts of data. It receives data elements, groups subsets of them into blocks according to some criterion and processes those blocks.Let's say we have data items of type Foo arriving some source (from the network, for example) one by one. We wish to gather subsets of related objects of type Foo, construct an object of type Bar from each such subset and process objects of type Bar.One of us suggested the following design. Its main theme is exposing IObservable objects directly from the interfaces of our components.// ********* Interfaces **********interface IFooSource{    // this is the event-stream of objects of type Foo    IObservable<Foo> FooArrivals { get; }}interface IBarSource{    // this is the event-stream of objects of type Bar    IObservable<Bar> BarArrivals { get; }}/ ********* Implementations *********class FooSource : IFooSource{    // Here we put logic that receives Foo objects from the network and publishes them to the FooArrivals event stream.}class FooSubsetsToBarConverter : IBarSource{    IFooSource fooSource;    IObservable<Bar> BarArrivals    {        get        {            // Do some fancy Rx operators on fooSource.FooArrivals, like Buffer, Window, Join and others and return IObservable<Bar>        }    }}// this class will subscribe to the bar source and do processingclass BarsProcessor{    BarsProcessor(IBarSource barSource);    void Subscribe(); }// ******************* Main ************************class Program{    public static void Main(string[] args)    {        var fooSource = FooSourceFactory.Create();        var barsProcessor = BarsProcessorFactory.Create(fooSource) // this will create FooSubsetToBarConverter and BarsProcessor        barsProcessor.Subscribe();        fooSource.Run(); // this enters a loop of listening for Foo objects from the network and notifying about their arrival.    }}The other suggested another design that its main theme is using our own publisher/subscriber interfaces and using Rx inside the implementations only when needed.//********** interfaces *********interface IPublisher<T>{    void Subscribe(ISubscriber<T> subscriber);}interface ISubscriber<T>{    Action<T> Callback { get; }}//********** implementations *********class FooSource : IPublisher<Foo>{    public void Subscribe(ISubscriber<Foo> subscriber) { /* ...  */ }    // here we put logic that receives Foo objects from some source (the network?) publishes them to the registered subscribers}class FooSubsetsToBarConverter  : ISubscriber<Foo>, IPublisher<Bar>{    void Callback(Foo foo)    {        // here we put logic that aggregates Foo objects and publishes Bars when we have received a subset of Foos that match our criteria        // maybe we use Rx here internally.    }    public void Subscribe(ISubscriber<Bar> subscriber) { /* ...  */ }}class BarsProcessor : ISubscriber<Bar>{    void Callback(Bar bar)    {        // here we put code that processes Bar objects    }}//********** program *********class Program{    public static void Main(string[] args)    {        var fooSource = fooSourceFactory.Create();        var barsProcessor = barsProcessorFactory.Create(fooSource) // this will create BarsProcessor and perform all the necessary subscriptions        fooSource.Run();  // this enters a loop of listening for Foo objects from the network and notifying about their arrival.    }}Which one do you think is better? Exposing IObservable and making our components create new event streams from Rx operators, or defining our own publisher/subscriber interfaces and using Rx internally if needed?Here are some things to consider about the designs:In the first design the consumer of our interfaces has the whole power of Rx at his/her fingertips and can perform any Rx operators. One of us claims this is an advantage and the other claims that this is a drawback.The second design allows us to use any publisher/subscriber architecture under the hood. The first design ties us to Rx.If we wish to use the power of Rx, it requires more work in the second design because we need to translate the custom publisher/subscriber implementation to Rx and back. It requires writing glue code for every class that wishes to do some event processing.
Should I expose IObservable on my interfaces?
c#;.net
I think saying that IObservable<T> ties you to Rx is the same as saying that IEnumerable<T> ties you to LINQ. Yes, IObservable<T> is at the core of Rx and Rx lets you do a lot of things with IObservable<T>.But that doesn't mean you have to use Rx to implement your classes, even if they inherit from IObservable<T>. And you also don't have to use Rx to work with the class, you could directly use Subscribe(). I believe this is also the reason why IObservable<T> is included in the core of the framework (it's in mscorlib since .Net 4), but Rx isn't.So, unless IObservable<T> doesn't fit your needs, you should use it. On the plus side, you'll get the possibility to use Rx. On the negative side, you might need to wrap your implementation to make it look like IObservable<T>, if you decide to change the implementation later on. But you would have to do the same if you used a custom interface.IObservable<T> is just an interface, it doesn't tie you up to anything. But it gives you the ability to use libraries that already work with it, unlike a custom interface.