Por supuesto, se puede invocar la ley de las abstracciones con fugas , pero eso no es particularmente interesante porque plantea que todas las abstracciones tienen fugas. Se puede argumentar a favor y en contra de esa conjetura, pero no ayuda si no compartimos una comprensión de lo que queremos decir con abstracción y lo que queremos decir con fugas . Por lo tanto, primero intentaré delinear cómo veo cada uno de estos términos:
Abstracciones
Mi definición favorita de abstracciones se deriva de la APPP de Robert C. Martin :
"Una abstracción es la amplificación de lo esencial y la eliminación de lo irrelevante".
Por lo tanto, las interfaces no son, en sí mismas, abstracciones . Solo son abstracciones si sacan a la superficie lo que importa y ocultan el resto.
Agujereado
El libro Principios, patrones y prácticas de la inyección de dependencia define el término abstracción permeable en el contexto de la inyección de dependencia (DI). El polimorfismo y los principios SÓLIDOS juegan un papel importante en este contexto.
Del Principio de Inversión de Dependencia (DIP) se desprende, citando nuevamente APPP, que:
"los clientes [...] poseen las interfaces abstractas"
Lo que esto significa es que los clientes (código de llamada) definen las abstracciones que requieren, y luego van e implementan esa abstracción.
Una abstracción con fugas , en mi opinión, es una abstracción que viola el DIP al incluir de alguna manera alguna funcionalidad que el cliente no necesita .
Dependencias sincrónicas
Un cliente que implementa una parte de la lógica empresarial generalmente usará DI para desacoplarse de ciertos detalles de implementación, como, por lo general, las bases de datos.
Considere un objeto de dominio que maneja una solicitud de reserva de restaurante:
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);
}
}
Aquí, la IReservationsRepositorydependencia está determinada exclusivamente por el cliente, la MaîtreDclase:
public interface IReservationsRepository
{
Reservation[] ReadReservations(DateTimeOffset date);
int Create(Reservation reservation);
}
Esta interfaz es completamente sincrónica ya que la MaîtreDclase no necesita que sea asíncrona.
Dependencias asincrónicas
Puede cambiar fácilmente la interfaz para que sea asíncrona:
public interface IReservationsRepository
{
Task<Reservation[]> ReadReservations(DateTimeOffset date);
Task<int> Create(Reservation reservation);
}
La MaîtreDclase, sin embargo, no necesita esos métodos sean asíncrona, por lo que ahora se viole el DIP. Considero que esto es una abstracción permeable, porque un detalle de implementación obliga al cliente a cambiar. El TryAcceptmétodo ahora también tiene que volverse asíncrono:
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);
}
No existe una lógica inherente para que la lógica de dominio sea asíncrona, pero para admitir la asincronía de la implementación, esto ahora se requiere.
Mejores opciones
En NDC Sydney 2018 di una charla sobre este tema . En él, también describo una alternativa que no tiene fugas. También daré esta charla en varias conferencias en 2019, pero ahora se renombró con el nuevo título de inyección asíncrona .
También planeo publicar una serie de publicaciones de blog para acompañar la charla. Estos artículos ya están escritos y en la lista de espera de mi artículo, esperando ser publicados, así que estad atentos.