One can, of course, invoke the [law of leaky abstractions][1], but that's not particularly interesting because it posits that all abstractions are leaky. One can argue for and against that conjecture, but it doesn't help if we don't share an understanding of what we mean by *abstraction*, and what we mean by *leaky*. Therefore, I'll first try to delineate how I view each of these terms: # Abstractions My favourite definition of *abstractions* is derived from Robert C. Martin's [APPP][2]: > "An abstraction is the amplification of the essential and the elimination of the irrelevant." Thus, [interfaces aren't, in themselves, abstractions][3]. They're only abstractions if they bring to the surface what matters, and hides the rest. # Leaky The book *Dependency Injection Principles, Patterns, and Practices* defines the term *leaky abstraction* in the context of Dependency Injection (DI). Polymorphism and the SOLID principles play a big role in this context. From the [Dependency Inversion Principle][4] (DIP) it follows follows, again quoting APPP, that: > "clients [...] own the abstract interfaces" What this means is that clients (calling code) define the abstractions that they require, and then you go and implement that abstraction. A *leaky abstraction*, in my view, is an abstraction that violates the DIP by somehow including some functionality that the client doesn't *need*. # Synchronous dependencies A client that implements a piece of business logic will typically use DI to decouple itself from certain implementation details, such as, commonly, databases. Consider a domain object that handles a request for a restaurant reservation: public class MaîtreD : IMaîtreD { public MaîtreD(int capacity, IReservationsRepository repository) { Capacity = capacity; Repository = repository; } public int Capacity { get; } public IReservationsRepository Repository { get; } public int? TryAccept(Reservation reservation) { var reservations = Repository.ReadReservations(reservation.Date); int reservedSeats = reservations.Sum(r => r.Quantity); if (Capacity < reservedSeats + reservation.Quantity) return null; reservation.IsAccepted = true; return Repository.Create(reservation); } } Here, the `IReservationsRepository` dependency is determined *exclusively* by the client, the `MaîtreD` class: public interface IReservationsRepository { Reservation[] ReadReservations(DateTimeOffset date); int Create(Reservation reservation); } This interface is entirely synchronous since the `MaîtreD` class doesn't *need* it to be asynchronous. # Asynchronous dependencies You can easily change the interface to be asynchronous: public interface IReservationsRepository { Task<Reservation[]> ReadReservations(DateTimeOffset date); Task<int> Create(Reservation reservation); } The `MaîtreD` class, however, doesn't *need* those methods to be asynchronous, so now the DIP is violated. I consider this a leaky abstraction, because an implementation detail forces the client to change. The `TryAccept` method now also has to become asynchronous: public async Task<int?> TryAccept(Reservation reservation) { var reservations = await Repository.ReadReservations(reservation.Date); int reservedSeats = reservations.Sum(r => r.Quantity); if (Capacity < reservedSeats + reservation.Quantity) return null; reservation.IsAccepted = true; return await Repository.Create(reservation); } There's no inherent rationale for the domain logic to be asynchronous, but in order to support the asynchrony of the implementation, this is now required. # Better options At NDC Sydney 2018 [I gave a talk on this topic][5]. In it, I also outline an alternative that doesn't leak. I'll be giving this talk at several conferences in 2019 as well, but now rebranded with the new title of *Async injection*. I plan to also publish a series of blog posts to accompany the talk. These articles are already written and sitting in my article queue, waiting to be published, so stay tuned. [1]: https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions [2]: http://amzn.to/19W4JHk [3]: http://blog.ploeh.dk/2010/12/02/Interfacesarenotabstractions [4]: https://en.wikipedia.org/wiki/Dependency_inversion_principle [5]: https://youtu.be/F9bznonKc64