1,230 karma · joined December 9, 2011
Get in touch: hacker.news AT brunosutic.com
The only breaking thing was a huge (almost bloated) memory consumption. At that time lnav basically just kept everything in memory. Does anyone did that change?
Killer feature is multiple plans per customer.
What's your approach to 3DS and related race-conditions for subscriptions? In my experience 3DS is by far the biggest problem for subscription integrations - not the webhooks.
This used to be the case back in 2015, but not anymore. The financial compliance is more strict now. You have to charge taxes. EU enforced SCA / 3DS in 2019. All of these are hard to implement (correctly) on their own - almost impossible together.
Source: I run (paid) Ruby on Rails library for Stripe subscriptions integrations. I also do billing audits. Here's an example audit where I pay $30, get ~$2000 https://www.youtube.com/watch?v=YuXp7V4nanU
"Friendly Attributes" is not the "new way", not to be used "everywhere now", does not "apply to all scenarios".
If you like it, maybe you'll use it once in the next five years when the opportunity arises.
If you want to make it even shorter, you have a few options - it really just comes down to preference:
# Option 1. my personal favorite, follows structure of
# intervals and plans on a pricing page.
1.month => {red: 10, blue: 120},
1.year => {red: 120, blue: 300}
# Option 2. this is fine too
red: {1.month => 10, 1.year => 120},
blue: {1.month => 120, 1.year => 300}
# Option 3. possible and works, but hurts my brain, NOT recommended
10 => {red: 1.month},
120 => {red: 1.year, blue: 1.month},
300 => {blue: 1.year}
> there is always at least one attribute that serves as a "discriminator" between the billing plans, rightJust a note: if you try to create two plans with the same attributes, that would error because of ActiveRecord uniqueness validations (and DB constraints). No point in having multiple identical plans.
Just a small Ruby syntax correction for your example:
Billing::Plan.find_or_create_all_by_attrs!(
standard: {1.month => 10, 1.year => 100},
...
)How would you then call the objects that store costs and billing frequency? :)
Here's what Stripe uses:
- Product: "describes the goods or services". This is where you define a (plan) name and features.
- Price: defines the amount, currency, and (optional) billing interval. Since interval is optional, Prices can be used to define both recurring, and one-off purchases.
Technically, using Prices for recurring, and one-off payments is a brilliant idea. The problem is, no one refers to recurring payments as "prices". Everyone calls a "$50 per year" option a "plan".
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
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.Let's take this example from the article:
Billing::Plan.find_or_create_all_by_attrs!(
1.month => {standard: 10, pro: 50, enterprise: 100},
1.year => {standard: 100, pro: 500, enterprise: 1000}
)
This ensures six billing plans are created. That means 6 DB queries and 6 Stripe API queries, at a minimum.Nice work btw. The landing page is pretty and I like the pricing slider :)
For this purpose I recommend "LectroFan" devices. We have like 5 "LectroFan Evos" in our's and our kids' bedrooms. They just work, no apps, no upgrades, no LEDs blinking, and thank god, no screens. These devices are worth their amount in gold.
On the phone I recommend using iOS built-in white noise feature. We use it when travelling by car, and our kids sleep in their seats. When we turn the white noise on they stop talking and it quickly lulls them into sleep.
The lack of features (notably Wifi on our boards) and somewhat larger size are benefits for us.
You see, Stripe is very powerful, but also very complex. Coding a straightforward subscriptions implementation will take you a couple weeks at best.
That is without handling all those edge cases like: prevent starting a paid subscription without a billing card on file (yes, you read that right)!
The gem is ready, I'm currently working on getting the website up. If you're working with Rails and need a solution for subscriptions get in touch at hacker.news@railsbilling.com - I'd love to chat!
If you implement something, then add SCA/3DS "payment confirmations" later on, I think it's impossible to fix that.
Stripe has a "developer friendly" and "easy to use" reputation. But, since 2019 the EU regulation has stepped in and made things more complex with 2nd factor authentication for payments (3DS/SCA). This made payment integrations way more complex. Integrating Stripe subscriptions now easily takes 6 man-months (I'm being very optimistic here).
Also, there are some basic scenarios that are hard to get right:
- Creating a paid subscription and ensure a customer always has a card on file (this one is almost impossible). - Upgrading a free ($0) plan to a paid one. - Upgrading paid plans, eg $10 to $100/month and ensuring immediate payment. - Guarantee customer Tax location, keep the flow simple.
I made a video analyzing Stripe integration of a successful SaaS company (+$100M valuation). I first paid $30, then upgraded to their highest $2000/month plan - for free!
https://www.youtube.com/watch?v=YuXp7V4nanU
The gem I'm working on is intended to be used with Ruby on Rails apps. It covers all the above mentioned hard cases, and irons out many more Stripe API kinks. And yes, it handles the basic-but-impossible "ensure customer always has card on file if they start paid subscription".
After buying the gem you can hand-off the task to the junior developer (it's that simple). They follow the integration tutorial: follow the steps for Stripe dashboard config, do the local env config, done.
The product (Ruby gem itself) is ready. I'm now working on the web app, tutorials etc. If anyone wants an early, guided access, please email me - contact is in the profile.
I even made a vim plugin that highlights these "dangerous" characters: https://github.com/vim-utils/vim-troll-stopper
I've never been pranked with unicode characters, but I've had a situation at work where a consultant from Japan unintentionally used some "japanese space" characters in a translation file, and that broke our app. Since I have my vim plugin running all the time it didn't take me a lot to see what's going on.
I also don't have anti-bot implemented right now, but that's my next step. I mean, my app "has one job" and it's not doing it well because of anti-bot protection...
I got the idea before the Covid pandemic: at the time I was looking for a better senior developer job. I sent a couple dozen job applications with my resume website, and I only got a couple job interviews, and no offers. I gave up and stayed at my old job. A couple months later I was optimizing my website. I checked for broken links and the results were bad: from 12 links total, 4 were broken. That's more than 30% broken links - no wonder I couldn't find a new job!
Since then I realized broken links are a problem for pretty much every website out there. If you have a website, you likely have broken links too. And the existing solutions don't cut it. Most online broken link checkers are old, and have outdated interface. Advanced SEO tools (ahrefs, semrush etc) can do broken links checking, but are too complex and expensive for regular people.
Under the hood linkok.com crawls sites using Async Ruby, which has proven great for this type of work. I love how easy it is to work with (when compared to threads). It also made some advanced features easy, like request retries. Async is a somewhat underused in the Ruby community. If someone has more questions about it, I'd be glad to answer.
My goal for linkok.com is that it should be easy to use (think: blogger moms), and it should be accurate and powerful enough for enterprises. linkok.com is free forever for small sites (up to 100 internal pages) and charges a fee for bigger sites. It's also completely free for open source, educational and non-profit websites. This is not automated yet, reach out at bruno.sutic@linkok.com and I'll set you up.
You may find this interesting: I worked on this project for 3 years! By far the hardest part was billing - integrating with Stripe properly took me almost 1 year (Stripe is very hard). I also shaved a couple of yaks, highlights: implemented postgresql and redis high availability, I run things bare metal servers (Hetzner).
I'd love to hear your thoughts, feedback and ideas! Looking forward to your comments.
Too bad the article doesn't contain the source reference, but oh well. I hope it gets the word out about this new cool stuff in Ruby.
You probably implemented your own custom scheduler implementation, right?