2 added 371 characters in body
source | link

If transactional correctness requires one aggregate knowing about the current state of another aggregate, then your model is wrong.

In most cases, transactional correctness is not required. Businesses tend to have tolerance around latency and stale data. This is especially true of inconsistencies that are easy to detect and easy to remedy.

So the command is going to be run by the aggregate that changes state. To perform the not necessarily correct check, it needs a not necessarily the latest copycopy of the statestate of the other aggregate.

For commands on an existing aggregate, the usual pattern is to pass a DomainServiceRepository to the aggregate, and the aggregate will pass its state to the domain service as arguments for therepository, which provides a query. that returns an immutable state/projection of the other aggregate

class Feedback {
    void downvote(SupplierOperatingQueryRepository<Supplier.State> query) {
        booleanSupplier.State isOperatingsupplier = query.isOperatinggetById(this->supplierId);
        boolean isOperating = state.isOperating();
        ....
    }
}

But construction patterns are weird - when you are creating the object, the caller already knows the internal state, because it is providing it. The same pattern works, it just looks pointless

class Feedback {
    __constrict__construct(SupplierId supplierId, SupplierOperatingQuery query ...) {
        booleanSupplier.State isOperatingsupplier = query.isOperatinggetById(this->supplierId);
        boolean isOperating = state.isOperating();
        ....
    }
}

We're following the rules by keeping all the domain logic in the domain objects, but we aren't really protecting the business invariant in any useful way by doing so (because all of the same information is available to the application component). For the creation pattern, it would be just as good to write

class Feedback {
    __construct(Supplier.State supplier, ...) {
        boolean isOperating = state.isOperating();
        ....
    }
}

If transactional correctness requires one aggregate knowing about the current state of another aggregate, then your model is wrong.

In most cases, transactional correctness is not required. Businesses tend to have tolerance around latency and stale data. This is especially true of inconsistencies that are easy to detect and easy to remedy.

So the command is going to be run by the aggregate that changes state. To perform the not necessarily correct check, it needs a not necessarily the latest copy of the state of the other aggregate.

For commands on an existing aggregate, the usual pattern is to pass a DomainService to the aggregate, and the aggregate will pass its state to the domain service as arguments for the query.

class Feedback {
    void downvote(SupplierOperatingQuery query) {
        boolean isOperating = query.isOperating(this->supplierId);
        ....
    }
}

But construction patterns are weird - when you are creating the object, the caller already knows the internal state, because it is providing it. The same pattern works, it just looks pointless

class Feedback {
    __constrict(SupplierId supplierId, SupplierOperatingQuery query ...) {
        boolean isOperating = query.isOperating(this->supplierId);
        ....
    }
}

We're following the rules by keeping all the domain logic in the domain objects, but we aren't really protecting the business invariant in any useful way by doing so (because all of the same information is available to the application component).

If transactional correctness requires one aggregate knowing about the current state of another aggregate, then your model is wrong.

In most cases, transactional correctness is not required. Businesses tend to have tolerance around latency and stale data. This is especially true of inconsistencies that are easy to detect and easy to remedy.

So the command is going to be run by the aggregate that changes state. To perform the not necessarily correct check, it needs a not necessarily the latest copy of the state of the other aggregate.

For commands on an existing aggregate, the usual pattern is to pass a Repository to the aggregate, and the aggregate will pass its state to the repository, which provides a query that returns an immutable state/projection of the other aggregate

class Feedback {
    void downvote(Repository<Supplier.State> query) {
        Supplier.State supplier = query.getById(this->supplierId);
        boolean isOperating = state.isOperating();
        ....
    }
}

But construction patterns are weird - when you are creating the object, the caller already knows the internal state, because it is providing it. The same pattern works, it just looks pointless

class Feedback {
    __construct(SupplierId supplierId, SupplierOperatingQuery query ...) {
        Supplier.State supplier = query.getById(this->supplierId);
        boolean isOperating = state.isOperating();
        ....
    }
}

We're following the rules by keeping all the domain logic in the domain objects, but we aren't really protecting the business invariant in any useful way by doing so (because all of the same information is available to the application component). For the creation pattern, it would be just as good to write

class Feedback {
    __construct(Supplier.State supplier, ...) {
        boolean isOperating = state.isOperating();
        ....
    }
}
1
source | link

If transactional correctness requires one aggregate knowing about the current state of another aggregate, then your model is wrong.

In most cases, transactional correctness is not required. Businesses tend to have tolerance around latency and stale data. This is especially true of inconsistencies that are easy to detect and easy to remedy.

So the command is going to be run by the aggregate that changes state. To perform the not necessarily correct check, it needs a not necessarily the latest copy of the state of the other aggregate.

For commands on an existing aggregate, the usual pattern is to pass a DomainService to the aggregate, and the aggregate will pass its state to the domain service as arguments for the query.

class Feedback {
    void downvote(SupplierOperatingQuery query) {
        boolean isOperating = query.isOperating(this->supplierId);
        ....
    }
}

But construction patterns are weird - when you are creating the object, the caller already knows the internal state, because it is providing it. The same pattern works, it just looks pointless

class Feedback {
    __constrict(SupplierId supplierId, SupplierOperatingQuery query ...) {
        boolean isOperating = query.isOperating(this->supplierId);
        ....
    }
}

We're following the rules by keeping all the domain logic in the domain objects, but we aren't really protecting the business invariant in any useful way by doing so (because all of the same information is available to the application component).