IMO ConfigureAwait is just the result of a failure to fully consider the implications of various design choices early on. To be fair, it is a tough problem, but the ergonomics ended up being horrible and the default they chose was probably the wrong default.
There are some other choices they made that are arguably not the right ones - for example, async code can do some of its initial execution on the calling thread and do the rest wherever continuations get scheduled (which is configurable...) which means you have to have exception handling in two places and the way the exception handling works will be different (the article calls this out). It is possible to avoid this by having the initial call to the async function only create the task but not run any of it - of course, there are reasons not to do it, performance being one of them, so it makes sense that they did it... it's just bad to optimize by default instead of making code simpler and more reliable.
My least favorite decision is that inexplicably, async/await state machines are very error prone... if any part of your codebase accidentally invokes a continuation twice, the state machine will potentially begin running twice or even start running again from the beginning with the same local variables. Fixing this would have been as simple as setting a bool at the end and checking it at the beginning, but for some reason they are dead-set on not fixing it. Premature optimization once again.
The existence of 'async void' is also just a complete trainwreck. They shouldn't have allowed it, especially since an 'async Task' that discards its result is just as easy.
The approach to cancellation (intrusive only) is also needlessly complex and gross. Putting a Dispose method on a Task would allow consumers of any async API to cleanly signal that they no longer need the result of a Task and any implementation would be able to observe this without anyone having to introduce a new method overload that takes a CancellationToken, not to mention that the intrusive cancellation design creates extra garbage on the heap. Really not obvious to me why they did this instead of reusing 'using x' and IDisposable.
There are some other choices they made that are arguably not the right ones - for example, async code can do some of its initial execution on the calling thread and do the rest wherever continuations get scheduled (which is configurable...) which means you have to have exception handling in two places and the way the exception handling works will be different (the article calls this out). It is possible to avoid this by having the initial call to the async function only create the task but not run any of it - of course, there are reasons not to do it, performance being one of them, so it makes sense that they did it... it's just bad to optimize by default instead of making code simpler and more reliable.
My least favorite decision is that inexplicably, async/await state machines are very error prone... if any part of your codebase accidentally invokes a continuation twice, the state machine will potentially begin running twice or even start running again from the beginning with the same local variables. Fixing this would have been as simple as setting a bool at the end and checking it at the beginning, but for some reason they are dead-set on not fixing it. Premature optimization once again.
The existence of 'async void' is also just a complete trainwreck. They shouldn't have allowed it, especially since an 'async Task' that discards its result is just as easy.
The approach to cancellation (intrusive only) is also needlessly complex and gross. Putting a Dispose method on a Task would allow consumers of any async API to cleanly signal that they no longer need the result of a Task and any implementation would be able to observe this without anyone having to introduce a new method overload that takes a CancellationToken, not to mention that the intrusive cancellation design creates extra garbage on the heap. Really not obvious to me why they did this instead of reusing 'using x' and IDisposable.