00:00:00.840
Hello, everyone, and welcome to my session.
00:00:12.360
We're going to get started here. I just need to do one thing real quick, so please give me a moment. I'll be right with you.
00:00:24.480
All right! A great start. But look, I search for things all the time, and maybe you do too. Perhaps that's why you are here today.
00:00:34.559
Today, we're going to talk not only about the types of information we search for but also about how to search for them. As we go through this presentation, I want you to think about why you search for the things you do. I believe that understanding the reasons behind your searches can help narrow down your search criteria and assist you in finding faster resolutions.
00:00:57.180
My name is Kevin Murphy, and I'm really thankful that you're here today. I work at a company called BookBub, where we provide ebook recommendations and have an audiobook marketplace as well. By the way, we're hiring, so if you'd like to hear more about that, feel free to come find me later!
00:01:10.560
Today, I'm here to introduce you to a brand-new search engine. I perform searches so often that I decided it was unfair to rely on other people's search engines, so I wrote my own. It's called Alluvial Deposit.
00:01:25.500
Alluvial is unique from a couple of other search engines in a few particular ways. First, if you search for "Kevin Murphy," it's the only search engine where you'll actually find information about me. No other search engine can do that.
00:01:40.020
Second, Alluvial does not provide you with page after page of results. It only gives you three results. If you can't find your answer in three, you probably never needed to know it anyway. Lastly, Alluvial keeps track of your search history across devices and browsers, giving you access to every search you've performed while using it.
00:02:01.920
We'll be iterating on this feature throughout today's presentation. The first thing we will do is add timestamps so you know when you searched for something.
00:02:11.520
In our application, we will use GitHub's View Component library to help manage the presentation of this information. We'll start with a test, specifying the time we want to record for our timestamp.
00:02:24.540
We'll render our component and ensure that the date and time show up formatted as we expect, according to the design specifications.
00:02:37.920
In our view, we'll also use Rails' localized helper, the 'l' method, to format this timestamp as a string. The way this works is by defining formats in your locales file and then specifying how to format the date.
00:02:54.120
At this point, I ran into a problem because my test failed; I initially wanted it to be the actual date and time, but I didn't know the characters to enter into the locales file to format them correctly.
00:03:00.300
I do know that if I search for 'Ruby's DateTime,' I'll come across the documentation, which includes a large table with all the directives that tell me the necessary characters to format the date as desired.
00:03:14.700
After looking at the documentation, I could return to my locales file and fill it with the somewhat cryptic characters that aren't memorized but will help my test pass.
00:03:31.800
That's how I was able to proceed—by searching for the information I needed. While I might not have every detail memorized, knowing to search for 'Ruby's DateTime' helps me find the correct resources without having to memorize those specific characters.
00:03:49.740
This is a good example of how I can free up my brain space for more critical information, such as song lyrics from my middle school days. I need to retain those memories forever!
00:04:07.020
Now, I may not have searched for this using a search engine; perhaps I used a bookmarking tool or note-taking method to keep track of it. Regardless, if I want to retrieve this information later, I need some keywords to trigger that recall. In this case, those keywords are 'Ruby's DateTime.' That's how I remind myself where to go.
00:04:28.560
Next, let's iterate a bit on our component. We'll enhance its appearance. We now have fancy icons on a single line instead of two. We also want to make functional changes. Currently, if we pass 'nil' values to our component, it doesn't handle them well.
00:04:43.800
What we prefer is for it to provide placeholder text indicating that the information is unavailable, rather than causing an error. Fortunately, in our application, we have a Rails helper defined elsewhere to accomplish just that—it wraps the 'l' method to ensure a timestamp is displayed, or else it provides placeholder text.
00:05:00.000
Therefore, we need to update our existing view component to use this Rails helper instead. This should be a straightforward fix; instead of using 'l,' we'll switch to 'l_datetime.' Let's run our tests to ensure everything is working.
00:05:17.760
However, upon testing, we find that it does not work, and we are uncertain as to why, especially since we've utilized both methods in different contexts successfully.
00:05:36.960
A potential approach is to take the error message it produced and search for it directly. I recommend this as it’s often effective. It is unlikely you are the first person to encounter this problem.
00:05:55.140
Yet, here's why I'm hesitant to do that. The exception raised is a 'NoMethodError,' part of Ruby's standard library and rather generic. I've raised this error a few times before in my career, and it's exceedingly common—it won't provide tailored insights for the issue I'm addressing.
00:06:14.220
On the other hand, everything else in this error message is incredibly specific to my application. The 'l_datetime' method is defined in my app's source code, as is the datetime component that is trying (and failing) to call it.
00:06:46.680
If I were to copy this entire error message for my search, I'd likely receive results that don't address my specific issue.
00:07:02.100
Considering the issue arises from integrating a Rails helper into view components, I turned to the README for the View Component for guidance.
00:07:12.360
The README itself is quite terse, but it provides a link to documentation on a separate site, which is extensive and particularly helpful.
00:07:31.680
Since this presentation is about searching, I utilized the search box in the documentation, querying 'helper.' Fortunately, I found a thorough page covering how to access helpers from the view component.
00:07:48.420
After reading through it, I learned about the Helper Proxy it proposed. Now, instead of calling 'l_datetime,' I'll call 'helpers.l_datetime,' and with that minor adjustment, my test will pass. All of this was made possible through diligent searching.
00:08:05.640
Next, we'll implement a new feature to allow comments in our search history. Now users can leave comments about their searches, capturing their thoughts and experiences with the results they found.
00:08:22.200
As we were testing it, we clicked the 'create' button after typing a comment in the comment box and... nothing happened.
00:08:38.880
There was no feedback, no indication whether it was successful or if an error occurred. Our first step was to look at the logs, which confirmed that we issued a request to the controller to add the comment.
00:08:55.920
Upon examining the database, we found that the comment was indeed persisted, but it appears we tried to redirect somewhere else and that part of the process has failed.
00:09:10.560
This application is built on Rails 7 and uses Hotwire. We noted the requests processed as turbo streams, and being unfamiliar with Hotwire, we suspected this might be where we went wrong.
00:09:26.100
So I decided to apply the same search strategy I used earlier. I copied a message from the logs related to Turbo streams and pasted it into my search engine.
00:09:43.380
I omitted the name of the controller because that information is too specific to my application and would likely produce irrelevant results.
00:10:00.840
After my search yielded no useful information, I considered my show page might not be functioning typically. So, I checked by typing the relevant URL directly in the browser, and to my surprise, it rendered correctly.
00:10:14.520
Now, I'm faced with tracing the differences between the Turbo stream requests that failed and the HTML requests that worked.
00:10:31.920
I observed that the HTML request renders a layout, while the Turbo request does not. This led me to suspect that Turbo might not be rendering the layout.
00:10:47.520
Searching for how Turbo renders a layout proved futile as I could not find any relevant information.
00:11:02.640
Next, I turned my attention to the Turbo Rails library's issues list to see if anyone had faced similar problems. Unfortunately, I still came up empty.
00:11:20.760
Frustration began to set in, as I faced capabilities that I have accomplished many times before, and now felt obsolete as if I should relocate to a farm.
00:11:32.280
Realizing the best course of action was to step back, I took a break. I would love to say I went for a run or read a book, but I simply ate a bowl of ice cream.
00:11:50.520
After enjoying my ice cream, I returned to the computer and looked up my search history on Alluvial to see if I’ve missed something.
00:12:05.520
Even still, I felt no closer to solving my issue after taking that break.
00:12:23.280
At this point, I knew I needed a new approach. I reached out to my network, hoping for a little assistance.
00:12:34.560
Thankfully, one of my knowledgeable friends, Connor, promptly pointed out where I went wrong. The problem lay in my attempt to ask Turbo to render my 'show.erb' file.
00:12:52.740
If you are not familiar with Hotwire, it processes HTML over the wire, not ERB. This was my error—it is Hotwire, not 'Yacht wire'. I should have requested to render 'show.html.erb' instead.
00:13:06.060
I learned an important lesson: when troubleshooting, it's crucial to examine the file names and conventions instead of just hastily searching without direction. This may lead you down paths that don't solve the core issue.
00:13:22.260
Consequently, when using search to address direct problems, I highly recommend copying the exact issue you're experiencing to see if others have encountered the same problem.
00:13:40.920
If that yields no results, remember that you don’t always have to consume external sources. Instead, consult the official documentation directly for the best insights.
00:13:59.460
When faced with challenging troubleshooting situations, take a step back. You're not alone—even if you're the only developer on the project.
00:14:15.840
Thanks to Connor, we've successfully added search history comments! Users are now enthusiastically commenting on their searches.
00:14:30.420
However, we did encounter performance issues while loading the search history page, as it struggled to accommodate all those comments.
00:14:45.780
Utilizing Rack Mini Profiler, we discovered that we were executing a database query for each comment rendered on the view, leading to an 'N plus one' query problem.
00:15:04.620
To resolve this, we decided to update our controller to include the associated comments, allowing us to issue a single query to fetch all relevant comments in one go.
00:15:22.740
This optimization successfully solved our performance issue without the need for searching.
00:15:29.040
However, we weren't satisfied with just resolving the issue; we wanted to avoid it in the first place. We remembered a tool called Bullet that can alert us about potential 'N plus one' issues.
00:15:49.020
As we went to add Bullet to our Gemfile, we paused to examine whether there might be alternative solutions.
00:16:04.440
Exploring the realm of 'N plus one' detection, provided me the opportunity to learn about the 'N plus one control' gem and a blog post detailing its features.
00:16:24.960
This gem introduced me to an exciting alternative approach for optimizing query detection and resolution.
00:16:38.640
After researching, I found a new dependent option called 'destroy async' introduced in Rails 6.1 that triggers a background job to delete associated records, rather than executing it in the main request.
00:16:58.620
This revelation intrigued me, as I had never encountered this feature before. It aligned perfectly with our ongoing discussion about optimizing our search history deletion.
00:17:19.680
Incorporating such knowledge allows me to make well-informed decisions about our implementations, based on current best practices.
00:17:38.280
At the beginning of this talk, I asked you to consider why we search for specific things. For me, there are four primary reasons.
00:17:59.520
Firstly, if I've no clue how to do something, I seek wisdom from others. Secondly, I might search for something I already know how to do in search of different approaches.
00:18:05.280
As we are aware, in our industry, practices frequently evolve. Therefore, being mindful of shifts in tools, design patterns, and methodologies can be beneficial.
00:18:21.600
Possessing this understanding may save time later. Lastly, I also search for information to share with others and preserve their knowledge for future reference.
00:18:40.680
In conclusion, visiting kevinjmurphy.com/browser-history offers access to these slides, additional resources, and routes to reach out to me.
00:18:56.280
If you have questions or want to chat, please find me afterwards or during the breaks.
00:19:11.880
If you want to say hello but don't have any questions, consider sharing something you've recently solved at work through searching.
00:19:24.840
We can have a meaningful conversation based on that context.
00:19:34.320
As you continue searching for various topics, I'd encourage you to ponder why you're looking for that information. Taking just a few seconds to strategize on your search can significantly enhance your efficiency.
00:19:45.780
Ultimately, my hope is that you find exactly what you're looking for. Thank you all!