How to Handle WTFs
On today’s episode of Ruby Rogues we are chatting about WTFs. On our panel we’ve got Dave Carmona, Brian Hogan and I’m Charles Max Wood. We talk a bit about some of the recent WTFs we’ve encountered and some of our tricks for handling it, including talking to a Rubber Duck. It’s a fun episode so check it out!
WTF’s in Two Flavors
Charles starts out the episode inquiring to the panel about two different kinds of WTFs. The whats and the whys. WTFs that happen and developers don’t understand what the WTF is, and then on the other hand WTFs that happen and the developer doesn’t know why it’s happening.
Unreadable Perl and the Rubber Duck
David talks a bit about how hard it is sometimes to read and understand what is happening with Perl code, even if you wrote it yourself. Sometimes debugging Perl codes many years later, running into syntax errors end up being a ‘Why’ WTF. He introduces a method to use for ‘Why’ WTFs that he calls the ‘Rubber Ducky Debugging’ method. The ‘Rubber Ducky Debugging Method’ is when you place a rubber duck on your desk, and when you encounter a WTF you can simply talk through the issue to the duck to help you think through your issue. Brian and Charles add that this method works fine with real people as well and have done it many times with their wives, even for issues that don’t involve code.
Blaming it on Past Brian
Brain mentions that sometimes when working with someone else’s code, it’s easy to blame the previous developer. Unfortunately in his case, Brian finds that “Past Brian” has often been the culprit.
Dave and Code he Doesn’t Understand
When encountering classes that are really big with many different methods, find the entry point. If it doesn’t have a traditional initializer or call method for the entry point, you can look around other relevant parts of the code to try and figure it out. Sometimes if it’s obfuscated, you can go through variables and rename them to more relevant names to identify what they are doing to help understand the method at hand.
Aaron Patterson had written an article on his blog about ‘Puts debugging’ that turned Dave onto the the untraditional debugging method. Dave will sometimes write a separate debugger class to separate puts into a different log to keep it organized.
Brian’s Version of Puts Debugging
Brian mentions that when working on a rails application he will sometimes
raise the object he wants to inspect. Errors in Ruby are often something you wouldn’t expect and being able to quickly inspect the object using
raise .Using raises the whole stack including the object, session, and cookies , etc.
Dave’s Ruby Lifesavers
Dave also adds that adding the gems to your development
better_errors, and then en
binding_of_caller are lifesavers. It allows for a more interruptive session with raised errors. Also, in Rails 4 the console feature was added, allowing you to tweak things and play around to debug. Also, Pry is really useful for loop through and investigate. Dave also notes that Pry, while being a great tool, can sometimes be a bit annoying if you have a large number of loops.
Crazy Bug Story - Brian
Brian talks about how in Elixir the declaring of methods is very similar to Ruby but at the end of Elixir method calls you add keyword
do. If you do this in Ruby, the interpreter’s error message is unusual and doesn’t give any information that helps you find the issue, making it very hard to find the issue. This could be very time consuming for the debugger. He adds that having a second pair of eyes helps with issues like these.
Crazy Bug Story - David
David talks about working on a personal project late into the night. Using Rails 5.1.1, he thought that maybe his issue with the enumerators. He considered that maybe the issue was with Rails 5.1.1 being that is newer. To test to find out if he caused the error, he recreated a simple bit of code that uses enumerators and saw that it worked, then created the same project in 5.1.1 and it also worked, concluding that he created the issue. Later he found he declared the datatype for the enumerator as a string instead of an int. Brian added that creating a fresh application to test for errors is a great way to start debugging, in comparison to immediately to asking others what the problem might be. This method of checking can have a quick pay off if the code is simple. Also, creating new applications to test gives a great foundation of knowing that the problem is in your own code.
Crazy Bug Story - Charles
Charles’ bug was something he encountered in his podcast feed application he created in Rails 4. Charles didn’t read the error message very well so he tried it debugging it with Puts Debugging. It’s turned out that he was using a
strftime method that he had accidentally formatted the string wrong, using -’s instead of /’s.
Characterizing with a Test
In issues like Charles’ you can take input that’s going into a method and then setup an integration test. Tests like this can be made fairly quickly. By copying and pasting the input parameters into a test like a Capybara test, then you can get a better idea of where the issue actually is.
Creating the Error to Fix the Error
Brain mentions that sometimes when he has a specific error, he will try to write a new set of code that reproduces the issue. Then from there he will try to ‘break’ the broken code in efforts to find a debugging solution in the original code.
Making your Production Environment The Same as Your Development Environment
If you’re using something like caching in your production environment, make sure it is set up in your developmental environment. Debugging caching issues can be some of the most complicated bugs to fix. If you set up your environment to be the same it helps. If you need to start the caching over during development or tests, it’s as simple as a CLI command. When you’re doing feature tests, if you do it with caching enabled, you can use
timecop. Timecop allows you to essentially time travel to test timing issues without having to wait.
Favorite Development Tools
Some of the panelist’s favorite tools are Pry, binding_of_caller, better_errors, Konami, and Sinatra. Google Chrome’s RailsPanel extension Works like MiniProfiler, but digs in further. By adding this gem to your development environment and running it on Chrome, it shows you all the requests that come through, the controller in action, and lists out all the parameters, as well as active record calls and errors.
Favorite Production Tools
Brian suggests using any tools available to capture exceptions and error messages. Capturing these issues before the user contacts you makes recreating the issue and debugging it a lot easier. Dave mentions using New Relic to capture performance of application as well as error notification. With New Relic you can adjust the notification threshold and give it actions like sending it to a Slack channel. Then use something like Sumo Logic to concatenate and combine the logs if it’s coming from various servers.
Shipping Logs Off
FluentD can be used to ship off logs to analyze. In some cases management won’t be okay with shipping things off. Doing things internally can sometimes be too much and using a third party aggregation tools can be helpful.
Some Tools Can Be Heavy
Sumo Logic applet is Java based and takes up quite a bit of space. Jenkins is also a Java setup and takes many parameters to get running. In some cases with smaller applications, applets like Sumo Logic can take up more space than the application. Trying to parse multiple servers can be daunting and will definitely need a centralized logging option.
Other Logging Tools
Elastic.co and Logstash are other logging tools. They have integrations with tools like Docker and Kibana. If you can roll your own logging tools then great. But it’s usually time consuming and takes resources.
Getting Information from People and Assume It’s Wrong
Charles mentions that in some cases, especially in cases where something you’re using is dated, resources can be limited to get information on a bug you’re having. Brian suggests that when this happens, getting information out of people is a good place to start. Also, when getting information from people, assume that it’s wrong. People tend to have a pretty poor recollection of what happened. You can sometimes take what they say and compare it to the logs to create tests and logically work out how something has happened. Users will sometimes leave out things like accidentally leaving a field blank, or hitting backspace, or something simple. Extracting information from the users to get relevant information is a skill. Sometimes the best way to get information from a user is to just watch them use the application. Sometimes they will use the application in ways unexpected. Approaching the problem with “Let’s fix this together” helps with getting the client to help.
Getting Access with Production Data
David mentions that If there is an issue with the production side of things, pulling data down into your own database and your own separate testing environment can keep it safe while debugging. If you’re able to recreate the issue than most likely it’s an application issue, otherwise it’s something to do with the environment like caching.
Safely Percautions of Having Client Data on Your Computer
If you’re pulling data down, you should absolutely have your devices encrypted. There is no reason not to. Also when pulling data down, you can create a mirror of the data dump. There are systems that dump data that will also obfuscates or remove particular information including personal information like emails.
Troubleshooting ActionCable: Step 1 - Cry in a Corner
David tells how he was troubleshooting an Actioncable issue and his first step was to cry in a corner for 5 minutes. Afterwards he used Chrome Dev tools to trace back the code’s method where it was getting declared. Sometimes if an application is complicated it can be running many moving parts and be difficult. When debugging something complicated start at the browser level. Check for connection then try pushing a message in the console. If you get it then you’re connecting but not broadcasting. If you have a complicated subscription model for authorizing a channel, it can be even harder, again start with checking to see if it’s connecting.
tail -f | grep ‘exception’
Charles remembers a simple way to watch for issues while debugging. A simple use of
tail -f | grep ‘exception’ tails the logs and shows only the exceptions. You can use this along with Put debugging by putting the word in all your puts.
His new 5 foot long 12 plug power strip