4 ms·
The examples are interesting in that why is it the Shopping carts responsibility to report the results of the discountService?? If the metrics have to be surfac
by dm03514 8y ago
The examples are interesting in that why is it the Shopping carts responsibility to report the results of the discountService?? If the metrics have to be surfaced, someone, somewhere needs to surface them: and I've been finding it achieves the cleanliness and doesn't break encapsulation when the service (discountService) is responsible for its own hooks, or monitoring adapter. Like mlthoughts2018 i've been finding success using decorators for this because it keeps the domain logic clean of metric/monitoring code:
(shameless plug i recently wrote about how decorators can be used to keep the domain metric/plumbing free)
https://medium.com/dm03514-tech-blog/designpatterns-considering-decorators-b4968a8006e8 https://medium.com/dm03514-tech-blog/designpatterns-consider...
(also just disclaimer: Team's i've been on have had lots of success using the approach outlined in the article, injecting a metrics/instrumentation object, it cleans up the domain logic, is easy to provide a stub implementation during tests, and abstracts the from metric implementations.
------
A decorator version might compose the production code by wrapping the domain logic in metric adapters:
metrics = InstantiateMetricsClient()
ObservableShoppingCart(
ShoppingCart(
ObservableDiscountService(
DiscountService(
),
metrics=metrics,
)
)
metrics=metrics,
)
----
Another option that I've seen be used successfully is to completely decouple domain events and the surfacing of domain events by having the domain generically emit events, and the logging/metrics subscribe and surface those however it decides.
----
I feel like for normal logging statements and metrics it only borders on being an issue, but when metrics include many timing wrappers, or when tracing (which involves much more reporting) is involved explicit adapters help to really keep things clean.