In December 2018, Expo asked me to build subscription payments functionality using Stripe to support users of https://playcastle.io. I decided to implement a micro-service to focus on being predictable, reliable, and sustainable. I'm using Render for both server hosting and Postgres hosting. You can try Render with this invite.
I am excited to share the first iteration of the work! Let's dig in.
The first version of this POC does not need every feature you can imagine in a payments service. That being said, certain requirements must be fulfilled.
Can a user update an account where the account can receive payments?
Can a user update an account where the account can make payments?
Can we keep track of account balances?
Can we withdraw money on behalf of the user?
Can we create a subscription contract between a payer and recipient?
Can we ensure the subscriptions are processed at the exact same time each month?
Can we ensure that each payer receives one and only one credit card bill during each billing cycle?
Can we ensure that any client with an API key can make a subscription network call?
Can you ensure that each payments account references one and only one user account?
Any employee of Expo should be able to manage payments if asked to.
There should exist an internal tool that is a living example of how the implementation works.
There should be documentation.
There should exist an executable script that tests the entire functionality of the service and cleans up after itself.
Development for the service should be extremely easy and require minimal dependencies.
There should be a production database and test database so the team can experiment without harming customers.
All of the requirements were fulfilled by a few tasks.
I knew that developers wouldn't even try the code unless the steps are easy. The most junior employee should be able to use the tool. Therefore:
There should be minimal dependencies for the first time setup.
There should be minimal steps to run the code.
Even with this pre-emptive planning. Mistakes still happen, so this belief requires vigilance and you must understand you are not entitled to anyones attention.
I prefer documentation that is easy to copy and paste into a codebase. People want code to just work with minimal attention cost. Here is an example:
Focus on the language that your team is using. Do not write examples that require understanding of a rendering library.
Do not assume that anyone on the team knows any complex language features.
Do not assume that anyone is comfortable making an
npm install inside of the project they are working in.
All of the major endpoints are documented with this philosophy. Here is an overview:
POST /payers # list all accounts that can pay
POST /payers/create # create a new payer
POST /recipients # list all accounts that are ready for subs
POST /recipients/create # create a new recipient
POST /recipients/subscribe # create/update a subscription between accts
POST /recipients/unsubscribe # cancel a subscription
It is not enough for your team if the documentation fully covers the usage of your service API. Engineers should produce a living example (kitchen sink?). A living example teaches collaborators about the whole surface area of functionality. We do this because everyone should be able to help when needed.
Here is the progress on our internal tool:
Here are some more advantages to having an internal tool:
You know what your teammates need. If your teammate makes a request, implement the solution for everyone.
Each collaborator only needs to see what they need to see. Developers can dig into the source code to see how the implementation really works and everyone else can discover features through the GUI.
The team at Render was kind enough to make themselves readily available. Their team is easy to contact and discuss any concern with. They have a great sense of what developers need when it comes to server and database deployments.
At Expo, our products and requirements are always evolving. There are many edge cases that need to be explored, such as:
Will payers want to make subscription payments to more than 20 recipients? If so will Stripe lift the limit for the number of plans in a subscription? How will we work around this if they won't?
Should this service bill payers on the 1st of the month? Or should this service bill payers on the 15th?
How does payments fit into the vision for the product? Should subscriptions only occur on the web? Should they also occur in the https://playcastle.io client? What about mobile?
Should any recipient of payments be able to withdraw money at their leisure? What are all of the requirements we should be aware of?
Should we make payers pay for the tax that the recipient would have had to pay?
Excited to work through these issues with the team! 🚀