Fixing SaaS Billing With Rust

The following is the transcript from my interview with Yann Leretaille, CTO of Wingback, a company you might be familiar with from the many times they've appeared in the Rust Jobs Report. I really enjoyed talking with Yann. It was interesting to hear about Wingback, how they're using Rust, and their very human approach to hiring engineers. As always, feel free to check out our extensive rust job board.

Drew: Hi Yann, thanks for taking the time to chat today. I’m excited to learn a little bit more about Wingback and especially to “poke around under the hood” of your product a little. I’m also interested to hear about the culture at Wingback and your job specifically, but let’s start with Wingback. Where did the idea for Wingback come from?

Yann: Wingback was built on some of the experiences we had in our previous company 1aim. We were always very product-focused, trying to build a great product, take care of all the edge cases, and create a great user experience. I think that’s how a lot of tech-focused teams get started. Eventually, we finally got to the stage where the product was in a good state, and it might sound simple, but we realized we actually had to start selling. Everyone gets to the point where commercialization becomes important. We were in the IoT sector, selling hardware with a software subscription connected to it. We had this really complicated SQL query that would aggregate usage over the months, and then that would get sent to the sales team. They would manually create an invoice in Excel. It turned out we often sent invoices late. Sometimes we even forgot to send them, and many were incorrect. We thought these issues were unique to us as a hardware-focused company. But then, as we started working on Wingback, we realized that this is a common problem, especially in SaaS.

Drew: Can you explain that complexity of billing a little bit more?

Yann: From a technical perspective, it initially seems very simple. Let's say you have three plans: silver, bronze, and gold, each with a different price. You just set up recurring payments on Stripe, and customers can sign up, right? Easy. The issue arises when you start making changes. Maybe next month, you add a free tier or a free trial. Then, you overhaul your gold plan. As you gain traction, you add new features. Suddenly, all your plans need these new features, and maybe you also move some of your existing features into new tiers. But you still need to grandfather in your old customers, so after a few iterations, you suddenly have 20, 30, even 50 different prices and feature sets. Now, it's your job as a developer to determine which customer should have access to which features and what the right charge should be. The information in your database says something like, "This is a gold plan, version two from last year." This balloons very quickly. We've seen late-stage companies with tens of thousands of different plans internally, and usually a complex, hacked together system to manage all of that. No one wants to touch it because any change is like opening Pandora's box. So, we realized there should be a solution that fulfills two goals: 1. Having the best possible implementation of plan & entitlement management with the complete billing chain derived from it - It just doesn't make sense that each company has to spend so much time building their own sub-par versions of this when it has nothing to do with the core product. 2. Enabling sales and marketing teams to build all the plans they want without bogging down engineering.

Drew: How does Wingback differ from just using a solution like Stripe?

Yann: Stripe is great for payments, and it’s one of the payment gateways you can use with us, but it falls short when trying to model complex pricing models. We are an all-in-one solution for the entire billing chain and aim to be the single source of truth for anything related to pricing and selling SaaS software. We start with the basic building blocks, which are the actual features of your product - everything else is derived from that: we provide a plan builder, quoting tools, sign-up links, dynamic pricing pages, and self-serve tools. This is translated into per-user entitlements so that you can programmatically enable or disable certain features. We also include a customer billing portal for tracking usage, viewing bills, updating payment methods, and plan upgrades. On the accounting side, we handle invoice generation, refunds, taxes and complexities like prorating, which is calculating the difference in price if customers upgrade mid-cycle. It sounds simple, but it gets very complicated fast. Shameless plug: If there are any engineers reading this who are continually bothered with packaging & billing tasks, we'd love to help! Please reach out.

Drew: The reason we’re talking today is because you guys use Rust, but what does your full stack look like?

Yann: The backend is composed of a few services, but it’s almost a monolith, and it's written 100% in Rust. On the frontend, we went pretty pragmatic: classic TypeScript and Svelte (+Tailwind), which I find very refreshing compared to React.

Drew: You said your whole backend is written in Rust. I feel like in a lot of cases people only use Rust for one critical component of their application. Why did you decide to use it across the board?

