Hacker News new | past | comments | ask | show | jobs | submit login
Separate Your Billing from Entitlements (arnon.dk)
177 points by nalgeon on May 11, 2022 | hide | past | favorite | 33 comments



While I agree with the overall idea here, something really odd struck me and that was that the author seems to assume that this would inevitably be some sort of microservice.

For so many companies, small to large, a microservice here would not just be an aditional point of failure as the article points out, but would totally over complexify the problem, when for most companies simply storing this data in their regular database, data store, whatever, and calling a relevant method to determine eligibility would suffice, and would require a hell of a lot less code.

customer.can_use_widgets? instead of customer.is_on_gold_plan?

customer.storage_allowance instead of customer.on_plan?("honkin' storage")

etc.

If you find that this won't scale at a later date then by all means turn it into a microservice, or add cacheing or whatever, but for most people that will never happen and time spent now solving the assumed scaling problems will be wasted.


Where does the author imply microservices? This seems more like a highlevel structure that could be implemented however you want.


It's very clearly implied in the "A modern entitlement/billing architecture" section:

> The requests should go to the entitlement system

> You may be thinking “isn’t this causing a single point of failure?” – and yeah, you’re right.

> In case the entitlement system (or a downstream system) fails, you should have some sane defaults.


Talking about an entitlement "service", not a term I see used for "another part of the same code base", talking about it being a new single point of failure, the seeming mapping out of a JSON API.


Service classes are a common pattern used in monolithic codebases to isolate related logic from the rest of the system. Everything the author described in the article can absolutely be built in a monolithic codebase sharing the same database, or separate databases if you prefer.


> Service classes are a common pattern used in monolithic codebases to isolate related logic from the rest of the system.

Yes, we have them in our code base. I'm pretty much 100% sure the author wasn't referring to these though, the way the author refers to "the service" is not how I've seen people refer to service classes.

> Everything the author described in the article can absolutely be built in a monolithic codebase sharing the same database, or separate databases if you prefer.

Yes, that, and the fact that the author seemed to assume that a microservice would be involved was what made me comment.


Any telco has been separating out call data records, billing rules and billing for years.

You should also differentiate between selling a product/plan and fulfilling it.

What you sell and what you fulfill are two different things, one is a price, the other is a cost, one is a product/PLU, the other is a SKU.

So what you're selling is a plan, which is a subscription, which has a price and other billing related stuff (periods, expiries, seats etc). The outcome of that is revenue. There may be wrinkles like discounts and coupons and free periods and etc, but that's all on your sales and billing side.

What you supply is features/services/logins etc. They have costs/expenses.

There needs to be a map between the PLU(s) and the SKU(s).


I recently worked on a payment integration which was effectively the entitlement layer as well, and I knew it was bad design at the time but hadn’t worked out a solution. It was a situation where we needed to move quickly and if it mattered later we could totally overhaul all of it, but it really rubbed me the wrong way knowing that it definitely wasn’t a good solution.

This covers everything I was unsure about, plus a lot I hadn’t considered. Thanks very much – this will save a lot of pain the next time I work on something similar.


This looks very analogous to enforcing a clear separation of authorization from authentication. So much so that I would assume that leveraging a library meant for authorization like oso[0] might be one of the most straightforward ways of implementing an entitlement system as described in the article.

[0]: https://www.osohq.com


Definitely useful to have queries based on feature existence with overlays (also for pricing! Discount coupons, price overrides... all very useful). All the advice about feature flags and progressive enhancement for the web, totally applicable to billing checks.

One thing I like though: try to make your feature matrix as dirt simple as possible. If you can find the pricing that just aligns with value, you don't have to play "which plans get this feature" _every single time_ cuz you know the pricing is capturing the value.


As a solo dev working on my SaaS, I can second this. My time and attention are scarce, so I ditched my earlier attempts to also have a monthly paying plan, for example. I also don't do coupons and sales. It was tempting to offer these things, but it wasn't grounded in reality. Choosing for the most dirt simple setup saves me a lot of time and it keeps the complexity at bay.


As another solo dev running a SaaS (7 years), I mostly agree. I stopped doing sales and coupons, it's a lot of effort for little practical gain (in a B2B SaaS you really care about the long-term, not hooking customers based on quick promos and coupons).

