Good Code
The good version receives repository and bus dependencies through the constructor. The service boundary says what infrastructure the workflow needs.
Lesson 04
Receive collaborators through constructors so services declare their dependencies and tests can replace infrastructure.
public sealed class ReviewPublisher
{
private readonly ReviewRepository reviews;
private readonly MessageBus bus;
public ReviewPublisher(ReviewRepository reviews, MessageBus bus)
{
this.reviews = reviews;
this.bus = bus;
}
public async Task PublishAsync(Guid id, CancellationToken cancellationToken)
{
// Constructor dependencies make infrastructure visible.
Review review = await reviews.GetAsync(id, cancellationToken);
await bus.PublishAsync(new ReviewPublished(id, review.Title), cancellationToken);
}
}public sealed class ReviewPublisher
{
public async Task PublishAsync(Guid id)
{
// New infrastructure inside the method hides dependencies.
var reviews = new ReviewRepository("prod");
var bus = new MessageBus("prod");
Review review = await reviews.GetAsync(id);
await bus.PublishAsync(new ReviewPublished(id, review.Title));
}
}The good version receives repository and bus dependencies through the constructor. The service boundary says what infrastructure the workflow needs.
The bad version creates production infrastructure inside the method. Tests cannot replace those collaborators without touching the implementation.