Yann: I'll admit, I'm a bit biased here. I discovered Rust back in 2015, during the week between Christmas and New Year's. At the time, my first company 1aim was in its early stages, with a very rough backend, cobbled together with different languages. Rust felt like everything I had ever wanted in a language. I spent the entire week reimplementing our entire backend in Rust - we ended up being one of the first production users of Rust. For an application like Wingback, where stability and repeatability are crucial, Rust is a great fit. The type system, in particular, allows us to do some really interesting things in terms of validation and abstraction. It catches a lot of business logic errors before they become a problem. For instance, we recently added an additional state that a payment can be in. Given the size of our code base, this state has to be handled in many places. If we missed it even once, it could disrupt the entire system and lead to inconsistent state somewhere, which would be really hard to fix. Thanks to Rust, we could confidently make this change knowing that the type system would catch any omission. Although heavy use of high-level abstractions aren’t always great for compile times, it gives us peace of mind while rapidly adding features. I don’t believe is the perfect fit for every backend (yet!), but for an application like ours, it’s a godsend.

Drew: So are your compile times really long at this point? Has that been an issue for you operationally?

Yann: Our project is organized in a large workspace with subcrates for the different components, all interlinked. We also use a lot of abstractions and amazing high-level libraries that come with the Rust ecosystem. So yes, compile times are a bit on the higher side now. However, the type system and the borrow checker catch so much that it's manageable and allows for quick local iteration. Thankfully, compile times have improved a lot over the years and writing async code has become a lot more ergonomic - and I believe that it will continue to improve. Operationally, we have an extensive set of tests that run in our CI. We recently switched from GitHub runners to BuildJet, which gave us two to four times the performance for the same price. That significantly sped up the process. Within a few minutes of submitting a PR, all the tests will have run. At this point, build times are not super noticeable. Building a release build is always a bit slower, but we don't do that often. Honestly, the harder part was enabling devs to run the entire environment locally in containers and setting up a robust test infrastructure.

Drew: Can you give a sense for some of the interesting engineering problems that you’ve run into building Wingback?

Yann: The most challenging aspect to get right has been the user experience, mainly because we have several different parties interfacing with our product. In many ways, we're a UX-first company. Almost everything you do in Wingback is through a graphical interface. We also provide an API, but we expect your sales and marketing teams to do most things through the GUI. So, it's crucial that we make the experience good for them. At the same time, we want to ensure a great developer experience, making it easy to integrate both on the backend and the frontend. For instance, we had to build a library called wingback.js for everything frontend related. So, we actually ended up having like five different APIs for the different scopes: our actual customer, the developers, and our customer’s customer, our customer’s customers users, plus various management that we need from our side. And then they all have to interact correctly, right? Rust’s type system has been instrumental in this. For example, we use UIDs for everything, but we prefix them with what type of ID it is. This ends up being a zero-cost abstraction. Internally it always translates into UID, but validation will fail if you accidentally pass a wrong kind of ID to any part of the application. And we can use “super traits” to have functions that only accept types that implement our internal implementations of Identifiable or Indexable.

Drew: I think a lot of the people who will read this are probably rank and file engineers, so it might be interesting if you could give a sense for what it’s like being a startup CTO?

Yann: Being a CTO in a startup, often one of the founders, is indeed a unique experience. It's not for everyone - it requires a lot of work, and, if we’re being honest, from a long-term perspective, taking into account the risk factor, you will almost always earn more as a senior dev. However, for someone like me who thrives on challenging the status quo and constantly seeking new solutions, it's the perfect fit. That said, the role means that I have a lot less exposure to day-to-day technical work. In my previous company, 1aim, I did everything myself in the beginning, as is often the case. That was everything from designing electronics to writing code. At Wingback, we were fortunate to be venture funded from the start, which allowed me to focus more on the CTO role. My job involves aligning what our customers want with our roadmap, bringing a vision of where we want the company to be, and ensuring we use our engineering resources effectively. The hardest part is aligning what I currently believe our customers want with the things we can actually do right now. It also includes a lot of research, creating specifications, reviewing code, and participating in sales and customer discovery calls. However, the opportunity to make an impact is unique. The changes you implement can positively influence how your product or service is received and used, and that, in a more subtle way, contributes to the broader industry. This is one of the more fulfilling aspects for me.

Drew: You guys thought a lot before making Wingback full remote. Can you tell me about that?

Yann: We started Wingback as the pandemic was slowly coming to an end, and a lot had changed in that time. We realized that there's a new normal now. We thought about it a very long time and ended up deciding that this was the way we would go. Looking back, I think it was a great decision. It really opened up who we could work with. Even in our last company, we hired globally. We always kind of ignored CVs. I think CVs are really stupid. I care about whether a person is capable and if they could flourish in the right environment. So, we always had a very open, very wide hiring approach. But we found that now that we're fully remote, suddenly working at Wingback became accessible to a lot more people. Not everyone can move countries. People have families or just like where they are. So, suddenly we had a team on five continents from the get-go. And we kind of realized this later, but we also have a really big age and personality range. You just look at these superficial things a lot less when you hire fully remote. Also, we have a mostly asynchronous work mode now. We'll have a developer in Australia submit some code for review. And then, maybe someone in Europe will review it a couple hours later. So, it's a very different style of communication. Everything has to be written down. Conversations are often more thoughtful, which I really appreciate. You do have to be careful how you do it. You have to really reimagine all communication processes. But if it works, it's fantastic. I really recommend it.