But complexity will catch up with you eventually. There is just no way around this. I read the article and I agree with most things there — my system is somewhat simpler, but I do have "features" and feature overlays, which let me override entitlements in specific cases. This gets a lot of use. And right now I'm working on plan overlays, so that I can offer custom plans when needed — and believe me, it's not because I have too much time on my hands, it's because I started to really need them.

Obviously don't do all this when you start.


I am a fan of "simple additional wrinkle to consider when setting up a system" style articles. For almost no cost, you get benefits that won't be apparent until later.


I wouldn't say no cost, but the benefits far outweigh the cost of having this kind of setup.

This is specifically true for "enterprise" B2B SaaS - not so much in the consumer space though.


Good advice. But instead of having an entitlements _system_ and API calls passing through multiple different services returning lists of features a customer is entitled to, you can follow basic OOP principles and write

  customer.is_entitled_to("feature")
to abstract the logic away to the same effect.


This is very basic stuff for people developing accounting or ERP systems. Sometimes it’s good to have some enterprise development experience ;)


Solid advice..

Somehow reminds me of a client whose new developers thought it was a good idea to fork the code base for each customer, instead of the feature flags it had..

Spent quite some time merging everything back a few years later


In general it's a good idea to separate internal billing/invoicing/plan management from your payment provider. Not always easy though as providers often have slightly different abstractions.


Some of us have no choice in the matter. For example, there is no payment provider that can correctly handle my invoicing requirements (EU, Poland).


Same, just wrote my own billing system that supports Stripe and a few other payment methods (e.g. bank transfer), still very painful to get it right though.


Curious: Are there any OSS entitlement management systems or libraries out there?


Unleash is an amazing open source feature management tool:

https://www.getunleash.io/

It would probably take some effort to hook it up to whatever billing platform you use, but it would make it easy to turn certain features on/off based on billing. Instead of checking if a customer has a specific plan, you instead have Unleash handle the features that are on/off and then check for those flags in the code.


Source code at https://github.com/Unleash/unleash

Setup instructions and SDKs for a number of languages in the README.


Thanks for the link - am I getting it right that this is a Feature Flag system akin https://www.growthbook.io/ and PostHog Flags (also OSS)? At least I got this impression from their landing page.


It looks similar, but Unleash has a lot of really awesome features that let you configure rules for when flags are enabled/disabled. Stuff like turning them on for specific domains or customer or any other metadata you can feed into it.


I'm curious why one would want a "system" or a "library"?

I run a SaaS which has a feature system. Every plan has a set of features. There are additionally feature overrides for users. Checking if a feature is available to a user is a set membership query.

With a couple more lines of code I also generate my entire pricing (plan comparison) page, so that each plan shows all available features.

Not sure where a library would provide any value, there is barely any code for this (I mean, it's Clojure, so it's very succinct and expressive, but still).


I work for developer...just found out we're launching a platform soon, for saas devs ansd start-ups to run their business - it includes payment integration. [email protected]


This article contains really good advice.


For reference, you can see this kind of thing in action in any large SaaS such as Microsoft 356. There are even separate commands in the CLI.


Would it be more straightforward to think about this in terms of standard e-commerce terms? Product, product variation.. ?


The focus of this article is more on SaaS-style products, where the delivery of features or 'product variations' is more continuous.


Not sure if "entitlement" here has a well recognized meaning. But I think this is all about revenue recognition. patio11 gave a good overview here https://bam.kalzumeus.com/archive/accounting-for-saas-and-sw...


Revenue recognition is orthogonal to this post. The main point is that if you're selling things for money you should model those things separately from how money is used to acquire them.

Case 1 (which the article suggests we shouldn't do): Bob tries to download his contacts, we check our database and find that he's subscribed at the gold payment tier and thus is allowed to do so, and so we provide a download option.

Case 2 (proposed alternative): Bob tries to download his contacts, we check our database and find he has that privilege for the next 6 months (which we recorded previously when he subscribed at the gold tier), and so we provide that download option.

The 2nd case is probably a bit worse if you never change your payment options, but it makes changing them trivial and doesn't introduce much burden.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: