5

I am developing an application that consumes data from an external service. The application is being implemented following a typical layered architecture with UI, Presentation, Domain and Data layers. The service client resides within the Data layer.

As is typically the case, I do not want the UI to 'lock-up' while waiting for calls from the external service to complete. However, implementing the service agents with asynchronous methods results in a complicate model chaining async methods up the layers so the UI can stay responsive.

For example:

In the ViewModel:

TheRepository.LoadDataAsync().ContinueWith(t => { _data = t.Result; });

In TheRepository:

public Task<TheData> LoadDataAsync()
{
    return ServiceClient.GetDataFromServiceAsync();
}

(Note, this is a significant over-simplification meant to convey what I mean by task chaining.)

Because the requirement is a UI requirement (prevent the UI from 'locking'), doesn't it make sense to keep the Domain and Data layers synchronous and leave it up to the Presentation layer to decide when it needs to perform some operation asynchronously?

On the other hand, it is so easy and natural to implement the service client/proxy with async methods (VS will auto-generate them if needed) because this is what we think of when we think about the need for async.

If the application was pulling data out of a database instead of making a service call, the layers wouldn't be any different and it shouldn't really change how the UI, Presentation or Domain layers have been implemented, right? In this case, we wouldn't think twice about having the data access be synchronous.

Would it be a better design to model the Domain synchronously and leave it to the Presentation layer to address performance issues in the UI? Or, in the emerging async world, should we just accept async as the norm and make everything fit this model?

2
  • What if somewhere along the chain of responsibility you want to keep updating a timeout variable? How is this code going to ever get to check whether the timeout has expired, cancel the tasks, and notify the user? This is a case where you may even want your middle layers to be synchronous, so it can supervise the async code, because the user will just wait forever, but you have determined through some process tha if async doesn't compete within 15 seconds, it never will. HELP you users, using async to let them continue their general mousing around but sync code 'watches the pot boil' Sep 2, 2013 at 15:44
  • It is now 2019; it would be interesting to hear your own experiences on this after 6 years. :) Did experience help you answer this question? I'm interested since I am currently in the same boat. Do we make application service interfaces 'async' or not. Oct 2, 2019 at 13:15

3 Answers 3

6

Whether a component does work synchronously or asynchronously is an implementation detail. Your design choice for each layer should be independent.

You stated a use case for the UI layer being asynchronous, it needs to not lock up so it should be asynchronous. For each other layer if they have a use case for being asynchronous then make them asynchronous otherwise make them synchronous. As you describe it currently I don't see any advantage in having your repository asynchronous.

2
  • does this mean that it is ok to implement "asynchronous" in domain or datalayer if there is a usecase for it and there is no need to put "asynchronous" to somewhere else?
    – k3b
    Sep 2, 2013 at 14:59
  • Yes. Its trivial to add a synchronous façade to the asynchronous methods if you want to consume them that way. Obviously though there is a design choice the programmer has to make. Is the use case important enough to warrant the extra complexity. Sep 2, 2013 at 15:18
2
 > Which layer does async code belong?

Short answer: into presenter or into an extra service-layer but not in the gui, data or domain layer.

Long answer:

I would put it into a service-layer that sits between presenter- and domain-layer resulting in these layers

gui - presenter - service - domain - data

In the domainlayer (or the servicelayer) you have a synchronios version of the logic that needs to consume the data of the external service. Lets call it mySyncMethod.

In the servicelayer you create a thin async wrapper around mySyncMethod.

Reason: It is very difficuilt to unittest async methods. sync methods are much easier to test.

If there is only one reference to the async functionality you can put into the presenter.

0

Whenever I deal with asynchronous web calls that populate UI data I start by throwing in a busy indicator of some sort (unless it is something that the end user does is not specifically waiting to happen). Once the data is ready I either place it in a property that gets synced with the UI on the next UI thread loop or marshal a message back to the UI thread depending on the type of application and what platform I am developing on. Here is a quick and dirty example in C#:

// Method executed in some other non UI thread!
private void OtherThreadMethod() {
    //Invoke the method that should change the control in the UI thread
    this.Dispatcher.BeginInvoke( UIThreadMethod );
}

private void UIThreadMethod() {
    //Perform the change of the control
    this.Cursor = Cursors.Wait;
}

The goal being that if the user is waiting for something to happen or some background data needs to be handled the program should not just freeze and wait. For example if I am copying a file in Windows Explorer, I want to be able to browse my pictures while I wait.

4
  • 2
    Yea, I'm aware how to marshall execution between threads. My question is whether or not we should be treating the operations as synchronous methods and letting the UI decide what to put on a background thread (what to execute asynchronously) or do we let the data layer dictate that the operation is asynchronous because we chose to implement the data layer asynchronously. Aug 2, 2013 at 20:04
  • 1
    For me, it is always a matter of user experience over "proper code" so it depends on what makes more sense at the time. If the user should have nothing better to do than wait, then I put everything synchronously on the UI layer. If the user has an alternative to waiting, I prefer to keep the operation asynchronous and simply notify the UI (and sometimes the user) when it needs to change. Sometimes it even just boils down to what is easier to implement in the case that some platforms are built to use one of the other, and getting it to do the opposite is difficult. Aug 5, 2013 at 21:01
  • What if the UI has nothing better to do than wait, but new circumstances ( phone call canceling the order to do something ) allow the user to cancel the async process. Keeping the UI responsive is still important even if don't think there is any other way to proceed, no?. Sep 2, 2013 at 15:37
  • Yes, that is correct. Before you make something synchronous you should always think of every possible circumstance in which the user would not want to just wait. Nine times out of ten I make async calls but there are always a few edge cases in which you want an operation to be unstoppable and force the user to wait before continuing. A good example would be the synchronous loading of fonts and modules when MS Word loads. The application is pointless without those items and therefore the user must wait for them before interacting with the application. Sep 2, 2013 at 15:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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