Drew: It’s nice to hear your positivity about remote work. You and I both know a lot of the dialogue right now is running the other way. I can say from looking at our platform data that your belief that it opens up the talent pool is totally true. Something like 90% of engineers say they’re open to remote work compared to only like 40% for hybrid work.

Yann: I'm willing to give these other companies a bit of slack. When you're an established company and all your processes are built around face-to-face interactions, shifting to remote work can be a daunting task, because it affects everything. The ideal reaction would be to adjust these processes, but that can be quite challenging. Hybrid work can be particularly tricky because even though some people are sitting together, they still have to communicate as if they were working apart, which is a huge ask. Not everyone in your company will want that, and they might have expected something different when they were hired. However, many things that people say about remote work are simply not true. People say you can't have a team that sees each other as a team, or work on large projects together, or even start a company. These are all misconceptions. Hell, if you look at open-source communities, they've been doing this successfully for a long time. It's about being willing to do it and being very deliberate about it. At the end of the day, remote work is not just about changing the location of where people work. It's about changing the way we work, communicate, and interact. It's about building a company culture that values transparency, autonomy, and trust. It requires an initial investment of thought and planning, but the rewards are worth it. You gain access to a global talent pool, foster a diverse and inclusive work environment, and give people the flexibility to do their best work, no matter their life circumstances.

Drew: What are some of the key things that you’ve implemented to build Wingback around remote work?

Yann: The most important thing is being direct. In face-to-face communication, there are a lot of subtleties. We don’t have that luxury online, so we have to say things as they are. This applies to everything, including our job advertisements. We clearly state who we are, what we're looking for, how much we pay, and so on. Everything needs to be transparent. In terms of internal processes, almost everything we do has a paper trail. It has to be documented somewhere. We couldn’t just gather people in a room and declare, “okay, we're a company now.” We had to establish communication policies. For instance, we have a policy that states our communications are asynchronous, but we expect a reply during your working days within 24 hours. All these details that would usually be implicit have to be spelled out. Similarly, when we do company-wide updates, they usually come in video form, and in written form, because not everyone can join the call. So, there’s a theme here: anytime anyone communicates, it’s following the rules and standards we set for ourselves. That doesn’t actually slow us down - quite the opposite, actually. What it does is that every time you’re working on something, it requires you to sit down, think about it, and then make your thoughts and progress known to everyone. Which if you think about it, we should be doing anyway.

Drew: How big is your engineering team at this point?

Yann: The total engineering team is seven people. Half of that is Rust developers and the other half is doing frontend.

Drew: You mentioned that you hate CVs, which definitely resonates with me. But, a lot of people rely on CVs for lack of an alternative. What are some of the things that you use in place of a CV?

Yann: I could talk about this for a long time. When hiring, it's important not to fall into pattern recognition or clichés. Everyone has a different story and a different background. The important parts are more often in the small details. We don't really do coding interviews or use LeetCode. I don't think that makes sense, because ultimately what you're looking for is someone with an engineering mindset. Instead, I like to prepare by looking at stuff like actual code from open source contribution, if available. During the interview, I like to discuss the challenges they’ve faced and how they solved them. My goal is to understand where someone came from, why they got into programming, what technologies they are passionate about, and their opinions on certain projects. Also, it’s important to look for someone that the team will be able to work well with. Every team is different, and we have to take that into account. If I can genuinely understand a potential hire and their mindset, I can determine if they will excel at solving the kind of problems that we're trying to solve. The question I’m essentially trying to answer is, “Does this person have the mindset and the capability to solve the very concrete problems that we’re trying to solve, given the right environment?” If that is the case, we usually go straight to making an offer. I think people should be less dismissive of different backgrounds and different ways to look at problems. Objectively, having a lot of different backgrounds and people who look at problems in different ways will enable you to build better stuff. You just cover more perspectives! By the way, we'll probably be hiring more rust developers soon. If someone is interested, they can always reach out. The email is work_with_yann@wingback.com.

Drew: I really appreciate that you try to take a more human approach to hiring. That’s a big part of our mission as well, and I think it’s the direction our industry needs to go. Thanks for being a good example of that and thanks again for talking!

Yann: No problem!

get rust jobs on filtra

Know someone we should interview? Let us know: filtra@filtra.io