RailsConf 2023

Merged PRs: An Untapped Resource for Practice and Exploration

Merged PRs: An Untapped Resource for Practice and Exploration

by Thomas Countz

Summary of Merged PRs: An Untapped Resource for Practice and Exploration

In this talk, Thomas Countz delves into the significance of debugging as an essential skill for software developers, particularly within the context of the Rails framework. He proposes that developers can enhance their debugging capabilities by studying merged pull requests (PRs) from the Rails codebase, presenting this as an opportunity for practice and exploration.

Key Points:

  • Understanding Debugging: Debugging is defined as the process of detecting, locating, and correcting faults in software. It was highlighted that developers spend between 35% to 70% of their time debugging. This is a substantial investment of time and money, making it critical to improve debugging skills.
  • Importance of Debugging Competencies: Countz identifies several key competencies for proficient debugging:
    • Identifying problems
    • Reproducing issues
    • Applying a systematic approach
    • Comprehending code quickly
    • Using debugging tools effectively
    • Communicating issues clearly
    • Learning from past experiences
  • Current Learning Trends: Most developers learn debugging skills informally through trial and error rather than through structured education, emphasizing the need for better practice and mentorship.
  • Utilizing Merged PRs for Practice: Countz advocates for using merged PRs from the Rails codebase as practical exercises to improve debugging skills. The process involves:
    • Setting up a development environment linked to the Rails repository.
    • Selecting candidate PRs that focus on bug fixes.
    • Starting the debugging process independently before referring to the merged code.
  • Tools and Techniques: The speaker reviews various debugging tools such as puts debugging, Ruby debug, and the web console, emphasizing that familiarity with these tools can significantly boost debugging efficacy.
  • Empathy in Reviewing Past Work: A reminder for developers to practice empathy when analyzing the work of others in PRs, as coding can differ vastly in terms of context and complexity.

Conclusion

The talk concludes with a powerful assertion that improving debugging skills correlates with improved overall developer competence. By engaging with merged PRs, developers can grow their abilities in a low-stakes environment, harnessing community knowledge for personal improvement. Countz's message is a call to action for the Rails community to lead the way in debugging education through practical, community-driven exploration.

