319: Wins & Losses
The Bike Shed - A podcast by thoughtbot - Martedì
Categorie:
Steph started a new project and shares details about the new tools she's using, including working on a remote dev environment. Chris shares a journey with Lograge and Rails flash messages as he strives to capture user-facing errors. They also discuss "silencing" flaky tests, using Graphviz to visualize data dependencies, and porting Devise views to use Inertia and Svelte. It's also interesting how different their paths have been this year! This episode is brought to you by ScoutAPM. Give Scout a try for free today and Scout will donate $5 to the open source project of your choice when you deploy. Joel Quenneville GitHub - roidrage/lograge: An attempt to tame Rails' default policy to log everything Graphviz Become a Sponsor of The Bike Shed! Transcript: CHRIS: Tech talk nonsense and songs, that's what people come to The Bike Shed for, variations on the Jurassic Park theme song, you know, normal stuff. Hello and welcome to another episode of The Bike Shed, a weekly podcast from your friends at thoughtbot about developing great software. I'm Chris Toomey. STEPH: And I'm Steph Viccari. CHRIS: And together, we're here to share a bit of what we've learned along the way. So, Steph, what's new in your world? STEPH: Hey, Chris. Let's see. So I've started a new project. So frankly, there's a ton of new stuff in my world. And I've been on the project for about a week and a half now. I started over the holiday, and it's been going really well. Still in that whole early stage with getting to know the application, the codebase, the processes, the team, all the dynamics. It's a large company. So I'm working with a small group of individuals, but there are about over 100 developers that work at this company. And they do have a lot of documentation, which has been very helpful. But there's a lot to learn in terms of setup and processes, specifically. So they have provided a laptop that I'm using to access their codebase. So I'm using their laptop. And then, I am also using a dev machine, a remote dev machine, that they have set up for me. So I need to be on their VPN and SSH into that dev machine. So that's novel as well. CHRIS: Ooh, I'm very intrigued by that bit, not that they gave you a laptop bit but the dev machine. This is in the cloud sort of thing? What is this? I'm very intrigued. STEPH: I don't know if I have concrete answers for you. But yes, for me to be able to access their codebase, I have to go into the dev machine. And then that's where then I can do my normal development work. CHRIS: So is this like an EC2 instance or something like that that you're SSH-ing into, and then you can run processes on it? Or is it closer to the GitHub dev containers thing that they just released? Or are you running with your local Vim? Is it a remote Vim? Are you using Vim? Is it VS Code? I have so many questions. STEPH: [laughs] I think it's more like the first version, although I don't know the backbone of it. I don't know specifically if it's an EC2 instance or exactly how it's being hosted and how I have access to it. But I did have to set everything up on it. So they started the dev machine up for me. Their DevOps team started an environment where then I could access, and then I did need to cultivate it to my own habits. So I had to install several things. I had to install Brew and Vim and also the tmux and all those configurations that I'd really like to have. They do have a really nice Confluence document that walks you through how to set up a connection between VS Code and the remote environment. So then that way, you can really just hang out in VS Code all day. And initially, I was like, okay, I could do this. And immediately, I was like, no, I love Vim. I'm going back to it even if I have to spend the 20, 30 minutes setting it up. I'm so comfortable with Vim and tmux that I stuck to my roots, and I didn't branch out into VS Code. But I think VS Code is one of the more popular tools that they're using. So that way, it feels more local versus having to work in a remote machine. I think I answered some of your questions. I don't think I answered all of them. CHRIS: Yes. I think you did answer all the questions. But just for clarification, the Vim and tmux and whatnot setup is that you're running SSH, and then on the remote machine, you are using Vim and tmux? Or is it a local Vim that is doing…I think Vim has some remote editing capabilities but not anywhere near what VS Code can do. STEPH: It's the first setup. So I am SSH-ed in. And then I have Vim and tmux running on that remote machine. CHRIS: Gotcha. Novel. STEPH: Yeah, it's a thing. It's working. So that's good. And it feels cozy. I feel like I'm at home. I feel like I can be productive. So that's great as well. Some of the other tools that I'm also new to, so they use Zeus, which is used to then speed up the booting of your application. And you can also use it for speeding up test runs. So very similar to Spring, which I think we've had some discussions about Spring and who loves it and who doesn't. [laughs] CHRIS: I don't know. I'm not...[chuckles] I feel like I remember Zeus. But Zeus is like three iterations ago of this preloader thing. I'm intrigued by that. I thought Spring had fully supplanted it in the Rails ecosystem but maybe not. STEPH: So this company has been around for a very long time. So there are a number of tools that I think they're using because that was the tool to use the day when they got started. And then it just hasn't been a need to move on to one of the newer tools to use Spring. So at least that's my current explanation for why we're using Zeus. And also, Zeus works most of the time. I'm frankly still getting comfortable with it. [laughs] I still have gripes about Spring too. CHRIS: 60% of the time, they work most of the time. STEPH: [laughs] So, Zeus is another new tool that I'm adding to my tool belt during this engagement. Another new tool that I'm using is Gerrit. And so they use Gerrit…it is used for managing their Git repositories. It is used for code reviews. And being as accustomed and familiar with GitHub as I am, that one has been a little tricky to then navigate and change the whole UI that I'm used to when it comes to pushing up code, reviewing code, asking for feedback on changes. And at one point, I was reviewing a change request for someone else. And there's a button on there where I was adding comments, but they were in draft mode. And I'm trying to figure out how to get them out of draft mode so that they're actually submitted, and the other person could see it. And I saw a submit button. I was like, cool. So I hit the submit button. And then it said something in red text about ready to be merged into main. [laughs] I was like, oh, no, I mean, maybe, but that's not what I meant to do. So I had to reach out to that person and be like, "Hey, I'm new to Gerrit. I don't know what I did. I hit a button. I hope everything's fine. Here's my review. Best of luck. [laughs] I think everything is fine. Nothing dramatic came out of it. But I had my own little dramatic moment. CHRIS: Wow, that is a bunch of new stuff. It's interesting. On the one hand, I totally understand projects get started, and there's a certain set of tools that are current at that point, and so then you're using them. And then, over time, it takes a very active effort to try and keep up with the new current, that new-new as we call it. But the trade-off there is really interesting because, at any given time, it never feels like the right investment to pursue the new thing to just upgrade for upgrading sake. But then the counterpoint is the cost to someone like you coming onto the project. And it's like, it's a bunch of new stuff. It's kind of old stuff. It's new for me, but it is old, and less documented, and less familiar. And it's also certainly less compatible with other things that are going on, almost certainly. And so, how to stay on top of those updates is always the thing that's really intriguing to me. I say as someone who started a project recently, and I have not thought about upgrading anything at this point. And we have bundler-audit I want to say is the one thing that we have in there. So if there's a CVE for a gem, then security-wise, we will be upgrading those. But otherwise, I haven't thought about upgrading our Ruby version or anything. And I think we're on 2.6 or something like that, which is a couple back at this point. And so it's something that's in the back of my mind. I feel like I should have a formal answer to this. Like, company-wide, how do we think about the process of upgrading? And Dependabot and things like that answers some of it, but that doesn't tell me when to upgrade Ruby, I don't think. It could. That would be annoying. I don't want that. But it's one of those many things that depends and is subtle. And you have to decide where you put the trade-offs and whatnot. So just an interesting thing. And to observe you now going into this project building and being like, there's a bunch of new stuff. STEPH: I think it really takes passion or pain. Those are the two things that then prompt us to upgrade. Either it's pain, and you need to change it to get rid of that, or it's passion. So you're really excited about the next version of Ruby or the next version of Rails. And I think that's fine. I think that's fine that those are often our drivers. But yeah, that is interesting. I hadn't really thought about that in terms of there's often no real strict process around when we upgrade except those are then the natural human catalyst. CHRIS: I think you're right that those are the catalysts. But I think quite often those cannot be sufficient to push us to do the work. And so what do you do in the absence of that? It's not really painful. And I'm not really passionate about it. But I probably should do it is the 80% of the time middle space that we live in. And so yeah, I don't have an answer to it. I'm more observing the question. But like so many other things, I feel like often we just exist in that awkward middle and got to find a way through, so how like life. STEPH: I was having a conversation with someone earlier a bit about these life cycles that we live in. Specifically, we were talking about consulting and how changing from project to project is so daunting. Because you go from I'm accustomed to this project, I'm accustomed to the team. And then all of a sudden you jump into this new project and with all these new things it can be really interesting. But then there's also this feeling of like, wait, I used to be smart, and I knew everything that was going on. And the team knew me, and I knew all the team processes, and I felt good. And now I'm in this totally new space, and I have to relearn, and I have to reprove myself and relearn all the company politics. And there's always that initial jumping from a sure space over to a very new space that always makes me then question and be like, yeah, I can do this, right? I can do this. And then I have to keep letting that voice build until about two weeks in. And I'm like, oh okay, I'm back in a good spot. I said two weeks; it's probably more like four. But there's still that grace period of a new project where you're leveling up on all the things and learning the new team. And as daunting as it is; apparently, it's what I like. Apparently, I like that roller coaster ride that comes from jumping from one project to the next. So on that note of a bit of novel insight into myself, what's new in your world? CHRIS: What is new in my world? Let's see. I think I've got two updates, two anecdotes to share. One, I lost the battle, one I won the battle. So we'll go with the lost battle first because that seems fun. So we have Lograge on this application, which Lograge, for anyone that's not familiar, is a library that helps with producing more structured and more complete log lines from a Rails application. You can tell it to do JSON log lines, which is useful for many of the tools that will receive your logs. And then with it, you can say grab me the controller name and the params but sanitized and this and that. And so, you aggregate a bunch more data than would traditionally be in the logs. In general, I've just found it to be a much better foundation. I find the logs to be more readable, and more informative, more useful, all those lovely things. But slowly, I've been looking at what's the other stuff that I want to have in here? What else would be nice to know? So one example is we use Inertia on this project. And Inertia has a particular way in which errors get mapped back to the front end. And it's an interesting little trick that involves the session, but that's sort of an aside. Basically, this is something that the user will see that I would love to know about. So how many users are hitting their head against the wall? Because typically, whenever these errors happen, that means this is a flash message or something like that we're going to show to the user. So we were able to add that into our log lines. Now we can see those. We can aggregate on them. We can do counts. We can do alerting and monitoring, all those kinds of fun things. So cool. That was great. That worked well. I then specifically…I mentioned the flash a second ago, but that's actually not…the Inertia messages will not show up in the flash. They end up in forms inline on certain inputs or whatnot. But we do also use the flash message pretty regularly as a way to communicate to the user success or failure or what have you. And I really wanted to get those into the logs. And I tried very hard, and I failed. I gave up. I threw in the towel. I raised the white flag. So the nature of the flash, which is something that knew in the back of my mind but I had never really experienced as pointedly as this, is the flash is a magic value within the Rails ecosystem that can be written to and then once read clears itself. That's the nature of how the flash is supposed to work. And it persists across requests. So it's doing some fun stuff there, which I assume is tunneling through the session or maybe putting it into a cookie. I'm not actually sure. But there's some way that you post to an endpoint, and then you get redirected to the show page. And on the show page, we actually display that flash value. But the flash is set on the controller endpoint that is handling the POST request. So this value spans across two request-response life cycles, which is interesting. And so the manner in which that works is Rails is managing that on our behalf. We write to it on the one side. And then, when we do the subsequent requests, if there's a value in the flash, we show it to the user, which is why occasionally you'll see those weird things where that flash message shouldn't show up. But it's like a sticky value that was left in the system that didn't get cleared via one thing or another. But I really wanted to put those into the logs. Like, what are we saying to the user is the thing I want to know. This is that question of like, what's my system doing at runtime? I understand what it's doing. I can read the code and understand what should happen. But what actually happened? Are users seeing this flash message way more than they should? That's a question I want to be able to answer. And I have lost the battle. I cannot find a way to read the flash value, put it into my loglines, but then also have it persist through. The first attempt I did, I was able to get it into my loglines, but then it didn't show to the user, which is a bad outcome. Because now I've read the value, Rails clears it, cool, that's fine. There is a flash.keep method. And that I thought would do the thing I wanted, which is like, oh, I want to read this value. I want to tap this value, I want to observe it, I want to peek at it. And I thought this keep method would do the thing that I wanted. It did not. It just caused the flash to be persistent. So now, anywhere I went had the same flash message for forever, which was not the behavior that I was looking for. I then tried, like, all right, just for exploration purposes, what if I reach inside and read the instance variables of the flash objects? Also did not work. Everything I tried did not work. And it had these fun failure modes that just made me very sad. Thankfully, we had feature specs that told me about this failure mode because I would not have known about it otherwise. This was not obvious to me on first implementation. But yeah, I lost, and I feel sad. And then I did the thing that we do, which is I searched Google, and there's nothing. I cannot find…This is one of those cases where like, I can't be the first person who wants to know what's in the flash. I can't be breaking new ground here. And yet I couldn't find anything on the internet. So that's where I'm at. STEPH: That's interesting. Yeah, I'm trying to think…I think I'm one of those people. I don't think I've ever tried to peek into the flash and see what's there ahead of time. And it makes me wonder if it's partially…so we can't peek into the flash. You've exhausted several examples or tries there. When you're setting the value of the flash, it makes me wonder if there's an order of operations that you have to pursue. So before you set the flash, you know what messages that you're going to share. So you send that off to the logs, but then also share that to the flash. So instead of writing the message directly to the flash and then having to check the flash, if you just stored that value elsewhere and shared it to the logs first. Is that a reasonable approach? CHRIS: It definitely could work. But that was in the space of this is getting weird enough. I thought about things like that, but I didn't want to do anything weird. And part of the benefit that I get from using Lograge is rather than having multiple lines for each request…so a request came in and rendered this partial and did this thing. It gets constructed such that there's a single logline, which is one big JSON object that contains all of the data about that request. And I really liked that structure because then everything's correlated like, oh, did we 404, or did we 302? And what was the message that we said to the user? And what were the params? It's all there in one line. I found that to be really useful. So I wanted to do that. I could just separately log it. But then I'm also worried of there is a statefulness there. Because again, the flash is written on one side and read on the…it's like a Hail Mary to ourselves between requests. Look at me with a sports reference. And so, I didn't want to try anything out of the ordinary. I really just wanted to find a way to just like; I just want to read this value but not like Heisenberg uncertainty principle observing changes in the system. I found myself in that space, and I was like, can't there be a way that I can just flash.peek? And I just want to take a quick look. I don't want to mess with anything. You do your normal thing, flash. Just let me know. And I do not have an answer for it yet. And for now, this is one of those nice to have, not an absolute requirement. So I wasn't yet in the position of okay, fine, let's do some out-of-the-box ideas here. So I'm still in the in the box phase, I would say, but who knows? Maybe down the road, I'll be like; I would really love to know what the flash message was for that request because this user is seeing stuff that we do not understand. And that information would tell us the answer. So we're not there yet. But I was surprised by how thoroughly I was defeated by Rails and the flash message on this adventure. STEPH: I am equally surprised. I wouldn't have thought that particular achievement would have or is proving to be that hard or, frankly, not doable. So yeah, I'm intrigued to see if anybody has thoughts on it or if you do find a different solution because Lograge is one that I haven't used. But I would be surprised if other people haven't had a similar request of like; I want to be able to store what's in the flash message. Because like you said, that seems super helpful. CHRIS: Well, certainly, if I do figure anything out, then I will share that with the world. But yes, part of this is putting it out there into the universe. And if the universe happens to send me back an answer, I will happily accept that. But yeah, again, I had two stories, and that was the one where I lost. I'm going to send it back over to you because I'm interested in anything else that's up in your world. And later, I'll tell the story of a victory. Mid-roll Ad And now a quick break to hear from today's sponsor, Scout APM. Scout APM is leading-edge application performance monitoring that's designed to help Rails developers quickly find and fix performance issues without having to deal with the headache or overhead of enterprise platform feature bloat. With a developer-centric UI and tracing logic that ties bottlenecks to source code, you can quickly pinpoint and resolve those performance abnormalities like N+1 queries, slow database queries, memory bloat, and much more. Scout's real-time alerting and weekly digest emails let you rest easy knowing Scout's on watch and resolving performance issues before your customers ever see them. Scout has also launched its new error monitoring feature add-on for Python applications. Now you can connect your error reporting and application monitoring data on one platform. See for yourself why developers call Scout their best friend and try our error monitoring and APM free for 14 days; no credit card needed. And as an added-on bonus for Bike Shed listeners, Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed. That's scoutapm.com/bikeshed. STEPH: I have a victory that I can share as well, and I'm excited to hear about yours. So to share a bit more context about the project that I'm on, we are focused very heavily on improving their test suite, not only the time that it takes to run the test suite but predominantly addressing a lot of the flaky tests that they have. Because that is a huge pain point for the team and often leads to the team having to rerun tests. And so, there are a couple of areas that we're very excited to make some contributions. The first part is that we are just looking at those flaky tests to figure out what is going on and how can we address these? And one of the nice things, one of the tools that they're using TeamCity is the tooling that they're using to run their automated test suite. And TeamCity will let you mute tests, so then that way, if you do encounter a flaky test, you can mute it. So then, at least it's not impacting other people. I say this with some asterisks that go along with it because, for people who can't see, Chris is making a very interesting face. I think you have thoughts on this. And the other thing that they will show is a flip rate for the flaky tests, which is really nice, too, because then you can see which tests are flaky the most. So then that helps us prioritize which ones we want to look into. All right, I'm going to pause so you can respond to that comment I made about muting tests. CHRIS: I'm intrigued. I talked in a recent episode about adding RSpec::Retry. So the idea of flakiness being a thing that exists and trying to decide how much engineering effort to apply to fixing it. But the idea of muting it and especially muting it in the UI, not in the test suite or not having that be something that's committed, there's something about that that caught my attention, and thus apparently, my eyebrows raised. You saw that. [laughs] But I don't actually know how I feel about it. This is such a complicated, murky area that I wish I had a stronger set of beliefs around. It was interesting when we talked about the RSpec::Retry thing. I think you rightly pushed back on me, and you were like, that's interesting, maybe don't do that. And I was like, that's a fair point. [laughs] And so now hearing you're in the quagmire of flaky tests, and yeah, it's an interesting space. STEPH: Well, I think my hard belief is that muting tests is a thing that we shouldn't do. It's going to lead to more problems, and you're not really addressing the issue that you have. It is a temporary solution to a much bigger problem that you have. And so it is a tool that you can use to then buy you some more time. And so that is the space that this team is in where they have used this particular tool to buy them more time and to be able to keep shipping changes while realizing that they do still need to address these underlying issues. So it is a tricky space to be in where essentially, you've gotten to the point that you do have these muted tests. It is a way to help you keep going forward, but you are going to have to come back to it at some point. And so that's the space that I'm in right now joining the team is that we have been brought in to help some of their engineers specifically address this issue while ideally letting the rest of the team continue to focus on shipping changes while we address the test. Although I really think there's going to be two angles that we've talked about in how we're going to help this particular codebase. One of them is that we are going to address a flaky test. But the other one is empowering people that they feel like they have the time and the knowledge that they can address a flaky test and also not contribute more flaky tests to the codebase. But I appreciate that you called me on that a bit because we've had those conversations around when we should actually address something versus muted, all the interesting trade-offs that come along with that conversation. So this particular flaky test that we addressed earlier this week is specific to hard coding primary IDs. The short version is that it's bad, don't do it. The longer version is that they were having a test that was failing intermittently because it would pass the first two runs, but then it would start to fail for all future runs. And the reason it would pass for the first two runs is because when they were setting the ID for a record that the test setup is creating, they were looking for existing records and saying, "Hey, what's your latest ID?" And then I'm going to guess the next ID. I'm going to add one to that to figure out what the next ID should be. Some additional context, when the tests boot up, there's some data that's being created before the test run. So then that's why they're checking to see, okay, what records already exist? And then let's add one to that. The reason that fails sometimes is because then once the tests have run, the Postgres IDs aren't being reset, so they're using a truncate approach. So then, when the test runs once or twice, that works. But then, at some point, there's a collision between those IDs where they tried to guess the next ID, but then Postgres is also on that same ID, and it ends up failing. There are also some callbacks. There's some trickery afoot. It took a little while [chuckles] to work through these tests to understand why they're failing. But the short version is that we thought we had to restructure the data in a way that no longer required us to guess what the next primary key should be for a record. We could actually use Factory Bot to generate that record, and then ask Postgres, okay, what ID did you assign? And we're going to pass that in. And that part was really challenging when you're in a new codebase, and you are learning the domain knowledge and exactly how data should be structured. So that was one challenge of it. The other part was that a lot of the data relies on each other. So then figuring out the right hierarchy in which we could create the data. So we didn't have a circular reference at some point. It took some time. And Joël Quenneville, who's on the project with me, used a tool that I found very helpful. It's called Dataviz. He went through and documented the let statements, the data that's being created, and then it generated a nice tree structure that shows you okay; these are your dependencies. This is the test setup that you're using. And then from there, just by changing a few lines in that particular file that used to generate that Dataviz tree, he would move it around. And we could simulate what we were already mentally trying to construct in our head. So as programmers, we're already thinking, okay, I know this record needs that data. And that data needs that data before I can build this. But this actually turned it into a concrete visualization where we could see it. And I was really struggling. And he was like, "Hey, I got it into a visual form that we can look at. And there's a circular reference. That's why this keeps happening and why we're not making progress." So then, using that, we were able to then reformat some of the dependencies, look at the graph, see that we didn't have that circular reference anymore. And then we could implement that in code. And it really helped me to be able to walk through that visual aspect because then I could say, okay, this is all the stuff that I'm trying to mentally hold on to, but instead, I can just look at this and know it's going to work. I don't have a circular reference. It also helped concretely show why the previous efforts were failing and why we kept running into some issues. So I'm really interested now in Dataviz because I found it very helpful in this particular case. And I'm very intrigued to see if I can apply this to more tests that I'm trying to fix and to see if I can start out with here's the current structure. Here's where I'm trying to go. And then essentially build that graph first before I start changing the code around. I would love to have that optimization. And I feel like it would speed up the process. CHRIS: It was funny as you started to say that I had observed some tweets going out into the world recently. And I was like, this is Joël. This is definitely Joël talking about these things. As an aside, for anyone who doesn't follow Joël Quenneville on Twitter, @joelquen, I would highly recommend it. We can include a link to Joël's Twitter in the show notes. Joël is one of the clearest thinkers and communicators about programming that I have ever worked with. And in particular, what you're describing of the data visualization is something that I think he does incredibly well. Often he'll make blog posts, but they'll include just simple little visualizations, little images, or diagrams, or flowcharts that just so concretely encapsulate an idea and express it so much better than text ever could. And so, in so many ways, I look to Joël's writing, both on Twitter, in the blog, in many places. And I just appreciate so much what he puts out there and the manner in which he does it. So I was by no means surprised when you said, "Oh, and I'm working with Joël on this project." I was like, yes, I bet you are. That sounds true, and in particular, some of the conversations about flaky tests and determinism and all of that. So yeah, the visualization stuff is also particularly interesting in taking a system that it's very hard to hold all of this in our heads. But that visualization, the tree and/or graph thing at play, having that in a picture and being like, oh, look, there's a cycle now. There we go. Can't have those. That's not okay. That's a really interesting solution that's just very cool to hear about and presumably led to a good outcome where you were able to break that cycle. And now you're happy and deterministic in your tests. STEPH: Yeah, it's one of those approaches where I wonder if it was helpful afterwards and how can I make it helpful beforehand? Because it felt like a confirmation of the pain in the process that we had been through. And I'm eager to see if now I can apply it ahead of time and save myself some of that pain. That's where I get really excited. But yes, it was a successful outcome. And we have fixed that particular flaky test. But I'm very excited to hear about your victory from the week. CHRIS: It's a shared victory. It was a team victory, just to be clear. But we are working in a system that is using Inertia. Inertia.js is a project that I've talked about a number of times on the show. I'm a huge fan of it. It is the core architecture of how we're building our application. But as a very brief revisiting of what it is, on the server-side, we have Rails, and Rails is acting in a pretty traditional way. We do not have an API. And on the front end, we have Svelte, which is a JavaScript view layer framework. Inertia sits between them and binds the traditional Rails MVC architecture and the Svelte front end. So again, there's no API in the traditional sense of this is a REST endpoint, and we hit it, and we get some data, and then the front end holds on to that in a store. None of that is going on. Inertia does a wonderful job of marrying these two concepts and allowing us to use familiar programming techniques on the server-side but then also have a more future-friendly front end. Animations and transitions and things like that are now totally possible while not throwing away the entirety of our programming model that we've had in Rails server-side applications. That's all well and good. Almost all of the UI in our application is rendered via Inertia and Svelte. That's great. We love it. The one caveat is Devise. So we have Devise on this project, and Devise comes with a lot of views built-in. And we have both an admin and a user model. So we have sign in and sign up, and confirm registration, and forgot password and all of these different views and flows and things that Devise just gives you out of the box. And being an early-stage startup, it was not a good time to revisit any of that or to try and build it from scratch or any of that. We just wanted to build on the good known trusted foundation that Devise gives us. But the trade-off there is that now all of our Devise logic lives in this uncanny valley. It's the only stuff that is in ERB views. Our styling, thankfully, we're using Tailwind, and so we are able to have some consistency between the styling. But recently, we redesigned the flash messages on the client-side in our Svelte pages. But on the server-side, they are a little on the Devise-side because Devise is the only pages that are being rendered truly server-side. They look a little different. And this is a pain that we felt, that inconsistency or that mismatch between the Devise views. And then the rest of the application is a pain that we felt but one that we consistently were like, I don't think it's worth the effort to try and change this. Finally, this week, we've been doing a lot of work on our user onboarding funnel. So the initial signup flow going through it's a progressive form screen where you go in between different pages. And a majority of it is implemented in the Inertia and Svelte side of things. And it's very nice and very fun to work with. But the signup form, the user signup form, is in Devise, and it's a traditional Rails server-rendered post, and then all the normal stuff happens. We finally decided to bite the bullet this week and see how painful it would be to port that over to Inertia and Svelte. And spoiler, it was awesome. It was very straightforward, and coming out of it, immediately, the page was largely the same. The server-side code was largely the same. But now we had things like when you submit this form, if there's a validation error, we don't clear out your passwords because we're staying on that page on the client-side. We're taking advantage of the way Inertia's error flow works. That's a subtlety of how Inertia works. That's probably more detail than we want to get into here, but it's an awesome thing that works and is great. And so immediately, this page just got better. We got inline errors for each of the fields. We were able to very easily add a library called Mailcheck, which I've talked about on an episode a while back. But this is a thing where if you have a typo in your email address, we can say, "Hey, you have a typo in your email address. And if you click this link where we suggest the alternative, we'll just replace it inline." That would have been really awkward to wire up in our Devise view. It would have been some jQuery-esque script tag at the bottom of the view page that doesn't stop…We don't have jQuery actually at this point. We wouldn't have jQuery. And we could certainly, but it would only be for that view. And it would be weird and different in a fundamentally different programming model. It was trivial to do in the Inertia and Svelte world once we had made that port over. This was always my hope. This was the dream that I had in mind. And it speaks to the architecture of Inertia. And Inertia is a really great abstraction that is very minimally leaky. I won't say it has zero leaks because no abstraction does. But this was my hope is I think the server-side should mostly stay the same. And I think the client-side, we just take an ERB template, turn it into a Svelte template, and we're good to go. And that has largely been the case. But suddenly, this page is so much more. There are subtle animations as things come in. And there are just lots of nice features that were trivial to add now and that fit with the rest of the programming model that we have throughout it. So that was awesome. STEPH: That is awesome. I love these styles of updates where there's like, oh, I had a loss this week. But I also had this really great win because that feels just so representative of a typical week. So I love this back and forth. CHRIS: It's also that sequence is how the week went. So the loss happened earlier in the week, and then the win happened later in the week, which is how I would prefer it because now I'm going into the weekend with a win. Like, cool, I'll take it. Had it gone in the other direction, I would have been like, oh man, Rails beat me. But I guess it's the weekend now. I'll forget about it for a little while. STEPH: Yeah, that definitely helps to end on a positive note. CHRIS: But yeah, I don't think too much more to say about that beyond it was both really nice to get the added functionality to get the better, more user-friendly behavior in this view that naturally falls out of this programming model. But also to have that reinforcement of my belief in Inertia as a good architecture. Not only did we get some really nice stuff out of doing this port, but it was also pretty straightforward because Inertia sits so comfortably between the pieces. And that's a story that I really like. I want more of that in my programming world, where to change this thing requires changing everything in our app. Oh no, this is sad. No, this was a great example of we were able to very minimally change things and get a much better experience out of it. So once again, I am very pro Inertia.js STEPH: It's interesting to me how different our paths have been this year where I have been working on applications that are brought on thoughtbot to then help out with some of the concerns that they have, either their application is going down, or they have a test suite that they need to improve, or there's a lot of triage that's involved. And so it makes me very excited to hear that, when you are building stuff, and it's going really well and how awesome that is. Because then I feel like most of my world has definitely been more in the triage space, which is a very interesting and fun space to be. But it brings me a lot of joy to hear about wins from let's build new stuff and hearing it be built from the ground up and how well that's going. CHRIS: Well, I'm definitely happy to provide that. But also, I want to be realistic and be like, I’m just writing next year's legacy code right now, let's be honest. I'm very happy with where we're at in this moment. But I also know how early I am in the project that I'm working on. And I'm burdened with the knowledge that I'm certain one decision that I'm making of the many that are being made I will deeply regret a year from now. I just know that that's true, and I can't let it slow me down. I got to just keep making decisions and do stuff. But I know that there's going to be one. I know that a year from now, I'm going to be like, why did we choose that option? But it's sort of the game. STEPH: [singing] We'll just know that there's something strange and your code won't change. Who are you gonna call? thoughtboters! CHRIS: Well, yes. I will definitely be calling you when I find myself in the uncertain times of legacy code of my own creation. So I look forward to that, frankly. But that's a problem for a year; I don't know, maybe two years from now. Who knows? But for now, what do you think? Let's wrap up. STEPH: Let's wrap up. The show notes for this episode can be found at bikeshed.fm. CHRIS: This show is produced and edited by Mandy Moore. STEPH: If you enjoyed listening, one really easy way to support the show is to leave us a quick rating or a review in iTunes as it really helps other people find the show. CHRIS: If you have any feedback for this or any of our other episodes, you can reach us at @_bikeshed on Twitter, and I'm @christoomey. STEPH: And I'm @SViccari. CHRIS: Or you can email us at [email protected] STEPH: Thanks so much for listening to The Bike Shed, and we'll see you next week. All: Byeeeeeeeeee!!! Announcer: This podcast was brought to you by thoughtbot. thoughtbot is your expert design and development partner. Let's make your product and team a success.Sponsored By:Scout: Scout APM is leading-edge application performance monitoring designed to help Rails developers quickly find and fix performance issues without having to deal with the headache or overhead of enterprise-platform feature bloat. With a developer-centric UI and tracing logic that ties bottlenecks to source code, you can quickly pinpoint and resolve performance abnormalities -- like N+1 queries, slow database queries, memory bloat, and more. Scout's real-time alerting and weekly digest emails let you rest easy knowing Scout's on watch and resolving performance issues before your customers ever see them. Scout has also launched its new error monitoring feature add-on for Python applications. Now you can connect your error reporting and application monitoring data on one platform. See for yourself why developers worldwide call Scout their best friend and try our error monitoring and APM free for 14-days, no credit card needed! And as an added bonus for Bikeshed listeners: Scout will donate $5 to the open-source project of your choice when you deploy. Learn more at scoutapm.com/bikeshed.Support The Bike Shed