In this moment i'm wondering -- why write applyDiscount(customer, order_id, discount) at all? Just use customer.findOrder(order_id).applyDiscount(discount); That's really clear.
If applyDiscount is part of an interface boundary -- for example because Customer or Order have methods that shouldn't be accessible to the caller of applyDiscount, or because Customer or Order themselves shouldn't be accessible -- then maybe that's a different story. But here the caller already has access to a customer. This applyDiscount is a "convenience" method. (quotes because it probably adds more complexity than it does convenience)
I also want to point out that APOSD doesn't declare pass-through methods bad in general -- it says the real problem is when adjacent layers have similar abstractions, and thus we haven't separated responsibilities clearly ("different layer, different abstraction").
paul
--
You received this message because you are subscribed to the Google Groups "software-design-book" group.
To unsubscribe from this group and stop receiving emails from it, send an email to software-design-...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/software-design-book/3bca655b-4623-49be-a297-7fba51b1f204n%40googlegroups.com.
I have the sense that "Tell, Don't Ask" is expressing a basic principle of modularity --- responsibility --- that we shouldn't be mucking about inside an object, doing its work ourselves. The work that requires the object's context should be done by the object; that's the purpose of the object. It's about where code should live, and what information should traverse the boundaries of objects.
Thanks for bringing this up. I feel like i'm learning!
paul
To view this discussion visit https://groups.google.com/d/msgid/software-design-book/efcd2178-c095-4020-b60d-c0e07e79e5afn%40googlegroups.com.
Shower thoughts:
Thinking relationally, we might structure Customer, Order, and
Discount differently in order to more clearly separate their
responsibilities. Rather than:
customer.findOrder(order_id).applyDiscount(discount);
We might do this:
discount.applyTo(orders.find(customer_id, order_id));
This suggests a structure where:
- Discount depends on Order; it contains the knowledge of how to
modify an Order to apply a discount. Order just holds information
like the customer, date, and line items. Order doesn't depend on
Discount.
- Order depends lightly on Customer; it has a customer id field.
Customer doesn't depend on Order; it just holds information like
the name and address.
- Different orders with different customer ids may have the same
order id.
- Our main entrypoint into the data is the 'orders' object rather
than the 'customer' object. Since our goal is to apply a discount
to an order, this seems good.
Obviously this would need to be borne out in a full design. I
think that the way we design objects to relate to each other can
have a big impact on their interfaces and thus on how we interact
with them.
paul
To view this discussion visit https://groups.google.com/d/msgid/software-design-book/efcd2178-c095-4020-b60d-c0e07e79e5afn%40googlegroups.com.