In much of the literature I've read online with respect to multi-layered architectures, many people describe how to create the simple application where:
- UI presents static model objects to the screen.
- Users can make one-off requests (e.g. send e-mail, commit payment).
- A database transaction is typically made to return new information to show to the screen.
Often, the articles will describe these concepts while adhering to Eric Evan's Domain-Driven Design.
Despite the good resources online, there isn't much guidance on how to organize the software responsibilities for applications that need to be continuously communicating with external devices. Consider the following:
- An e-mail client should continuously query a POP server to know when new e-mail has arrived.
- A device monitor should continuously query the device's status variables to always display the live values (e.g an aircraft HMI might depend on the visibility of hundreds of variables at all times).
In both cases, the UI needs to be updated in real-time as changes occur in the external world. My question is about who should be responsible for initiating the requests to be made. I have come up with two potential solutions, the first involving a direct request from the UI, and the second utilizing inversion-of-control so that the UI can be notified:
- The UI layer can make use of background-threads (e.g. .NET's
BackgroundWorker) to continuously make direct queries to application services which return ONLY the data required by the view in question.
- A background thread in an infrastructure service can continuously query ALL relevant information from an external device (perhaps by relying on some configuration) and send events/notifications (or call a callback) to other layers so that the UI can react. While personally not a fan of it, an event aggregator can be helpful to this end.
I think that solution #1 is better aligned with the examples I've come across, but my concern is that this is NOT a scalable solution. As the amount of continuous I/O increases, spinning off many background threads (for each view) not only causes us to violate DRY, but it degrades performance because of many, small I/O requests instead of few, large I/O requests.
How should we approach multi-layered architectures that need large amounts of continuous, real-time, communication?
Should the UI make direct queries on their own background threads, or should a single background thread and inversion-of-control be used?