Open patricekrakow opened 1 year ago
The problem when defining a customer-article by only referencing a seller-product is that you cannot update the seller-product without creating an ambiguity on the customer-article; when using this customer-article, you will not be able to know if it refers to the seller-product before or after the update.
Let's illustrate this problem with, as an example, a seller-product with XYZ
as id
and 1000
as diameter
, and create a customer-article with ABC
as id
by only referencing it. We will exclude the other properties for the conciseness of the example:
READ seller-product --> | | XYZ | 1000
CREATE customer-article <-- | ABC | XYZ
READ customer-article --> | ABC | XYZ | 1000
If afterwards the diameter
of the seller-product XYZ
is modified from 1000
to, let's say, 1250
, it will not be possible to use the customer-article ABC
as we will not know if its diameter is 1000
or 1250
:
READ seller-product --> | | XYZ | 1250 (UPDATE)
READ customer-article --> | ABC | XYZ | Ambiguity
One solution to this problem would be to forbid any change of seller-products, constraining them to be immutable. However, this solution does not fit normal business practices.
Another solution is to decouple the customer-article from the seller-product from the customer point of view. The values of the properties of the customer-article will be fixed at the moment of its creation. In order to emphasize that, the customer-article will not explicitly refer to a seller-product, but all properties will be explicitly provided. Let's illustrate that with the same example:
READ seller-product --> | | XYZ | 1000
CREATE customer-article <-- | ABC | ___ | 1000
READ customer-article --> | ABC | ___ | 1000
This time, if there is an update of the seller-product after the creation of a customer-article (using it), it will not affect the customer-article:
READ seller-product --> | | XYZ | 1250 (UPDATE)
READ customer-article --> | ABC | ___ | 1000
We have decoupled the customer-article from the seller-product from the customer point of view, but, of course, on the seller side you still have a "mapping" between the customer-article, which is ordered, and one (or multiple) seller-product(s), which are produced. If the modification on seller side does not allow anymore the seller to provide the customer-article, it must become Inactive
. It is important that the customer-article still exists, it cannot be deleted, as it is still used in past orders!
READ seller-product --> | | XYZ | 1250 (UPDATE)
READ customer-article --> | ABC | ___ | 1000 | status = Inactive
In the examples above, it would not make sense to modify the customer-article after an update of the seller-product as it would again create an ambiguity on the customer-article. So, we should remove the API endpoints PUT /customer-articles/{customerArticleId}
and PATCH /customer-articles/{customerArticleId}
. But, again, it's not that simple because of normal business practices that allow such modifications when they are backward compatibles.
A good example of a backward compatible change is when the seller is adding a possible value to a property. This backward compatible change of a seller-product can be safely transferred to customer-articles. It is up to the seller to decide what change are backward compatibles, giving the appropriate response for the API endpoints PUT /customer-articles/{customerArticleId}
and PATCH /customer-articles/{customerArticleId}
.
Let's illustrate that:
READ seller-product --> | | XYZ | 1000, 1250
CREATE customer-article <-- | ABC | ___ | 1000, 1250
READ customer-article --> | ABC | ___ | 1000, 1250
READ seller-product --> | | XYZ | 1000, 1250, 1500 (UPDATE)
READ customer-article --> | ABC | ___ | 1000, 1250
UPDATE customer-article <-- | ABC | ___ | 1000, 1250, 1500
READ customer-article --> | ABC | ___ | 1000, 1250, 1500
On the other hand, removing a diameter
is probably better considered as an incompatible change that should not be transferred:
READ seller-product --> | | XYZ | 1000, 1250, 1500
CREATE customer-article <-- | ABC | ___ | 1000, 1250, 1500
READ customer-article --> | ABC | ___ | 1000, 1250, 1500
READ seller-product --> | | XYZ | 1000, 1250 (UPDATE)
READ customer-article --> | ABC | ___ | 1000, 1250, 1500
UPDATE customer-article <-- | ABC | ___ | 1000, 1250 --> Error!
Unfortunately, there are more subtle incompatible change like adding a possible value to a property when it was previously a single-value property. Let's illustrate that:
READ seller-product --> | | XYZ | 1000
CREATE customer-article <-- | ABC | ___ | 1000
READ customer-article --> | ABC | ___ | 1000
READ seller-product --> | | XYZ | 1000, 1250 (UPDATE)
READ customer-article --> | ABC | ___ | 1000
UPDATE customer-article <-- | ABC | ___ | 1000, 1250 --> Error!
Why should the seller return a error? The fact that the diameter
had one single value 1000
meant that when the customer-articles ABC
was used, for instance within an order, its id
was sufficient to use it. On the other hand, when you are using a customer-articles with one or multiple multi-value properties within an order, you MUST always specify the value you want out of the possible values. Thus, if you allow this kinf of update, there will be an ambiguity on the customer-article used in orders.
QUESTION 1: Since we allow seller-product to be updated by the seller, do we allow customers to order directly seller-product (without creating customer-article first)?
Indeed, if we do allow that, we will end up with an ambiguity on the seller-product property values in orders. Let's illustrate that with an example:
READ seller-product --> | XYZ | 1000
CREATE order <-- | 1 | XYZ |
READ seller-product --> | | XYZ | 1250 (UPDATE)
CREATE order <-- | 2 | XYZ |
READ order --> | 1 | XYZ |
READ seller-product --> | | XYZ | 1250
For the order 1
the seller-product XYZ
has a diameter
of 1000
, but for the order 2
the seller-product XYZ
has a diameter
of 1250
. However, when we will later read the order 2
and lookup for the diameter
of the seller-product XYZ
, the answer will be 1250
, as the update of the seller-product XYZ
has erased the previous diameter
of 1000
!
We could solve this problem by making the creation of a customer-article has a mandatory step, but we can notice that this problem does not occur when we have an update on a multi-value property. Let's illustrate that with an example:
READ seller-product --> | XYZ | 1000, 1250
CREATE order <-- | 1 | XYZ | 1000
READ seller-product --> | | XYZ | 1000, 1250, 1500 (UPDATE)
CREATE order <-- | 2 | XYZ | 1500
READ order --> | 1 | XYZ | 1500
READ seller-product --> | | XYZ | 1000, 1250, 1500
Indeed, when you have a multi-value property, you MUST specify the value you want out of the possible values and therefore you keep the 'memory' of the right value!
QUESTION 2: If we allow customers to order directly seller-product, do we oblige them to specify every properties of the seller-product, even the single-value one?
REMARK. For the customer-article, we could have the same reasoning, but we can also reject incompatible changes (see above). If we would oblige customers to specify every properties of the customer-article when creating an order, it would make the concept of customer-article obsolete and/or ambiguous. Let's illustrate that with an example:
READ seller-product --> | | | XYZ | 1000
CREATE customer-article <-- | | ABC | ___ | 1000
CREATE order <-- | 1 | ABC |
READ order --> | 1 | ABC
READ customer-article --> | | ABC | ___ | 1000
READ seller-product --> | | | XYZ | 1000, 1250 (UPDATE)
READ customer-article --> | | ABC | ___ | 1000
CREATE order <-- | 2 | ABC |
READ order --> | 2 | ABC
READ customer-article --> | | ABC | ___ | 1000
READ order --> | 1 | ABC
READ customer-article --> | | ABC | ___ | 1000
UPDATE customer-article <-- | | ABC | ___ | 1000, 1250 --> Error!
CREATE customer-article <-- | | DEF | ___ | 1250
CREATE order <-- | 3 | DEF |
READ order --> | 3 | DEF
READ customer-article --> | | DEF | ___ | 1250
READ order --> | 2 | ABC
READ customer-article --> | | ABC | ___ | 1000
READ order --> | 1 | ABC
READ customer-article --> | | ABC | ___ | 1000
QUESTION 3: After all these explanations, and I am still not sure that I have covered all the corners of the subject, I am wondering if we should not make the radical decision to enforce the immutability of both seller-product and customer-article?
If we go for this unlinking, we still need to explore all its consequences of this, such as for our idea to remove the
DELETE /customer-articles/{customerArticleId}
API endpoint, only allowing the customer to inactivate his customer-products (via a PUT or a PATCH), and many more...