Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Can you articulate what this feels less complex? The author did a good job articulating the complexity with the trivial example.

One benefit I like in the author's example, vs a static utility method, is you don't need to concern yourself about the implementation when it comes to tests.

Let's consider your example. The CheckoutService needs to call applyDiscount. So how do we get a discount to be applied? Well, we need to look at the source code of the static function to see that the order needs a CouponCode of "SUMMER2024". We may also need to see how much the order is discounted by so we can assert on the correct total value in the tests (or we can simple assert the total is less than the total we started with). That means that anytime we update the CouponCode (e.g. "WINTER2024") then we have to update a bunch of tests.

Now let's consider the example's change. I see that the constructor takes some DiscountService interface. So now I can create a fake implementation that's used in the tests. I don't need to dig into implementation code to see how to trigger a discount. I can create that fake implementation in the test itself so I can provide exactly how much discount will be applied and the test can assert that the total is discounted by the amount specified in the test itself, now we can see it's definitely being applied! Or I can create a FiftyPercentDiscountFake for all other tests to use.

The example is trivial of course and you likely don't need such an abstraction for trivial services. After all, this is for example purposes. But as code becomes less trivial or many teams are repeating the same thing if you're at a large enough company, then this a tool in our toolbelt to use to manage the complexity.



Well in the real world you would have all the coupon codes, amounts, and any other special behavior driven by entries in a database. It would never be in code. So the code would either be checking the database on every call, or loading the current valid coupons into some kind of resident app memory (and keeping them up-to-date somehow), depending on the platform.

So I'm not going to think about how different coupon codes would change the code complexity until I see what a real-world implementation with database-driven coupon codes looks like.

Testing is a whole other animal. It could be that a DiscountService interface works best from a testing perspective. But within the scope of the post, a DiscountService interface with different implementations for Shipping and Retail Price certainly isn't less complex than the original code.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: