Design with async/await – should everything be async?

should I make absolutely all my methods initially async even if I’m not planning to call anything async inside?

This design problem with async is essentially the same as the problem with IDisposable. That is, interfaces have to predict their implementations. And this is going to be messy, no matter what you do.

In my experience, it’s usually rather straightforward to consider a method/interface/class and predict whether it will use I/O or not. If it requires I/O, then it should probably be made task-returning. Sometimes (but not always), it’s possible to structure your code so that I/O is done in its own section of the code, leaving business objects and logic strictly synchronous. The Redux pattern in the JavaScript world is a good example of this.

But bottom line, sometimes you make the wrong call and have to refactor. I think this is a far better approach than just making every method asynchronous. Do you make every interface inherit from IDisposable and use using everywhere? Nah, you only add it when necessary; and you should take the same approach with async.

Leave a Comment