Talks

When Making Money Becomes a Headache Dealing with Payments

When Making Money Becomes a Headache Dealing with Payments

by Sebastian Sogamoso

In the talk "When Making Money Becomes a Headache," delivered by Sebastian Sogamoso at Rails Pacific 2016, the speaker explores the various challenges and pitfalls associated with managing payments within applications. He emphasizes the importance of establishing and maintaining trust with users in order to ensure a positive user experience.\n\nKey points discussed include: \n- Trust in Payments: Trust is critical when dealing with payments, and any errors can severely diminish this trust. The talk highlights how bugs in payment processing can lead to users abandoning the application. \n- Payment Gateway Pitfalls: It’s a common misconception that the response status codes from payment gateways always correlate with successful transactions. Sogamoso illustrates that many payment operations take significant time to settle, and often the real outcome is communicated via webhooks after the initial status is returned. \n- Idempotency Issues: Ensuring idempotency in payment operations prevents users from being charged multiple times for the same transaction. Sogamoso showcases how to structure code to avoid such issues. \n- Tracking Payment History: Maintaining a comprehensive payment event history aids in accountability and allows for effective resolution of user queries about their transactions. This can be addressed through event sourcing or the use of libraries like PaperTrail. \n- User Experience Enhancements: The speaker outlines five strategies to improve user experience regarding payments: \n - Implement asynchronous transactions to avoid user waiting times. \n - Provide visibility of payment statuses to users to build trust. \n - Allow users to manage and delete their payment information securely. \n - Prepare for seamless deployment of significant changes. \n - Establish robust monitoring and alert systems for dealing with errors promptly. \n\nSogamoso concludes with the necessity of accepting errors as part of software development. He stresses the importance of having strategies in place for communication, proactive user engagement, and post-mortem analysis of bugs to foster continued user trust. Ultimately, the talk serves as a valuable resource for developers to navigate the complexities of payment systems effectively and improve user satisfaction in their applications.

