Hacker News new | ask | show | jobs
by kburman 220 days ago
This is a perfect example of something that looks good in a demo but fails in a real product. Business logic and 'packages' are never this clean or simple.

Putting this kind of type-based 'magic' in the code is a bad decision that will bite you very soon. It optimizes for being 'cute' rather than being clear and maintainable, and that's a trade-off that almost never pays off.

2 comments

Hi, I'm the author of the article and the software library. I confirm I actually do use the examples from the article in my code.

Here's the example that runs in hundreds of integration tests:

  expect(billing_pricing_plans).to eq billing_plans(
    1.month => [:free, :premium, :pro, :enterprise],
    1.year => [:free, :premium, :pro, :enterprise]
  )
It asserts what plans the customers see on the pricing page.
There's a massive gap between that pattern and the real-world complexity of billing. It's too much to cover in a comment, but this link explains the actual nightmare - https://www.getlago.com/blog/why-billing-systems-are-a-night...
That link describes billing problems of a neobank... I mean, yes, there's a big gap between my test helpers and financial institution's problems - to the point it's not related at all.

But, in principle I agree billing, even the simple SaaS stuff, is much harder than most people expect it to be in 2025. My product (linked in the original article) is based completely on Stripe Billing - and it is still very hard to avoid all the footguns.

For people wondering, I even have an example how wrong it can go: I "audited" a successful SaaS I know uses custom Stripe billing. I paid $30 for a starter plan, but was able to "upgrade" to $2k plain for free. Here's the full video: https://www.youtube.com/watch?v=YuXp7V4nanU

We can't really tell that without knowing where the code is used, no? It's not hard to imagine a test that checks the following:

   bill = FactoryBot.create(:bill, products: [])
   expect(bill.currency).to eq("USD")
It doesn't cover all possibilities of all currencies, but it doesn't need to. It covers the one case it needs to test.
They do say they use this in their real production code.
Just because it's in their production code doesn't mean it's not a ticking time bomb.
You are still talking about the three line find_or_create in this article, right?