Would you use Symfony for SaaS?

Over the past four weeks I have been working on the revised back end for CodeReviewVideos. The part that’s taken the longest has been working with payment / billing integration.

Over the past few years a steady stream of requests come in asking if it’s possible to pay with PayPal. Up until now I have had no streamlined way to accept PayPal, but with the new back end this should be possible. One thing though, it might not be there on day 1.

I’m not particularly shy about my reasons for not having any other payment option than Stripe. The biggy would be that Stripe is amazing to work with, and as a developer it’s by far and away the nicest payment integration I’ve ever dealt with.

But the primary reason I don’t have PayPal so far is that adding in PayPal – or any other payment provider – to the existing setup for CodeReviewVideos is really, really hard.

When I first came to launch the site, I had no idea how it would perform. Would there be 10 people wanting to join, 100, 1000… or none?

Aside from all that, I had a ton of other stuff to get right for the launch.

Rightly or wrongly, my first priority has always been to create new content. I think about my preferences as a visitor of other sites that provide online programming training videos, and I can forgive a heck of a lot if the content is valuable to me.

All of this is a roundabout way of me saying I pretty much ‘hardcoded’ Stripe as the only payment provider, and that made it super hard to extract Stripe and make the concept of payment more abstract.

I’ve since found out (as per the 4 weeks above) that I probably made the right choice.

If no one had subscribed, that would have been four weeks of totally lost effort – on top of the months I’d already put in.

But this got me to thinking further: why isn’t this a pre-solved problem? Surely I’m not the only one using Symfony in this way?

There’s a bunch of really fiddly bits to get right when working with payments. It’s got to be absolutely perfect, or people – rightfully – get mad, and / or lose a lot of confidence. Imagine if the first encounter you have with a site is the sign up process breaking for whatever reason – you’re not going to feel too confident about the rest of the site after that. At least, that’s how I feel.

What this all boils down to is that the whole process needs to be as rigorously tested as possible. But writing these tests is a total pain.

Normally when testing the “golden rule” is to avoid any real calls to external systems.

With payment though, this is a total catch 22.

If I don’t interact with e.g. Stripe during tests then I need to keep on top of any API changes they make at a microscopic level. If they change the way they send events, I need to update all my fake data, validate everything, and even then I’m really just “resetting” the problem until they next change something.

Now, in truth, Stripe are decent about this and they won’t force an API update on you – at least not right away. But still, it’s not what I wanted to do.

Instead, I went with tests that talk to Stripe. Even this isn’t perfect – some events are not easily faked. An example of this is when a customer’s payment fails. Stripe will retry this payment attempt a few times before sending the webhook to my configured endpoint with the invoice.payment_failed notification.

What this means is I had to fake that one particular event. All the others actually talk to Stripe.

Another downside to this is that when faking an event, the given id field will be very fake – e.g. evt_0000000000000 or similar.

Stripe suggest each event received via a webhook should be considered untrusted. The solution here is to take the received ID and then call Stripe saying hey, is this ID actually legit? Of course, evt_0000000000 is not legit, which means either hackery in my code, or avoid making the validation call.

Needless to say, getting through this process felt like an absolute grind. Getting the tests to a point where they don’t flake out when run via GitLab CI was amongst the trickiest parts.

Whilst in this grind phase I was having a bit of a back-and-forth chat with a fellow dev and the conversation touched on two interesting questions:

  1. How many other developers are using Symfony for SaaS, or SaaS-like services?
  2. Is Stripe / payment integration something that many other devs want or need tutorial content on?

I’d be really grateful if you could hit reply and let me know your thoughts on these two points.

I will share my own opinions on these two points next week.

I think that’s the hardest part done now. There’s a couple of steps that remain before I can make the big switch over, but it’s almost there.

Video Update

This week saw three new videos added to the site:

https://codereviewvideos.com/course/let-s-build-a-wallpaper-website-in-symfony-3/video/fixing-the-fixtures

Early in our project we created Doctrine Fixtures to setup our database with known data. We now need to keep our fixtures working with the latest changes.

https://codereviewvideos.com/course/let-s-build-a-wallpaper-website-in-symfony-3/video/untested-updates

Learn how to accept Updates to existing uploaded Wallpaper image files in this first of three parts covering Update and Delete in EasyAdminBundle.

https://codereviewvideos.com/course/let-s-build-a-wallpaper-website-in-symfony-3/video/untested-updates-part-two-now-we-can-actually-update

There’s a bunch of little gotchas that have caught us out along the way to a working Update process. By the end of this video we should have fixed them all.

We’re nearly at the end of the first phase of the Wallpaper Website tutorial. I’ve had a few video requests come in whilst recording this series so we will move on to addressing them, along with a couple of other series that are constantly requested, before moving on to phase two.

Thanks for reading, have a great weekend, and happy coding.

Chris

Shares

Published by

Code Review

Code Review

CodeReviewVideos is a video training site helping software developers learn Symfony faster and easier.

Leave a Reply

Your email address will not be published. Required fields are marked *