00:00:15.500 Joining a little late, I have a lot of slides, so I'll try to go really fast through them. I promise I'll do my best. So, hello!
00:00:26.960 That's going to be a tough act to follow, but I'm going to try.
00:00:34.880 I ordered a MacBook selfie stick today. It didn't get here on time for the talk, but I'm sure this will be one more experiment.
00:00:42.780 My God, my selfie stick had to use his finger!
00:00:48.329 I hope this is going to be interesting as we dive into it.
00:01:01.379 Now, let's get into the talk. The name of this talk is "When Making Money Becomes a Headache: Dealing with Payments." My name is Sebastian Sogamoso, and you can find me on Twitter as @saratoga. I work at Ride, which is a company that built the best app for carpooling. You should check it out at ride.com.
00:01:19.610 I also organize a Ruby conference in Colombia called Rails Live, and you should join us there. It's going to be in Medellín, which is a pretty cool city. We are currently receiving proposals, so check out the CFP to submit.
00:01:34.799 Okay, now let's dive into the talk. This talk is going to be about trust. I'm going to tell you why it's crucial to have trust from your colleagues, from your company, and, more importantly, from your users. You must gain your users' trust. How do you do that? You can achieve this in two ways: first, by keeping information safe, and second, by keeping your ad-free gift box ready to show.
00:02:21.569 In this talk, we're going to focus on the latter. This is how your users' trust looks like, and if you have a bug appear, trust diminishes. The loss of trust is significant. For example, at Ride, if we experience a bug in our chat service or location service, trust is heavily impacted.
00:02:49.260 However, if we have a bug in a non-critical feature, like traffic updates or reminders, trust will suffer, but it won't be as bad. On the other hand, if we have bugs in the payment process, user trust can drop to almost zero. This is dangerous because users can easily stop using your app and lose their trust.
00:03:35.220 To prevent this from happening, I want to discuss some common pitfalls I've found when working with payments. I've personally dealt with these issues or seen others struggle with them.
00:03:41.069 The first pitfall is relying too much on payment gateways. Many people think that when you make a request to a payment gateway, the status code of the response tells you whether the transaction was successful. This is not true in many cases.
00:04:11.849 I will show code during this talk, but I'll be using over-simplified examples to make my point, so bear with me. Let's say we have a transfer class that creates a transfer in a payment gateway. This class also checks the status code of the response to determine if the transfer was successful.
00:04:32.650 When using this class to create a transfer, we might accidentally introduce bugs. This happens because if we trust that the status code indicates success, we might be surprised later. Some operations, like transfers, take time to settle, which can be up to several days.
00:05:39.279 When you make a request to the payment gateway to create a transfer and receive a 200 OK status code, you might think that the transaction was successful. However, many payment gateways only notify you later if the transaction was actually successful.
00:06:00.460 They typically do this via callbacks, known as webhooks. They will inform you of the transaction result and keep sending them until you acknowledge receipt of the message or they hit their retry limit. This is a common struggle I've noticed: not checking for the actual transaction status via webhooks.
00:06:23.649 Another important aspect when exposing an endpoint to a third-party service, like a payment gateway, is security. When exposing such an endpoint, it’s best to add authentication. However, some payment gateways do not require that.
00:06:58.280 One alternative is to retrieve the event ID from the payment gateway's payload and then fetch the relevant data based on that event ID, rather than processing it immediately.
00:07:03.710 Now I want to talk about another common issue, which is ensuring operations are idempotent. Failing to address this can be a significant problem when dealing with payment transactions.
00:07:45.380 Let’s take a look at some code to understand this better. At the top, there's a method that charges for an item every time it's called. At the bottom, there’s a method that charges the invoice only if it hasn't been charged before.
00:08:31.490 This might seem small, but there are companies that have dealt with bugs caused by overcharging users. Overcharging is terrible. It can easily happen, and it’s something we need to be vigilant about.
00:09:01.640 Another common pitfall is tracking payment history. This is crucial for accountability and for handling support requests. It’s essential to be able to determine how a record reached its current state.
00:09:16.700 It can be challenging to determine which actions led to a particular state change, especially if the code responsible for that change is no longer available. A good way to handle this is to record events every time there’s a change in state.
00:10:23.600 Once you start recording events for state changes, be strict about never modifying those events. Doing so undermines the purpose of logging them. You can achieve this with tools like the gem PaperTrail that helps manage recording events.
00:10:51.230 If the tool does not meet your specific needs, you could create a custom solution, potentially using an event sourcing approach. For instance, you could have a Charge class with many events that detail their type and relevant data.
00:11:06.590 When you initiate a charge, you send it to the payment gateway and update the charge record based on the response. This way, if a user complains about payment issues, you can investigate the relevant events related to that charge.
00:11:30.950 We just covered three critical pitfalls when dealing with payments: trusting payment gateways, understanding payment history, and ensuring operations are idempotent. While this might seem dull, effective handling of these tasks is crucial.
00:12:05.840 I know that Godfrey, a Rails core team member, will break the news about a new module called Action Payments, which sounds boring. It should be called Horrible Payments.
00:12:29.890 Now that we have a possible solution to some of our issues, let's get serious again. We want to maintain our users' trust. Payments play a huge role in user experience. If you’re focused on backend development, you might think your work doesn’t impact user experience. However, that’s not true, especially concerning payments.
00:13:04.320 Here are five ways I think you can provide a good user experience regarding payments: using asynchronous transactions, giving users visibility into payment statuses, allowing users to delete their payment information at any time, deploying large changes seamlessly, and efficiently addressing bugs, which we’ll discuss last.
00:13:56.960 To illustrate my first point on asynchronous transactions, let’s simplify a scenario. Imagine a charge controller that interacts with a payment gateway to create charges. This seems simple; the user initiates a request, which is processed, and a response is returned.
00:14:29.840 In reality, what happens is much more complex. Requests are sent to a payment processor that handles the heavy lifting and checks for the validity of the card and availability of funds. The payment processor communicates with multiple entities, including banks.
00:15:35.940 This process can leave the user waiting too long, leading to a poor experience. To fix this, consider implementing asynchronous processes. For example, your controller should schedule background jobs that handle payment processing. This allows you to provide a better user experience and enables easier retry mechanisms for failed transactions.
00:16:57.979 For the second point regarding payment status visibility, it's crucial to allow users to see their payment history. Users frequently inquire about charges on their statements, so providing a dedicated section can help address their concerns.
00:17:43.840 The more transparent you are regarding payment history, the more trust you will earn from users. The third point is allowing users control over their payment information. It’s important not to trap users into payment systems that don’t allow them to withdraw their consent.
00:18:54.220 Empowering users to delete their payment information is crucial. However, do consider that if users can delete their payment data, ensure they settle any outstanding transactions first.
00:19:35.940 When suggesting users delete their payment methods, check for any pending transactions first. For instance, if a user has pending trips, charge them before deleting their payment method.
00:21:02.220 Moving on to the fourth point: how to prepare for significant changes without negatively impacting users. Discussing these changes with your team is crucial.
00:21:46.230 Document these changes comprehensively by explaining the intention behind the modification and consider how it will impact other systems. One effective method we use is RFCs (Request for Comments), an open document where team members can provide feedback.
00:22:51.700 Additionally, you should work to decouple your code; ensure the billing logic isn't intertwined with payment gateway functions. This allows for more flexible adaptations in the future.
00:23:20.440 You can also simulate billing in non-production settings to test how changes might impact users. This can catch potential issues before they reach real transactions. Having a simulation payment gateway can allow for testing of payment flows without real transactions.
00:24:52.690 Last but not least, let’s discuss how to deal with bugs. Accept that bugs are an inevitable part of software development. To maintain user trust, proactively monitor for bugs before users encounter them.
00:27:11.940 Monitoring and alerting systems are key to quickly catching these bugs. For example, if you notice a charge of an unusual amount, alert the relevant teams. Additionally, maintain a damage control plan to ensure swift communication with affected users.
00:28:27.650 Communication is critical during these times. Make sure all team members understand how to respond, what information to provide, and how to approach users effectively.
00:29:50.270 Finally, conduct post-mortems to analyze what went wrong, why it happened, and how to prevent similar issues in the future. Learn from these experiences as they enhance your team's knowledge and preparedness.
00:30:30.350 To recap, we explored asynchronous transactions, payment status visibility, user control of payment information, preparing for significant changes, and dealing effectively with bugs.
00:30:52.660 All the points lead back to one critical aspect: maintaining user trust. I hope you found this talk useful and interesting; it compiles a lot of lessons learned from my experiences and the struggles of others.
00:32:17.530 If this resonated with you, please come talk to me after the talk. I'll be here for both days. Don’t be shy! I love discussing payments, as it's an area I've been working in for years.
00:32:41.060 Thank you for listening.