00:00:18.539 I hope everyone got their pastries, coffee, and so on this morning. I know this talk is right before lunch, so hopefully I can keep it brief to enable us to eat.
00:00:25.260 However, we have important topics to discuss today. We're talking about merged PRs and how they can serve as an untapped resource for practice and exploration.
00:00:31.679 I actually gave this talk another title: 'Merged PRs: Let's Talk About Debugging.' The goal is to practice debugging and build confidence by diving into the Rails codebase.
00:00:37.440 My hope is that this will help us become better Rails debuggers and developers. That's what I hope we can achieve today.
00:00:43.920 Here's the plan: we're going to start by walking through some theory behind debugging. We’ll explore the role debugging plays in the industry and identify opportunities for improving our debugging competency. After that, we'll look at how using merged PRs can enhance our competency through practice and exploration.
00:00:55.920 Before we jump in, let me share a bit about myself. I work at a company called Zendesk, where I collaborate with thousands of other engineers working in Ruby and Rails.
00:01:03.480 I am part of a core Ruby engineering team, where our job is to manage the use and abuse of Ruby and Rails within Zendesk.
00:01:09.240 I want to clarify that my role is different from that of the Rails core team or the Ruby core team; I am not part of those teams, as my work is specific to Zendesk.
00:01:16.740 One last thing to mention is that I am a community-taught developer and endlessly curious about various aspects of programming, which ties into this talk.
00:01:28.500 We'll begin by discussing the theory behind debugging. What is debugging, and what does it mean in the context of the software industry?
00:01:36.420 The ISO, IEC, and IEEE are three crucial organizations for standards, and they have a joint definition of debugging, which is "to detect, locate, and correct faults in computer software."
00:01:44.720 For our purposes, let's define faults as unexpected behavior exhibited by the software. In this talk, we’ll define debugging as the process of detecting, locating, and correcting unintended behavior in software systems.
00:01:50.580 To understand this better, I'd like to conduct a quick survey. Please raise your hand based on the percentage of your time you believe you spend on debugging tasks.
00:02:03.420 I’m specifically asking about coding time, which is separate from meetings and other activities that also take up our time.
00:02:10.320 Raise your hand if you believe you spend between 0 and 25 percent of your coding time on debugging tasks.
00:02:19.020 Okay, take a look around; it seems there are not many hands raised—perhaps around 20 people.
00:02:26.640 Next, raise your hand if you think you spend between 25 and 50 percent of your coding time debugging.
00:02:35.040 Alright, quite a few more! I'd say it's about one in three or even one in two people.
00:02:41.399 Now, how about those who spend between 50 and 75 percent of their time debugging?
00:02:51.000 Hmm, it looks to be down to just a few people. Lastly, if you spend the majority of your time debugging—75 to 100 percent—please raise your hand.
00:02:57.840 Okay, I see about three hands. It appears the majority fall within the 25 to 50 percent range.
00:03:06.660 Does anyone find that number surprising? Does it seem about what we expected?
00:03:12.660 A few of you seem surprised.
00:03:16.380 If we look back through various studies from the past few decades, we find that the average software developer spends between 35 to 50 percent, and some even upwards of 70 percent, of their time debugging.
00:03:27.180 Researchers have used both qualitative methods, like conducting surveys and interviews, and quantitative methods, such as analyzing IDE analytic data.
00:03:34.260 Broadly speaking, there is consensus that engineers generally spend a majority of their time debug.
00:03:41.220 Not only do engineers spend significant time debugging, but companies also incur substantial costs related to debugging.
00:03:51.540 A 2022 report by the Consortium for Information and Software Quality highlighted that finding and fixing deficiencies makes up the largest single expense element in the software development life cycle.
00:04:03.000 Almost 50 cents out of every dollar is spent on finding and fixing bugs that do not include other costs like damages or reputation loss associated with software bugs.
00:04:10.140 This finding made me wonder about the cost ratio of construction versus correction in other industries.
00:04:16.320 Thinking about it, if 50 cents of every dollar were spent on correction in construction, that would seem highly inefficient.
00:04:23.580 Yet, in software development, we've shifted towards iteration rather than design by committee, a model that various other industries still rely on.
00:04:29.820 It is important to note that the risk profile varies significantly between applications, such as firmware for critical medical devices and regular web applications.
00:04:37.020 What other industries consider rework and waste, we label as debugging and iterating, adopting an agile approach.
00:04:46.140 One of my favorite quotes from the early literature on debugging states that debugging is twice as hard as writing a program in the first place.
00:05:00.000 So if you’re as clever as possible when writing it, how will you ever debug it?
00:05:07.020 Debugging is a costly, yet essential, part of a software developer's experience, which underscores the importance of enhancing our debugging capabilities.
00:05:15.660 Since we dedicate so much time, effort, and resources to debugging, let's explore what it means to be proficient at it.
00:05:23.160 The practice of debugging can vary widely depending on the language, environment, or domain, but a common set of behaviors is exhibited by proficient debuggers.
00:05:35.220 I like to refer to these behaviors as debugging competencies, which include: identifying problems, reproducing issues, applying a systematic approach, comprehending code proficiently, using debugging tools effectively, communicating effectively, and learning from experience.
00:05:42.840 Let’s delve deeper into each of these competencies. The first is identifying problems, which involves recognizing and isolating issues in code based on error messages, unexpected behavior, or user reports.
00:05:51.420 For example, if our app crashes, can we determine the immediate cause by observing its state, reading error messages, analyzing stack traces, or examining crash reports?
00:05:58.320 It's the difference between saying, 'My app is broken' and asserting that 'when I enter text instead of an integer into the input field, an exception is raised due to the input parser.'
00:06:06.840 Next is the ability to reproduce issues, which is essential for understanding their root causes.
00:06:13.740 Once we've identified an error in a specific line of code or application state, we need to reproduce that error in a controlled environment.
00:06:20.820 This allows us to test our hypotheses while controlling other variables.
00:06:28.500 The third competency is applying a systematic approach, employing a structured, methodical process while debugging.
00:06:35.280 One well-cited debugging methodology comes from the book 'Why Programs Fail' by Andrea Leonelli, where he introduces a modified version of the scientific method, known as scientific debugging.
00:06:42.360 The next competency is comprehending code, which involves the ability to quickly read and understand code and develop a strong mental model of the system.
00:06:49.680 Rails conventions aid this process: if we debug an unfamiliar Rails codebase that adheres to Rails conventions, we often progress more quickly than if the app does not utilize those conventions.
00:06:59.640 The fifth competency is the proficient use of debugging tools, which involves effectively applying various techniques during the debugging process.
00:07:06.060 Interestingly, studies suggest that having confidence in just a few basic debugging methodologies like print or puts debugging can often suffice for most problems.
00:07:13.620 User-friendliness or the lack thereof is commonly a barrier preventing developers from adopting more advanced debugging tools.
00:07:20.880 Next, we discuss effective communication, which is about articulating the problem, reproduction steps, and the proposed solution to others.
00:07:27.780 We see this manifest in bug reports, pull request descriptions, and writing tests.
00:07:35.400 The final competency is learning from experience, meaning we continually enhance our debugging skills through past encounters, keeping up to date with best practices, and updating our mental models.
00:07:43.680 This is also evident when we take a localized fix for a bug in our application and submit it upstream, turning a localized solution into a global fix.
00:07:51.000 If we take a step back from the literal definition of debugging, we can see that these competencies also apply to software construction, not just debugging.
00:08:00.180 This is because debugging skills require understanding the code, its structure, and functionality, all of which are essential for software development and general programming.
00:08:06.480 This further emphasizes why debugging matters in our work as developers, and it’s why I am so excited about debugging education.
00:08:13.920 Not only is debugging costly in terms of time, effort, and money, but improving as debuggers means improving as developers.
00:08:21.960 This raises a profound question: how do developers become better debuggers?
00:08:29.760 The short answer is often by accident; most developers do not intentionally learn or train debugging skills as they do with algorithms or design patterns.
00:08:37.740 Instead, they learn through trial and error, community resources, or through informal mentorship.
00:08:44.520 This phenomenon has been the subject of research since the 1970s, indicating a long-standing gap in debugging education.
00:08:52.560 Numerous papers urge the inclusion of debugging course material in university curricula or advocate for structured learning around debugging.
00:09:00.700 However, a field study conducted as recently as 2017 revealed that many developers attribute their debugging knowledge to self-education and information gathered from the internet.
00:09:08.880 Those who did report some form of debugging education did not respond significantly differently to debugger-related questions.
00:09:15.960 On the surface, this indicates a potential problem: debugging is a crucial skill in our industry, yet it is rarely formally taught.
00:09:23.160 I propose that it isn’t more formal education we need, but rather better—if not just more—intentional practice and mentorship that provides real-world hands-on debugging experience.
00:09:30.960 To recap why developing competence in debugging is essential, consider this: debugging takes significant time.
00:09:37.020 Many of us invest a considerable portion of our time, effort, and budget on debugging, rather than on creating the code.
00:09:43.380 Furthermore, debugging incurs high costs—finding and fixing bugs is the single largest expense in the software development life cycle.
00:09:51.360 Becoming better at debugging correlates directly to improved programming competency.
00:09:58.380 Yet, I couldn’t emphasize enough how debugging is not formally taught, leaving many of us without education in this crucial area.
00:10:06.660 I’m excited that the Ruby and Rails communities have an opportunity to lead the industry with our debugging expertise, just as we have with our mastery in testing.
00:10:13.680 Now, let’s take this overarching idea and examine how it operates in practice.
00:10:20.700 This brings us to the next section: strengthening core competencies through insights from the community.
00:10:27.540 In order to add intention to our debugging practices, I'm proposing to you an exercise that utilizes merged PRs for practice and exploration.
00:10:36.360 Utilizing merged PRs for debugging practice allows us to receive immediate feedback in a low-stakes environment.
00:10:44.880 These real-world examples from the Rails codebase encourage a deeper examination of the framework than we might ordinarily undertake.
00:10:51.480 What makes this resource extremely valuable is that it already exists, and there’s no cost involved in leveraging what is already available.
00:10:57.480 The artifacts from development left behind can be utilized for either self-directed study or through guided mentorship.
00:11:05.640 Here’s how the exercise works: we start by setting up our development environment.
00:11:13.320 Then, we find a suitable candidate PR, ideally one that's a bug fix and has a clear description of the bug, with a relatively small number of lines changed.
00:11:23.040 A key aspect of this exercise is to not read the code of the PR initially—we want to begin with the description of the bug in mind.
00:11:30.720 This way, we can put our debugging skills into practice without being influenced by what we already know worked.
00:11:37.680 Next, we embark on the actual debugging process, using techniques ranging from puts and breakpoints to benchmarking and tests.
00:11:44.640 Finally, once we feel we have a solution or if we get stuck (and that’s perfectly okay), only then do we examine the patch and the code.
00:11:50.880 We then compare our solution to what was ultimately merged.
00:11:58.740 Let’s go through these steps in further detail. First, setting up our lab.
00:12:07.500 I’ll cover this section fairly quickly, assuming that most of us have our Ruby and Rails development environments set up.
00:12:14.700 Even if it might not be configured to work on the actual Rails framework, I trust we have Ruby installed and familiarized.
00:12:22.620 Also, setting up your development environment for this exercise mirrors setting up your environment for Rails.
00:12:29.820 This process is documented in the contribution guides within the Rails guide, so certainly check those out.
00:12:38.340 On a high level, there are two approaches for setting up the environment for this exercise.
00:12:45.060 In both scenarios, the first step is to fork Rails.
00:12:52.740 If you've yet to fork Rails, go ahead and click 'Fork' on GitHub to have the code available.
00:12:59.640 After forking, you have two potential approaches: you can clone the code locally and build a new Rails app using the 'dev' flag.
00:13:05.520 I will clarify what that is if you're not familiar. Alternatively, you can use GitHub Codespaces to write and run tests and utilize bug report templates.
00:13:13.980 Both of these approaches are covered in the Rails guides.
00:13:23.160 Since we’re practicing using bugs that are already fixed in main, we should ensure that we are working with the code as it existed before the PR was merged.
00:13:30.540 We accomplish this by using the SHA of the merge commit, which can be found at the bottom of the pull request once it has been merged.
00:13:38.400 We want to branch off of that merge commit's parent by using the caret symbol at the end of the SHA.
00:13:46.920 Once we branch off the parent commit, we have the code as it existed prior to the fix being merged.
00:13:54.750 To build an application from this code, we run 'bundle install' and then 'rails new' along with the dev flag.
00:14:02.970 This command will update our Gemfile by adding the path option to the Rails gem declaration, pointing to the current directory.
00:14:11.520 Thus, we want to run 'rails new' with the dev flag within the Rails directory where we cloned our fork.
00:14:19.260 After everything finishes installing and bundling, we will have an empty app as it existed when it was before the bug was fixed.
00:14:27.960 Now, we can build a Rails app like we typically would and start replicating the bug by constructing parts of the application relevant to the issue.
00:14:36.240 Another option is to use GitHub Codespaces, which allows us to develop directly in the browser or through VS Code.
00:14:43.380 This method enables us to run Rails tests seamlessly while avoiding managing all the Rails dependencies or utilizing VirtualBox.
00:14:50.520 To create a GitHub Codespace, go to github.com/codespaces, click on 'Create New Codespace,' and follow the instructions.
00:14:58.620 You will have a VS Code instance initialized directly in your browser.
00:15:06.680 If you prefer working locally, you can use the Remote Explorer extension developed by GitHub.
00:15:13.920 Regardless of the approach taken, once you have the codespace, check out the parent commit of the merge commit as we did previously.
00:15:20.580 Next, run 'bundle install,' just like we did in the previous steps. Then, we're ready to run our tests and explore.
00:15:28.920 Once our environment has been set up, we now need to find a candidate PR that we wish to use for our debugging practice.
00:15:35.310 I will admit, I found this aspect daunting at first with the sheer number of PRs available.
00:15:42.840 It felt overwhelming, as I thought it would be difficult to understand what was going on with any given PR.
00:15:50.850 Nevertheless, I discovered a few strategies for identifying well-scoped PRs that are isolated enough for practice.
00:15:58.230 First, ensure we are searching for bug fixes; luckily, not all code that goes into Rails is a bug fix; we also have new features and documentation updates.
00:16:05.220 As the Rails repository does not label bug fix PRs, we’ll need to perform a text search for terms like 'fix,' 'bug fix,' or 'regression.'
00:16:13.080 Moreover, examining linked issues is beneficial, as I find it helpful to consider the original issue the PR author addressed.
00:16:20.520 Similarly, while there’s no explicit filter for linked issues in PRs, they can be easily identified in the UI.
00:16:28.320 Next, consider focusing on particular components; each of the 12 Rails components comes with a corresponding label in the repository.
00:16:35.400 If there’s a component you're particularly interested in or one you wish to explore, you can filter PRs specifically for that component.
00:16:43.140 Next, it’s best to narrow down to PRs that involve a relatively small number of changes—around a hundred lines changed seems reasonable.
00:16:51.000 Smaller modifications generally tend to correspond to lower complexity, making practice easier.
00:16:57.720 While we can’t filter in the UI for this, the GitHub API might offer better options; I just haven’t explored that yet.
00:17:05.520 Also, consider the discussions section of the PR; numerous comments can provide insights, but PRs with a lot of discussions often indicate controversy or a need for rework.
00:17:12.780 Therefore, while engaging and informative, PRs with more limited discussions tend to be more suitable for practice.
00:17:20.460 Finally, we only want to consider PRs that have been merged, not simply closed.
00:17:27.780 The default filter in the UI shows both open and closed PRs, but importantly, the closed filter also includes merged PRs.
00:17:36.060 So, be sure to check that we’re specifically looking at merged PRs to practice with.
00:17:44.220 Admittedly, the process of finding suitable PRs is somewhat manual, but it is not without benefits.
00:17:54.060 We are compelled to read numerous PRs, which is rarely a waste of time; examining merged PRs can always offer insights.
00:18:00.900 With that said, I plan to share a comprehensive list of PRs that I’ve found to be good candidates, as well as the slides for this talk after the conference.
00:18:06.600 So keep an eye out for those resources if you’re not too thrilled at the thought of combing through numerous PRs.
00:18:14.520 Quickly, I want to share three PRs that I believe serve as excellent examples.
00:18:20.520 The first one is 'Fix Auto Increment on Primary Key for MySQL.' This PR has limited conversation, a clear problem description, just 11 lines changed, and it was recently merged.
00:18:27.240 I find value in working on PRs that have been merged recently because they often reflect code that is more relevant to our work.
00:18:35.880 The next PR is 'Fix Add Foreign Key with If Not Exists Referencing the Same Table via Different Columns.' This PR also has minimal conversation but a clear description and only 11 lines changed.
00:18:43.920 Moreover, it features a well-documented linked issue, which is helpful for understanding the context of the bug.
00:18:50.220 Finally, I wish to share a PR titled 'Add Support for Unique Constraints in PostgreSQL!' This one has substantial conversation, indicating an extensive discussion.
00:18:58.920 While it contains 531 lines changed and provides a thorough description, I do believe this larger PR may involve too much work for this type of exercise.
00:19:05.580 I envision this exercise as something akin to completing a crossword puzzle—not a task that should resemble a week’s work.
00:19:13.140 Now that our environment is set up and we’ve selected a PR to practice with, it’s time to get down to debugging.
00:19:20.400 The next section will be a lightning round of debugging tools and techniques I have been currently practicing.
00:19:28.620 This isn't an exhaustive list, but I want to provide a high-level catalog to showcase the variety we can work with.
00:19:36.420 As a quick note, I will ask for audience participation at the end of this list—if you have a tool or technique you find intriguing, I’d love for you to share it.
00:19:43.740 So, let’s get started! First up is the ever-popular puts debugging, which is widely used and often sufficient for solving issues.
00:19:51.420 If you stop here, you likely are still quite effective debugging your code.
00:19:59.520 Rails also features a built-in logger, which allows for log level adjustments, adding custom log messages, and specifying the destination for logs.
00:20:06.680 When debugging, we often log to standard output, yet there are instances when logs not going to standard output are essential.
00:20:14.040 Next, I've mentioned scientific debugging, based on Andrea Sella's methodology from his book 'How Programs Fail.'
00:20:22.320 This involves observing failures, inventing hypotheses, making predictions, testing experimentally, and repeating until we resolve the defect.
00:20:30.060 He also advocates maintaining a debugging journal.
00:20:36.600 Desk checking is another technique, which essentially means reading both the code and documentation.
00:20:43.560 Tests can also aid in debugging, as they are helpful not only for regression testing but also for validating that a bug is fixed.
00:20:50.610 You may not run all the Rails tests, but there are methods to run specific files or tests covered in the Rails guides.
00:20:58.920 Using bug report and benchmark templates from the Rails codebase is another beneficial technique.
00:21:05.370 These templates are designed to help quickly reproduce issues with minimal dependencies.
00:21:13.920 They are particularly useful when submitting a bug report or validating a bug during debugging.
00:21:21.060 The Benchmarks template is valuable as it allows us to analyze code performance and check for any regressions.
00:21:30.300 Next up is Ruby Debug, or rdbg, which is the default library for interactive debugging, enabling us to set breakpoints and navigate through our code.
00:21:39.240 Pry and Byebug offer similar features; also, rdbg has a VS Code extension that utilizes remote debugging.
00:21:46.560 A notable blog post by Justin Searles explains how to set this up with the debugging UI integrated into VS Code for Ruby and Rails.
00:21:54.090 The web console, built into Rails, lets us execute arbitrary Ruby code directly in the browser, given our application’s state.
00:22:02.160 To use it, simply install the web console gem.
00:22:10.710 Another nifty tool is 'Bundle Open,' which allows for opening the source code of a gem without cloning it.
00:22:17.160 You can edit the code in your default editor, set breakpoints, and make changes just like with your application code.
00:22:24.900 There’s also the 'git bisect' tool, which allows you to navigate through Git history to find the specific commit where a certain bug surfaced.
00:22:32.280 Source location and Kernel caller methods help efficiently understand where the method is executed and what the current stack trace looks like.
00:22:42.780 These tools assist you in pinpointing where the code is executed from and where it is defined.
00:22:52.080 We also have Parser and Ripper, which will help you interact with the abstract syntax tree of Ruby.
00:22:59.220 Note that this can be beneficial for implementing code tools, as well as any kind of automation.
00:23:05.640 Now, onto a little audience participation—does anyone have a tool or technique they want to share that I may not have covered yet?
00:23:13.560 For example, Flame Graphs?
00:23:22.380 These graphs visualize the execution stack and show where the time is being spent in your code.
00:23:29.040 Does anyone else have a suggestion? Right here?
00:23:36.060 Yes, Pry rescue! Great!
00:23:43.560 There are also tools like App Map and Stack Profiler.
00:23:51.100 The hallway track is a great place to share additional tools and experiences.
00:23:56.780 I want to emphasize that there are countless tools and resources out there, and during work, it's often the last time we try something new.
00:24:03.740 That’s why I believe these exercises are ideal for experimenting with new tools that one might not typically use.
00:24:10.540 Now, let’s cover the final section: evaluating your solution.
00:24:17.880 Once you’ve set up your environment and approached the debugging process, how do you proceed?
00:24:25.380 You can evaluate your code much like you would with a pull request. While we certainly want our code to work, this exercise focuses on enhancing debugging competencies.
00:24:33.180 I encourage you to reflect on what you learned during the debugging process and ensure you have fun.
00:24:42.420 This exercise is low-stakes and centered around learning and growth—there's always an intangible takeaway when I engage in this exercise.
00:24:49.740 It doesn’t feel necessary to conduct a formal code review—instead, it’s about exploration.
00:24:56.880 As we draw to a close, I want to mention three quick points.
00:25:03.360 First, I have not contributed to Rails; I'm just an observer at this stage, exploring the available artifacts.
00:25:12.300 My passion lies in education and growth, and I definitely aim to contribute to Rails in the future.
00:25:18.540 But for now, I’m focused on growing my understanding, which feels beneficial.
00:25:27.420 Secondly, it’s critical to remember that analyzing someone else’s past work should not be an opportunity to criticize retrospectives.
00:25:35.040 They are delivering the code while we’re pretending to be in their shoes, so practicing empathy during reviews is essential.
00:25:42.900 We began by discussing debugging theory and its significance in the software industry, including the costs associated with time, effort, and money.
00:25:52.200 We defined key competencies and realized the lack of formal education, allowing us to establish competencies that guide our growth, both personally and for others.
00:26:01.860 Lastly, we used the exercise of setting up our environment, finding merged PRs, conducting the debugging work, and evaluating our solutions.
00:26:09.069 This is the exercise: rewind time and debug Rails with many tools at your disposal, employing this self-directed exercise to explore and become familiar with Rails.
00:26:17.320 You can do this in a low-stakes environment, where you are not responsible for delivering on a deadline.
00:26:23.069 Thank you, everyone!