Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code Spelunking: Teach Yourself How Rails Works

Code Spelunking: Teach Yourself How Rails Works

Have you ever wondered how something works deep in the guts of Rails or been stuck when a README says one thing but the code acts another way? Guides and docs are often the best way to get started but when they fall short, you may need to get your hands dirty.

Using method introspection, this talk will show you ways to confidently explore Rails code. By looking at common problems inspired by real-world situations, learn how to dive into Rails and teach yourself how any feature works under-the-hood.

Let’s go spelunking!

Jordan Raine

May 02, 2019
Tweet

More Decks by Jordan Raine

Other Decks in Programming

Transcript

  1. <?php require( dirname(__FILE__) . '/db-config.php' ); $connection = connect_to_database($db_user, $db_password);

    $post = $connection->query("SELECT * FROM posts WHERE slug = '%".$_SLUG."%';"); ?> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <?php require( dirname(__FILE__) . '/head.php' ); ?> <body> <h1><?php $post["title"]; ?></h1> <div class="content"> <?php $post["body"]; ?> </div> </body> <?php require( dirname(__FILE__) . '/footer.php' ); ?> </html>
  2. Measuring Program Comprehension A Large-Scale Field Study with Professionals Xin

    Xia , Lingfeng Bao, David Lo , Zhenchang Xing, Ahmed E. Hassan, and Shanping Li Published 30 July 2017 ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ ̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉̉ *
  3. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 82% 5% 13%
  4. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 82% 5% 13%
  5. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 82% 5% 13%
  6. No comments or insufficient comments Meaningless classes/methods/variable names Large number

    of LOC in a class/method Inconsistent coding styles Lack of documentation, ambiguous requirements Unfamiliarity with business logic Query refinement, browsing a number of search results Navigating inheritance hierarchies Many third-party libraries Poor IDE support for code navigation Switching between editor/IDE and browser
  7. 1. Write code that is easier to use and change

    2. Improve our ability to find answers future you you
  8. $ rails new blog ! " 77 gems >250k LOC

    12 core gems 75k LOC How this was calculated: https://gist.github.com/jnraine/b0f7bb5a4a5b10ff07274389e2de83ad
  9. %w{ Symbol Slash Dot }.each do |t| class_eval <<-eoruby, __FILE__,

    __LINE__ + 1 class #{t} < Terminal; def type; :#{t.upcase}; end end eoruby end
  10. What’s the difference between try and try!? $ rails c

    Loading development environment (Rails 6.0.0) >> "something".length => 9 >> nil.length NoMethodError: undefined method `length' for nil:NilClass
  11. try(:length) try!(:length) "something" 9 9 nil nil nil What’s the

    difference between try and try!? >> "something".try!(:length) => 9 >> nil.try!(:length) => nil
  12. try(:length) try!(:length) "something" 9 9 nil nil nil What’s the

    difference between try and try!? >> "something".try!(:length)
  13. try(:length) try!(:length) "something" 9 9 nil nil nil What’s the

    difference between try and try!? >> "something".try!(:length)
  14. >> Dog.new.methods =>[:good_boy?, :name, :to_json, :deep_dup, :acts_like?, :html_safe?, :w ith_options,

    :duplicable?, :blank?, :present?, :presence, :to_yaml, :as _json, :instance_values, :instance_variable_names, :in?, :to_param, :pr esence_in, :to_query, :pretty_print_cycle, :pretty_print_instance_varia bles, :pretty_print, :pretty_print_inspect, :try, :try!, :require_or_lo ad, :load_dependency, :unloadable, :instance_variable_defined?, :remove _instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_v ariable_get, :instance_variable_set, :protected_methods, :instance_vari ables, :private_methods, :method, :public_method, :public_send, :single ton_method, :define_singleton_method, :class_eval, :pretty_inspect, :ex tend, :to_enum, :enum_for, :<=>, :===, :=~, :! ~, :gem, :eql?, :respond_to?, :byebug, :remote_byebug, :debugger, :free ze, :inspect, :object_id, :send, :to_s, :display, :class, :nil?, :hash, :dup, :singleton_class, :clone, :then, :itself, :yield_self, :untaint, :taint, :tainted?, :trust, :untrust, :untrusted?, :singleton_methods, : frozen?, :methods, :public_methods, :equal?, :!, :==, :instance_exec, :
  15. >> dog = Dog.new => #<Dog:0x00007fedbe85ba48> >> dog.method(:name) => #<Method:

    Dog#name> >> dog.method(:name).source_location => ["/spelunking/app/models/dog.rb", 2]
  16. >> dog = Dog.new => #<Dog:0x00007fedbe85ba48> >> dog.method(:name) => #<Method:

    Dog#name> >> dog.method(:name).source_location => ["/spelunking/app/models/dog.rb", 2] >> dog.method(:name).source
  17. >> dog = Dog.new => #<Dog:0x00007fedbe85ba48> >> dog.method(:name) => #<Method:

    Dog#name> >> dog.method(:name).source_location => ["/spelunking/app/models/dog.rb", 2] >> dog.method(:name).source ! gem “method_source”
  18. >> dog = Dog.new => #<Dog:0x00007fedbe85ba48> >> dog.method(:name) => #<Method:

    Dog#name> >> dog.method(:name).source_location => ["/spelunking/app/models/dog.rb", 2] >> dog.method(:name).source => " def name\n \”Foxley\"\n end\n"
  19. >> dog = Dog.new => #<Dog:0x00007fedbe85ba48> >> dog.method(:name) => #<Method:

    Dog#name> >> dog.method(:name).source_location => ["/spelunking/app/models/dog.rb", 2] >> dog.method(:name).source => " def name\n \”Foxley\"\n end\n" >> dog.method(:name).source.display def name “Foxley" end => nil
  20. >> Post.create(title: "Code spelunking") >> Post.method(:create).source.display def create(attributes = nil,

    &block) if attributes.is_a?(Array) attributes.collect { |attr| create(attr, &block) } else object = new(attributes, &block) object.save object end end => nil
  21. >> Post.create(title: "Code spelunking") >> Post.method(:create).source.display def create(attributes = nil,

    &block) if attributes.is_a?(Array) attributes.collect { |attr| create(attr, &block) } else object = new(attributes, &block) object.save object end end => nil
  22. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method ✅ ✅
  23. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method => #<Method: ActiveRecord::Validations#save> >> ✅ ✅ ✅
  24. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method => #<Method: ActiveRecord::Validations#save> >> Post.new.method(:save).super_method.super_method.super_method ✅ ✅ ✅
  25. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method => #<Method: ActiveRecord::Validations#save> >> Post.new.method(:save).super_method.super_method.super_method => #<Method: ActiveRecord::Persistence#save> >> ✅ ✅ ✅ ✅
  26. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method => #<Method: ActiveRecord::Validations#save> >> Post.new.method(:save).super_method.super_method.super_method => #<Method: ActiveRecord::Persistence#save> >> Post.new.method(:save).super_method.super_method.super_method.super_method ✅ ✅ ✅ ✅
  27. >> Post.new.save >> Post.new.method(:save) => #<Method: ActiveRecord::Suppressor#save> >> Post.new.method(:save).super_method =>

    #<Method: ActiveRecord::Transactions#save> >> Post.new.method(:save).super_method.super_method => #<Method: ActiveRecord::Validations#save> >> Post.new.method(:save).super_method.super_method.super_method => #<Method: ActiveRecord::Persistence#save> >> Post.new.method(:save).super_method.super_method.super_method.super_method => nil >> ✅ ✅ ✅ ✅
  28. What’s the difference between try and try!? >> "something".method(:try).source.display def

    try(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end => nil >>
  29. What’s the difference between try and try!? >> "something".method(:try).source.display def

    try(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end => nil >>
  30. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end
  31. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end Only read relevant code
  32. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end
  33. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end false
  34. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end
  35. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... elsif respond_to?(method_name) public_send(method_name, *args, &b) end end
  36. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... elsif respond_to?(method_name) public_send(method_name, *args, &b) end end
  37. What’s the difference between try and try!? >> "something".method(:try).source.display def

    try(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end => nil >>
  38. What’s the difference between try and try!? >> "something".method(:try).source.display def

    try(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end => nil >> nil.method(:try).source.display def try(method_name = nil, *args) nil end => nil
  39. What’s the difference between try and try!? >> "something".method(:try).source.display def

    try(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end elsif respond_to?(method_name) public_send(method_name, *args, &b) end end => nil >> nil.method(:try).source.display def try(method_name = nil, *args) nil end => nil
  40. What’s the difference between try and try!? >> "something".method(:try!).source.display def

    try!(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end => nil >>
  41. What’s the difference between try and try!? >> "something".method(:try!).source.display def

    try!(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end => nil >>
  42. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end
  43. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end
  44. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end false
  45. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end
  46. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... else public_send(method_name, *args, &b) end end
  47. def try!(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... else public_send(method_name, *args, &b) end end
  48. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... elsif respond_to?(method_name) public_send(method_name, *args, &b) end end def try!(method_name = nil, *args, &b) if method_name.nil? && block_given? # ... else public_send(method_name, *args, &b) end end
  49. def try(method_name = nil, *args, &b) if method_name.nil? && block_given?

    # ... elsif respond_to?(method_name) public_send(method_name, *args, &b) end end def try!(method_name = nil, *args, &b) if method_name.nil? && block_given? # ... else public_send(method_name, *args, &b) end end
  50. What’s the difference between try and try!? >> "something".try(:lengthhhhh) =>

    nil >> "something".try!(:lengthhhhh) NoMethodError: undefined method `lengthhhhh' for "something":String
  51. What’s the difference between try and try!? >> "something".method(:try!).source.display def

    try!(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end => nil >>
  52. What’s the difference between try and try!? >> "something".method(:try!).source.display def

    try!(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end => nil >> nil.method(:try!).source.display def try!(method_name = nil, *args) nil end => nil
  53. What’s the difference between try and try!? >> "something".method(:try!).source.display def

    try!(method_name = nil, *args, &b) if method_name.nil? && block_given? if b.arity == 0 instance_eval(&b) else yield self end else public_send(method_name, *args, &b) end end => nil >> nil.method(:try!).source.display def try!(method_name = nil, *args) nil end => nil
  54. For nil, they’re the same. For everything else, try! is

    more strict. What’s the difference between try and try!? >> "something".try(:lengthhhhh) => nil >> "something".try!(:lengthhhhh) NoMethodError: undefined method `lengthhhhh' for "something":String >> nil.try(:lengthhhh) => nil >> nil.try!(:lengthhhh)
  55. For nil, they’re the same. For everything else, try! is

    more strict. What’s the difference between try and try!? >> "something".try(:lengthhhhh) => nil >> "something".try!(:lengthhhhh) NoMethodError: undefined method `lengthhhhh' for "something":String >> nil.try(:lengthhhh) => nil
  56. 1. Ask a question What’s the difference between try and

    try!? 2. Start with what you know Look at try and try! code 3. Only read relevant code Skim 20 lines, read 6 lines
  57. We need a way to keep track of which request

    enqueued a job. Can you figure out a way to add that?
  58. class ApplicationController < ActionController::Base before_action do Current.request_id = request.id end

    end class ReportsController < ApplicationController def create ReportJob.perform_later # ... end end
  59. class ApplicationJob < ActiveJob::Base attr_accessor :request_id end class ReportJob <

    ApplicationJob queue_as :default def perform(*args) # ... puts "request_id: #{request_id.inspect}" end end
  60. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >>
  61. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_|
  62. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start request_id: nil ReportJob JID-123 INFO: done
  63. How do we add request_id to every job? $ rails

    c Loading development environment (Rails 6.0.0) >>
  64. How do we add request_id to every job? $ rails

    c Loading development environment (Rails 6.0.0) >> ReportJob.method(:perform_later).source.display
  65. How do we add request_id to every job? $ rails

    c Loading development environment (Rails 6.0.0) >> ReportJob.method(:perform_later).source.display def perform_later(*args) job_or_instantiate(*args).enqueue end => nil >>
  66. How do we add request_id to every job? $ rails

    c Loading development environment (Rails 6.0.0) >> ReportJob.method(:perform_later).source.display def perform_later(*args) job_or_instantiate(*args).enqueue end => nil >>
  67. How do we add request_id to every job? >> ReportJob.job_or_instantiate.method(:enqueue).source.display

    NoMethodError: private method `job_or_instantiate' called for ReportJob:Class from (pry):5:in `__pry__’ >>
  68. How do we add request_id to every job? >> ReportJob.job_or_instantiate.method(:enqueue).source.display

    NoMethodError: private method `job_or_instantiate' called for ReportJob:Class from (pry):5:in `__pry__’ >> ReportJob.send(:job_or_instantiate)
  69. How do we add request_id to every job? >> ReportJob.job_or_instantiate.method(:enqueue).source.display

    NoMethodError: private method `job_or_instantiate' called for ReportJob:Class from (pry):5:in `__pry__’ >> ReportJob.send(:job_or_instantiate).method(:enqueue).source.display
  70. How do we add request_id to every job? >> ReportJob.job_or_instantiate.method(:enqueue).source.display

    NoMethodError: private method `job_or_instantiate' called for ReportJob:Class from (pry):5:in `__pry__’ >> ReportJob.send(:job_or_instantiate).method(:enqueue).source.display def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end => nil
  71. How do we add request_id to every job? >> ReportJob.job_or_instantiate.method(:enqueue).source.display

    NoMethodError: private method `job_or_instantiate' called for ReportJob:Class from (pry):5:in `__pry__’ >> ReportJob.send(:job_or_instantiate).method(:enqueue).source.display def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end => nil
  72. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end
  73. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3
  74. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3
  75. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3 1 self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false 1. Variable assignment
  76. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3 1 self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false 1. Variable assignment
  77. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3 1 self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false 1. Variable assignment
  78. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3 1 self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false 1. Variable assignment
  79. def enqueue(options = {}) self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait] self.scheduled_at

    = options[:wait_until].to_f if options[:wait_until] self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] successfully_enqueued = false run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 2 3 1
  80. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 1 2 3
  81. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 2 3
  82. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 2 3
  83. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 2 3 2 2. Method with a block run_callbacks :enqueue do if scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end
  84. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 3 2
  85. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 3 2
  86. 3. Conditional if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else

    ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code " returning the instance of the job and set `config.active_job.return_false_on_ " to remove the deprecations." ) self end end
  87. 3. Conditional if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else

    ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code " returning the instance of the job and set `config.active_job.return_false_on_ " to remove the deprecations." ) self end end
  88. if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails

    6.0 will return false when the enqueuing is aborted. Make sure your code " returning the instance of the job and set `config.active_job.return_false_on_ " to remove the deprecations." ) self end end 3. Conditional
  89. if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails

    6.0 will return false when the enqueuing is aborted. Make sure your code " returning the instance of the job and set `config.active_job.return_false_on_ " to remove the deprecations." ) self end end 3. Conditional
  90. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end if successfully_enqueued self else if self.class.return_false_on_aborted_enqueue false else ActiveSupport::Deprecation.warn( "Rails 6.0 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \ " returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \ " to remove the deprecations." ) self end end end 2 3
  91. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2 3
  92. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  93. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  94. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  95. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  96. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at # ... else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  97. def enqueue(options = {}) # ... run_callbacks :enqueue do if

    scheduled_at # ... else self.class.queue_adapter.enqueue self end successfully_enqueued = true end # ... end 2
  98. How do we add request_id to every job? >> ReportJob.queue_adapter.method(:enqueue).source.display

    def enqueue(job) #:nodoc: # Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end => nil
  99. How do we add request_id to every job? >> ReportJob.queue_adapter.method(:enqueue).source.display

    def enqueue(job) #:nodoc: # Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end => nil
  100. How do we add request_id to every job? >> ReportJob.queue_adapter.method(:enqueue).source.display

    def enqueue(job) #:nodoc: # Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end => nil
  101. How do we add request_id to every job? >> ReportJob.new.method(:serialize).source.display

    def serialize { "job_class" => self.class.name, "job_id" => job_id, "provider_job_id" => provider_job_id, "queue_name" => queue_name, "priority" => priority, "arguments" => serialize_arguments_if_needed(arguments), "executions" => executions, "exception_executions" => exception_executions, "locale" => I18n.locale.to_s, "timezone" => Time.zone.try(:name), "enqueued_at" => Time.now.utc.iso8601 } end => nil >>
  102. How do we add request_id to every job? >> ReportJob.new.method(:serialize).source.display

    def serialize { "job_class" => self.class.name, "job_id" => job_id, "provider_job_id" => provider_job_id, "queue_name" => queue_name, "priority" => priority, "arguments" => serialize_arguments_if_needed(arguments), "executions" => executions, "exception_executions" => exception_executions, "locale" => I18n.locale.to_s, "timezone" => Time.zone.try(:name), "enqueued_at" => Time.now.utc.iso8601 } end => nil >>
  103. How do we add request_id to every job? >> ReportJob.new.method(:serialize).source.display

    def serialize { "job_class" => self.class.name, "job_id" => job_id, "provider_job_id" => provider_job_id, "queue_name" => queue_name, "priority" => priority, "arguments" => serialize_arguments_if_needed(arguments), "executions" => executions, "exception_executions" => exception_executions, "locale" => I18n.locale.to_s, "timezone" => Time.zone.try(:name), "enqueued_at" => Time.now.utc.iso8601 } end => nil >>
  104. How do we add request_id to every job? >> ReportJob.new.method(:serialize).source.display

    def serialize { "job_class" => self.class.name, "job_id" => job_id, "provider_job_id" => provider_job_id, "queue_name" => queue_name, "priority" => priority, "arguments" => serialize_arguments_if_needed(arguments), "executions" => executions, "exception_executions" => exception_executions, "locale" => I18n.locale.to_s, "timezone" => Time.zone.try(:name), "enqueued_at" => Time.now.utc.iso8601 } end => nil >> “request_id” => Current.request_id
  105. How do we add request_id to every job? >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.new
  106. How do we add request_id to every job? >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.new.serialize
  107. How do we add request_id to every job? >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.new.serialize["request_id"]
  108. How do we add request_id to every job? >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.new.serialize["request_id"] => "abcdef" >>
  109. >> Current.request_id = "abcdef" => "abcdef" >> ReportJob.perform_later >> m,

    `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| How do we add request_id to every job?
  110. >> Current.request_id = "abcdef" => "abcdef" >> ReportJob.perform_later >> m,

    `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start request_id: nil ReportJob JID-123 INFO: done How do we add request_id to every job?
  111. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ How do we add request_id to every job?
  112. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ How do we add request_id to every job?
  113. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ export EDITOR="code -w" # VS Code, or $ How do we add request_id to every job?
  114. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ export EDITOR="code -w" # VS Code, or $ export EDITOR="vim" # vim, or whatever you use $ How do we add request_id to every job?
  115. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ export EDITOR="code -w" # VS Code, or $ export EDITOR="vim" # vim, or whatever you use $ bundle open activejob How do we add request_id to every job?
  116. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ export EDITOR="code -w" # VS Code, or $ export EDITOR="vim" # vim, or whatever you use $ bundle open activejob How do we add request_id to every job?
  117. >> exit $ bundle open activejob To open a bundled

    gem, set $EDITOR or $BUNDLER_EDITOR $ export EDITOR="subl -w" # Sublime Text, or $ export EDITOR="code -w" # VS Code, or $ export EDITOR="vim" # vim, or whatever you use $ bundle open activejob How do we add request_id to every job?
  118. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end
  119. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3
  120. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3
  121. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3 def enqueue(job) #:nodoc: # Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end 1. enqueue method
  122. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3
  123. module ActiveJob module QueueAdapters class SidekiqAdapter # ... def enqueue_at(job,

    timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3
  124. module ActiveJob module QueueAdapters class SidekiqAdapter # ... def enqueue_at(job,

    timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 2 3
  125. module ActiveJob module QueueAdapters class SidekiqAdapter # ... def enqueue_at(job,

    timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 2 3
  126. module ActiveJob module QueueAdapters class SidekiqAdapter def enqueue(job) #:nodoc: #

    Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 1 2 3 def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end 2. enqueue_at method
  127. module ActiveJob module QueueAdapters class SidekiqAdapter # ... def enqueue_at(job,

    timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ "class" => JobWrapper, "wrapped" => job.class.to_s, "queue" => job.queue_name, "args" => [ job.serialize ], "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 2 3
  128. module ActiveJob module QueueAdapters class SidekiqAdapter # ... # ...

    class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 2 3
  129. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  130. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  131. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  132. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  133. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  134. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  135. module ActiveJob module QueueAdapters class SidekiqAdapter # ... class JobWrapper

    #:nodoc: include Sidekiq::Worker def perform(job_data) byebug Base.execute job_data.merge("provider_job_id" => jid) end end end end end 3
  136. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> How do we add request_id to every job?
  137. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job?
  138. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start
  139. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start
 [26, 35] in activejob-6.0.0.beta3/lib/active_job/queue_adapters/sidekiq_adapter.rb 26: class JobWrapper #:nodoc: 27: include Sidekiq::Worker 28: 29: def perform(job_data) 30: byebug => 31: Base.execute job_data.merge("provider_job_id" => jid) 32: end 33: end 34: end 35: end (byebug)
  140. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? [26, 35] in activejob-6.0.0.beta3/lib/active_job/queue_adapters/sidekiq_adapter.rb 26: class JobWrapper #:nodoc: 27: include Sidekiq::Worker 28: 29: def perform(job_data) 30: byebug => 31: Base.execute job_data.merge("provider_job_id" => jid) 32: end 33: end 34: end 35: end (byebug)
  141. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? [26, 35] in activejob-6.0.0.beta3/lib/active_job/queue_adapters/sidekiq_adapter.rb 26: class JobWrapper #:nodoc: 27: include Sidekiq::Worker 28: 29: def perform(job_data) 30: byebug => 31: Base.execute job_data.merge("provider_job_id" => jid) 32: end 33: end 34: end 35: end (byebug) job_data
  142. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? [26, 35] in activejob-6.0.0.beta3/lib/active_job/queue_adapters/sidekiq_adapter.rb 26: class JobWrapper #:nodoc: 27: include Sidekiq::Worker 28: 29: def perform(job_data) 30: byebug => 31: Base.execute job_data.merge("provider_job_id" => jid) 32: end 33: end 34: end 35: end (byebug) job_data { "job_class"=>"ReportJob", "job_id"=>"d13993c6-dd0f-4323-a1c3-544f2ed3b44a", "provider_job_id"=>nil, "queue_name"=>"default", "priority"=>nil,
  143. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data { "job_class"=>"ReportJob", "job_id"=>"d13993c6-dd0f-4323-a1c3-544f2ed3b44a", "provider_job_id"=>nil, "queue_name"=>"default", "priority"=>nil, "arguments"=>[], "executions"=>0, "exception_executions"=>{}, "locale"=>"en", "timezone"=>"UTC", "enqueued_at"=>"2019-04-26T01:11:19Z", "request_id"=>"abcdef" } (byebug)
  144. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data { "job_class"=>"ReportJob", "job_id"=>"d13993c6-dd0f-4323-a1c3-544f2ed3b44a", "provider_job_id"=>nil, "queue_name"=>"default", "priority"=>nil, "arguments"=>[], "executions"=>0, "exception_executions"=>{}, "locale"=>"en", "timezone"=>"UTC", "enqueued_at"=>"2019-04-26T01:11:19Z", "request_id"=>"abcdef" } (byebug) job_data["request_id"] "abcdef" (byebug)
  145. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug)
  146. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display
  147. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug)
  148. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug)
  149. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display
  150. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug)
  151. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug)
  152. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug)
  153. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug)
  154. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug) job_data["job_class"].constantize.new
  155. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display
  156. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:execute).source.display def execute(job_data) #:nodoc: ActiveJob::Callbacks.run_callbacks(:execute) do job = deserialize(job_data) job.perform_now end end nil (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"]
  157. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) Base.method(:deserialize).source.display def deserialize(job_data) job = job_data["job_class"].constantize.new job.deserialize(job_data) job end nil (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name)
  158. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name) self.enqueued_at = job_data["enqueued_at"] end nil (byebug)
  159. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name) self.enqueued_at = job_data["enqueued_at"] end nil (byebug)
  160. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name) self.enqueued_at = job_data["enqueued_at"] end nil (byebug)
  161. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name) self.enqueued_at = job_data["enqueued_at"] end nil (byebug)
  162. $ rails c Loading development environment (Rails 6.0.0) >> Current.request_id

    = "abcdef" => "abcdef" >> ReportJob.perform_later >> How do we add request_id to every job? (byebug) job_data["job_class"].constantize.new.method(:deserialize).source.display def deserialize(job_data) self.job_id = job_data["job_id"] self.provider_job_id = job_data["provider_job_id"] self.queue_name = job_data["queue_name"] self.priority = job_data["priority"] self.serialized_arguments = job_data["arguments"] self.executions = job_data["executions"] self.exception_executions = job_data["exception_executions"] self.locale = job_data["locale"] || I18n.locale.to_s self.timezone = job_data["timezone"] || Time.zone.try(:name) self.enqueued_at = job_data["enqueued_at"] end nil (byebug) self.request_id = job_data["request_id"]
  163. class ApplicationJob < ActiveJob::Base # ... def serialize super.merge("request_id" =>

    Current.request_id) end def deserialize(job_data) end end
  164. class ApplicationJob < ActiveJob::Base # ... def serialize super.merge("request_id" =>

    Current.request_id) end def deserialize(job_data) super end end
  165. class ApplicationJob < ActiveJob::Base # ... def serialize super.merge("request_id" =>

    Current.request_id) end def deserialize(job_data) super self.request_id = job_data["request_id"] end end
  166. >> Current.request_id = "abcdef" => "abcdef" >> ReportJob.perform_later >> m,

    `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| How do we add request_id to every job?
  167. By adding it to serialization and deserialization. We add request_id

    during serialization and set it during deserialization. >> Current.request_id = "abcdef" => "abcdef" >> ReportJob.perform_later >> m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start request_id: "abcdef" ReportJob JID-123 INFO: done How do we add request_id to every job?
  168. By adding it to serialization and deserialization. >> Current.request_id =

    "abcdef" => "abcdef" >> ReportJob.perform_later >> m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$bmmd$$$P^' .d$$$$$$$$$$P' $$^' `"^$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ReportJob JID-123 INFO: start request_id: "abcdef" ReportJob JID-123 INFO: done How do we add request_id to every job?
  169. 1. Ask a question How do we add request_id to

    every job? 2. Start with what you know Look at perform_later. 3. Only read relevant code Skim 100 lines, read ~50 lines
  170. 1. Ask a question How do we add request_id to

    every job? 2. Start with what you know Look at perform_later. 3. Only read relevant code Skim 100 lines, read ~50 lines
  171. 1. Ask a question How do we add request_id to

    every job? 2. Start with what you know Look at perform_later. 3. Only read relevant code Skim 100 lines, read ~50 lines
  172. https://pryrepl.org/ >> show-source "hello".empty? From: string.c (C Method): Owner: String

    Visibility: public Number of lines: 7 static VALUE rb_str_empty(VALUE str) { if (RSTRING_LEN(str) == 0) return Qtrue; return Qfalse; }
  173. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 82% 5% 13%
  174. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 82% 5% 13%
  175. Average Percentage of Time Spent by Developers 0% 25% 50%

    75% 100% Comprehension
 & Navigation Editing Other 77% 10% 13%
  176. • Donald Giannatti, Unsplash, https://unsplash.com/photos/OVLa83nRaLQ • Niklas Hamann, Unsplash, https://unsplash.com/photos/Pe4gh8a8mBY

    • By The original uploader was Minghong at English Wikipedia. - Transferred from en.wikipedia to Commons by IngerAlHaosului using CommonsHelper., CC BY-SA 3.0, https://commons.wikimedia.org/ w/index.php?curid=8922606 • Andrew Buchanan, Unsplash, https://unsplash.com/photos/Csf7vDp-Whc • Majid Rangraz, Unsplash, https://unsplash.com/photos/IPMaxeoHXi4 • Rachel, Unsplash, https://unsplash.com/photos/GGlz-QSvL38 • Rohan Makhecha, Unsplash, https://unsplash.com/photos/5fldl8eWIt0 • Eva Darron, Unsplash, https://unsplash.com/photos/oCdVtGFeDC0 • Mike Benna, Unsplash, https://unsplash.com/photos/5Cv3surFZM8 • Luc Tribolet, Unsplash, https://unsplash.com/photos/FQRxB1SimfI • Damian Zaleski, Unsplash, https://unsplash.com/photos/RYyr-k3Ysqg • Jennifer Regnier, Unsplash, https://unsplash.com/photos/sjP0USlCt10 Photo Credits