<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rémi Mercier</title>
    <description>The latest articles on DEV Community by Rémi Mercier (@mercier_remi).</description>
    <link>https://dev.to/mercier_remi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F10866%2F1f38daf2-c3e8-44fc-9411-51bc4a06f3d6.jpeg</url>
      <title>DEV Community: Rémi Mercier</title>
      <link>https://dev.to/mercier_remi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mercier_remi"/>
    <language>en</language>
    <item>
      <title>RSpec fundamentals: setup, naming and basic structure</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Tue, 09 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/mercier_remi/rspec-fundamentals-setup-naming-and-basic-structure-198a</link>
      <guid>https://dev.to/mercier_remi/rspec-fundamentals-setup-naming-and-basic-structure-198a</guid>
      <description>&lt;p&gt;When you start programming, it’s not easy to know what to test, how to test, and why should you test? You’ve probably heard that TDD (as in Test Driven Development) is THE best practice. But at first, it’s hard to know what your code should do before you’re writing it.&lt;/p&gt;

&lt;p&gt;Testing requires practice to reveal its potential.&lt;/p&gt;

&lt;p&gt;When I started programming, I’d copy other people’s tests because, well, I had to test, right? But after a while, my tests would uncover edge cases, potential bugs I’d overlooked.&lt;/p&gt;

&lt;p&gt;So, I feel a series of short know-hows, know-whats and, know-whys, could be of some use to newcomers; brief essays explaining one aspect of testing with RSpec.&lt;/p&gt;

&lt;p&gt;If this sounds fun to you, let’s start with the basics.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RSpec?
&lt;/h2&gt;

&lt;p&gt;First, let’s begin with the obvious question: what is RSpec?&lt;/p&gt;

&lt;p&gt;RSpec is a testing framework built in Ruby to test Ruby code. It focuses on testing the behavior of your program: what am I feeding my code? What do I expect to come out?&lt;/p&gt;

&lt;p&gt;It’s one of several testing frameworks available out there. You might also know Minitest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding RSpec to your application
&lt;/h2&gt;

&lt;p&gt;The RSpec team maintains a gem, making it easy to use the framework in Rails applications.&lt;/p&gt;

&lt;p&gt;First, add RSpec to your Gemfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # Gemfile

  gem "rspec-rails", group: [:development, :test]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the gem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  bundle install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaffold RSpec’s configuration and switch your application’s testing framework to RSpec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  rails generate rspec:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run your migrations and prepare your test database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  rails db:migrate &amp;amp;&amp;amp; rails db:test:prepare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There! Now, you can run your tests by typing &lt;code&gt;rspec spec&lt;/code&gt; in your shell. &lt;code&gt;spec&lt;/code&gt; is the folder where you’ll create your test files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Naming your RSpec files
&lt;/h2&gt;

&lt;p&gt;RSpec naming convention is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;users_controller.rb&lt;/code&gt; is tested by &lt;code&gt;users_controller_spec.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user.rb&lt;/code&gt; is tested by &lt;code&gt;user_spec.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_notification_job.rb&lt;/code&gt; is tested by &lt;code&gt;user_notification_job_spec.rb&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecturing your spec folder
&lt;/h2&gt;

&lt;p&gt;To make sure RSpec and Rails work smoothly together, mimick the structure of your &lt;code&gt;app&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  my_app_directory
  |
  |- app
  | |
  | |- models
  | |
  | |- user.rb
  |
  |- spec
     |
     |- models
        |
        |- user_spec.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/models/user.rb&lt;/code&gt; is tested by &lt;code&gt;spec/models/user_spec.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/serializers/admin/book_serializer.rb&lt;/code&gt; is tested by &lt;code&gt;spec/serializers/admin/book_serializer_spec.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s only one catch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/controllers/users_controller.rb&lt;/code&gt; is tested by &lt;code&gt;spec/requests/users_controller.rb&lt;/code&gt;. The RSpec team discourages you to use &lt;code&gt;spec/controllers&lt;/code&gt;. Why? Because testing requests allows you to test the behaviour of your controller’s actions through the stack (routing, request, response, etc…) versus testing the controller in isolation &lt;sup id="fnref:1"&gt;1&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for testing controllers, your folder’s structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  my_app_directory
  |
  |- app
  | |
  | |- controllers
  | |
  | |- users_controller.rb
  |
  |- spec
     |
     |- controllers ❌
     |
     |- requests
        |
        |- users_controller_spec.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The structure of your RSpec files
&lt;/h2&gt;

&lt;p&gt;Let’s say we want to test our &lt;code&gt;User&lt;/code&gt; model. Our file’s structure would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # spec/models/user_spec.rb

  require 'rails_helper'

  RSpec.describe User do
    # test stuff
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There! Your setup is done.&lt;/p&gt;

&lt;p&gt;But now, I’d like us to dig into each element so we get a better understanding of what’s going on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;require 'rails_helper'&lt;/code&gt; loads the configuration for RSpec. &lt;code&gt;rails_helper.rb&lt;/code&gt; is located at the root of the &lt;code&gt;spec&lt;/code&gt; folder. RSpec is configured out of the box so no need to worry about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RSpec&lt;/code&gt; is the core module for all RSpec code. It encapsulates and loads a lot of things on instantiation: configuration, expectations, examples, etc. You can check out the code &lt;a href="https://github.com/rspec/rspec-core/blob/main/lib/rspec/core.rb#L41"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.describe&lt;/code&gt; is a class method defined on the &lt;code&gt;RSpec&lt;/code&gt; module. It groups your tests around a common abstraction: a class, a request, etc. In the example above, our abstraction is the &lt;code&gt;User&lt;/code&gt; model.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code below is from &lt;a href="https://github.com/rspec/rspec-core/blob/fe3084758857f0714f05ada44a18f1dfe9bf7a7e/lib/rspec/core/dsl.rb#L42"&gt;the RSpec repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def self.expose_example_group_alias(name)
    return if example_group_aliases.include?(name)

    example_group_aliases &amp;lt;&amp;lt; name

    (class &amp;lt;&amp;lt; RSpec; self; end). __send__ (:define_method, name) do |*args, &amp;amp;example_group_block|
      group = RSpec::Core::ExampleGroup. __send__ (name, *args, &amp;amp;example_group_block)
      RSpec.world.record(group)
      group
    end

    expose_example_group_alias_globally(name) if exposed_globally?
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a bit hard to read because of the metaprogramming bits, but the main idea is that it defines the &lt;code&gt;.describe&lt;/code&gt; instance method in the &lt;code&gt;RSpec::Core::ExampleGroup&lt;/code&gt; class with the abstraction you’re testing (&lt;code&gt;User&lt;/code&gt;) and the tests you wrote as arguments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;User&lt;/code&gt; is the class you’re testing. It’s passed as an argument to the &lt;code&gt;.describe&lt;/code&gt; method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;do ... end&lt;/code&gt; is the block where you’re writing your tests. These will be passed as a second argument to the &lt;code&gt;.describe&lt;/code&gt; method (see &lt;code&gt;&amp;amp;example_group_block&lt;/code&gt; above).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope these explanations will give you a better understanding of how RSpec works. Next time, we’ll write our first tests.&lt;/p&gt;

&lt;p&gt;Noticed something? &lt;a href="https://twitter.com/mercier_remi"&gt;Ping me on Twitter&lt;/a&gt; or &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;create an issue on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks &lt;a href="https://twitter.com/Benoit_Tgt"&gt;@Benoit&lt;/a&gt; for pointing that out! ↩&lt;/p&gt;

</description>
      <category>rspec</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to wrap your head around a new codebase</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Sat, 13 Jun 2020 18:10:06 +0000</pubDate>
      <link>https://dev.to/mercier_remi/how-to-wrap-your-head-around-a-new-codebase-4ppj</link>
      <guid>https://dev.to/mercier_remi/how-to-wrap-your-head-around-a-new-codebase-4ppj</guid>
      <description>&lt;p&gt;For the last eighteen months, I’ve spent my time trying to understand bits of code I’d never seen before. Eighteen months later, I still don’t know every corner of this reasonably sized codebase (~300_000 lines of code). But what I do know is how to get familiar with new parts of it.&lt;/p&gt;

&lt;p&gt;So today, I’ll try and give you some tips about an understated skill: how to wrap your head around a new (part of the) codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you probably shouldn’t do
&lt;/h2&gt;

&lt;p&gt;Don’t. Be. Stubborn.&lt;/p&gt;

&lt;p&gt;That part, I’ve struggled with a lot. Stubbornness impeded the order of magnitude of my output for months.&lt;/p&gt;

&lt;p&gt;I would try to understand the code alone and knock my head on my keyboard for hours on end. Man, my ego REALLY got into the way of my learning curve.&lt;/p&gt;

&lt;p&gt;I had that same bad habit when learning Ruby. I would get to the point of self-loathing before asking teachers for help.&lt;/p&gt;

&lt;p&gt;When I finally got to teach Ruby to new developers, I saw this was a common mistake. So, ask for help early, ask for help fast.&lt;/p&gt;

&lt;p&gt;Once I identified that habit and worked on improving it, both my learning curve and my output skyrocketed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some things you could do
&lt;/h2&gt;

&lt;p&gt;The end goal for you is to get how things work, faster and more comprehensively, so you can work on improving the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you can do on our own
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Read the code you need to work with.&lt;/li&gt;
&lt;li&gt;If some things aren’t clear, take notes. Things you don’t understand can be very different: Is a whole class unclear? Is it just the syntax? Did a senior developer get overboard with their abstractions?&lt;/li&gt;
&lt;li&gt;Try and break down what’s happening: isolate each logical part, how do they interact with each other, and get a sense of the flow.&lt;/li&gt;
&lt;li&gt;If you’ve identified some gems or patterns: go and read the relevant documentation.&lt;/li&gt;
&lt;li&gt;Of course, you won’t approach a whole new codebase the same way you approach a specific part of it. The granularity of what you want to do changes whether you’re starting a new job or tackling a feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If after these steps you still feel unsure about where you should start, take a break. This is the tipping point where you’ll fall into stubborn-mode.&lt;/p&gt;

&lt;p&gt;Do you feel you’ve started to pull on a thread but still can’t quite wrap your head around it - “I’m almost there.”? Take a break. This is a tipping point too.&lt;/p&gt;

&lt;p&gt;Move on to the next stage.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you can’t do on your own
&lt;/h3&gt;

&lt;p&gt;Note that depending on your situation, some of these tips cannot be copied and pasted. You’ll sometimes need to adapt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go and ask the person responsible for the code. With them, go through the following:

&lt;ul&gt;
&lt;li&gt;Explain your research, what you understood, and what’s still unclear.&lt;/li&gt;
&lt;li&gt;Ask for a walkthrough: what’s the main goal underlying that part of the codebase, what are the interactions, why did they code things that way, etc.&lt;/li&gt;
&lt;li&gt;Get a proper set up: do you need to create test accounts with 3rd-party software? Are there any credentials you’ll need to do your work? Should you run any tasks?&lt;/li&gt;
&lt;li&gt;As your understanding grows, dig deeper for edge cases. Don’t shy away from tough questions. Your work is to improve the codebase, not stroke your colleagues’ ego.&lt;/li&gt;
&lt;li&gt;If the person responsible for the code is not here, go to the person who has the highest seniority-mentorship ability ratio. If that one is not available, go to the next person with the second highest ratio.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Some additional steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Draw things of paper: database interaction, data flow, user flow, etc…&lt;/li&gt;
&lt;li&gt;Check the data stored in the database: databases aren’t as clean as they ought to be, so check the kind of values you have there. Look out for nil values in email columns, that kind of thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;What's your favourite tips for getting familiar with a new codebase? &lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;p&gt;This post was originally published on &lt;a href="https://remimercier.com/wrap-your-head-around-new-codebase/"&gt;remimercier.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Don't sell yourself short</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Thu, 05 Mar 2020 09:09:56 +0000</pubDate>
      <link>https://dev.to/mercier_remi/don-t-sell-yourself-short-29lh</link>
      <guid>https://dev.to/mercier_remi/don-t-sell-yourself-short-29lh</guid>
      <description>&lt;p&gt;Imagine yourself back to the interview table. You've just graduated from university. Or you've just done a coding bootcamp. Maybe you're in your first two years as a developer.&lt;/p&gt;

&lt;p&gt;You are, what the market calls, a junior developer.&lt;/p&gt;

&lt;p&gt;Now, you know there's this strong belief that junior developers are a burden to their employer. It's on everyone's lips. It's on the recruiter's who's sitting in front of you. It's on your lips too.&lt;/p&gt;

&lt;p&gt;Nobody knows why. But everybody's droning on about it.&lt;/p&gt;

&lt;p&gt;Well, this is bullshit. And you're in for a raw deal.&lt;/p&gt;

&lt;h2&gt;
  
  
  "The market is tough right now" and other fallacies
&lt;/h2&gt;

&lt;p&gt;When I started looking for my first gig, many developers told me it'd be difficult.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The market is tough right now.&lt;/p&gt;

&lt;p&gt;Companies don't hire junior developers like they used to.&lt;/p&gt;

&lt;p&gt;Teams want fake juniors: technically skilled, battle-tested, unwilling to properly negotiate their comp package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, I didn't pay attention to these. But after a few weeks of meeting people, I started to have second thoughts. After all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'd never had a job title remotely related to coding.&lt;/li&gt;
&lt;li&gt;I was super picky about the team I'd joined.&lt;/li&gt;
&lt;li&gt;I have polarizing opinions (&lt;em&gt;albeit&lt;/em&gt; diplomatically expressed) and, I say "fuck" a lot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more interviews I did, the more I felt like a burden to everyone:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We'd be investing a lot of money hiring a junior developer. We wouldn't expect any return on that investment for the next 3 years.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Note how they just - unsuccessfully - tried to talk me into not asking a raise for the next three freaking years?)&lt;/p&gt;

&lt;p&gt;Then, out of all these sentences, one struck me as my escape route:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since you're a junior developer and have limited skills, we'd give you $some_amount per annum.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is was my 'aha' moment! 💡&lt;/p&gt;

&lt;p&gt;What changed? I realized that companies were only assessing my value out of my technical skills. Employers were overlooking my previous 15-ish years in the workforce and perceived me as a complete tenderfoot - &lt;a href="https://daedtech.com/junior-developer-never-accept/"&gt;something I couldn't accept&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I decided to push back, &lt;a href="https://remimercier.com/own-your-story/"&gt;own my story&lt;/a&gt;, bring attention to my full skill set, and move from the cost centers ("We'd be investing a lot of money hiring a junior developer.") to the profit centers ("Sure, come on work with us and take our money. Please?").&lt;/p&gt;

&lt;p&gt;I believe that creating value is much (much) more than increasing revenues or cutting costs. But most companies don't share that point of view.&lt;/p&gt;

&lt;blockquote&gt;
  You really want to be attached to Profit Centers because it will bring you higher wages, more respect, and greater opportunities for everything of value to you.
  &lt;cite&gt;
    @patio11
  &lt;/cite&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Show it or it doesn't exist
&lt;/h2&gt;

&lt;p&gt;Here's a list of my non-tech skills and how they affect my technical work daily.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Writing: I love writing. I love when words chime and rhythm, and take me someplace else. So I try and write code that's expressive, articulated and easy to understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Museology: After working in museums for years, I'm officially a nerd when it comes to taxonomy. This has proved handy when searching for the appropriate level of abstraction in code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Design: Studying and designing stuff throughout my life has been one of my greatest joy. It's taught me how to listen to problems, deconstruct them to first principles, and to find creative yet down-to-earth solutions. I also learned to be less domain-dependent and find inspiration everywhere. &lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Craftmanship: I worked for four years as a stained-glass master. During that time, I restored stained-glass from the 15th to the 20th century. There I nourished my love of building things, of honing the know-how, of patience and minutiae.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Entrepreneurship: Running a business for years has proved useful when dealing with employers. I can put myself into their shoes and avoid a paradox Calvin (as in Calvin and Hobbes) pointed out:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Even though we're both talking English, we're not speaking the same language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;15-ish career: Finally, working for 15 years has taught me a lot about working with people. And this proves an invaluable asset every day. Try and put a bunch of ego-loaded developers and business developers in the same room for 2 hours and see what happens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these skills, I talked about during interviews. I defended them and showed what they would bring to the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find your skills
&lt;/h2&gt;

&lt;p&gt;I can already hear you say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But Remi, I don't have any skills.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, let me prove you wrong, friend.&lt;/p&gt;

&lt;p&gt;Make time in your schedule (a couple of hours at least). Grab some pen and paper. You're ready?&lt;/p&gt;

&lt;p&gt;Now, I want you to list every fucking job you've ever done in your lifetime. Next to each entry, list every task you've done and what you learned from it.&lt;/p&gt;

&lt;p&gt;Worked in a pizza parlor? You've probably learned a lot about diplomacy, toxic managers, and being client-facing. So write it.&lt;/p&gt;

&lt;p&gt;Got the garbage out for years at your parents' house? This is dedication. Write about it.&lt;/p&gt;

&lt;p&gt;Worked on a piece of software instead of getting a CS degree? You value real-world experience over grades. Write about it.&lt;/p&gt;

&lt;p&gt;Write everything. First, this will give you a master list of your skills that you can return to. Secondly, when someone tells you you know nothing, it'll remind you that they're wrong (if only Jon Snow had made such a list).&lt;/p&gt;

&lt;p&gt;Mine is four pages long, and I add stuff on it once a year. It's always a treat to go back to it. So go and do yours now.&lt;/p&gt;

&lt;p&gt;How do you feel about it? &lt;a href="https://twitter.com/mercier_remi"&gt;Lemme me know on Twitter&lt;/a&gt;. Noticed something? &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;Create an issue on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Many thanks to the people on &lt;a href="https://dev.to/mercier_remi/unpopular-opinion-junior-devs-bring-much-more-value-to-their-employers-than-the-market-wants-them-to-believe-1fgi"&gt;dev.to&lt;/a&gt; for sharing their perspective on this topic.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Some of the design-y stuff I love: medieval stained-glass, frescoes, and architecture, the Bauhaus (hand-in-hand form and function), nature (waves building up, geological folds, forests), Fra Angelico, etc... ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>career</category>
      <category>motivation</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unpopular opinion: Junior devs bring much more value to their employers than the market wants them to believe </title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Tue, 04 Feb 2020 13:09:45 +0000</pubDate>
      <link>https://dev.to/mercier_remi/unpopular-opinion-junior-devs-bring-much-more-value-to-their-employers-than-the-market-wants-them-to-believe-1fgi</link>
      <guid>https://dev.to/mercier_remi/unpopular-opinion-junior-devs-bring-much-more-value-to-their-employers-than-the-market-wants-them-to-believe-1fgi</guid>
      <description>&lt;p&gt;I'm currently in the process of writing something about how the market wants us - junior devs - to feel we're a burden to our employers, and how I realized how this is plain wrong (as in "not true", not as in "not moral"). &lt;/p&gt;

&lt;p&gt;After reviewing the work I had done during my first nine months as a developer, I realized that the value created by my work was paying my own salary by an order of magnitude. I replayed every interview I had and realized how common this fallacy is.&lt;/p&gt;

&lt;p&gt;How do you feel about this? What is your experience with it?&lt;/p&gt;

&lt;p&gt;Value created == growing_revenues OR cutting_costs&lt;/p&gt;

</description>
      <category>healthydebate</category>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>A beginners' introduction to Ruby classes and objects</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Mon, 18 Nov 2019 13:17:30 +0000</pubDate>
      <link>https://dev.to/mercier_remi/a-beginners-introduction-to-ruby-classes-and-objects-jjc</link>
      <guid>https://dev.to/mercier_remi/a-beginners-introduction-to-ruby-classes-and-objects-jjc</guid>
      <description>&lt;p&gt;When you start learning Ruby, you often hear that everything is - or evaluates as - an object. And you're usually like "🤔 Come again"?&lt;/p&gt;

&lt;p&gt;So, here's an introduction to objects and classes in Ruby for my &lt;a href="//%7B%7Bsite.baseurl%7D%7D/own-your-story/"&gt;fellow Ruby junior developers&lt;/a&gt; out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an object?
&lt;/h2&gt;

&lt;p&gt;An object is a piece - any piece - of data (regardless of the language you're using). That's it.&lt;/p&gt;

&lt;p&gt;Some types of data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;'Hey there'&lt;/code&gt; is a string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; is an integer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;5&lt;/code&gt; is another integer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;👶&lt;/code&gt; is a baby.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[]&lt;/code&gt; is an empty array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oKxZOybq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eyna90xxvd7j3oek5r9f.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oKxZOybq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eyna90xxvd7j3oek5r9f.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Easy right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Objects and classes 101
&lt;/h2&gt;

&lt;p&gt;Now, to handle objects, Ruby creates a set of abstractions handling common behaviors for the same objects: classes.&lt;/p&gt;

&lt;p&gt;Let's dive in:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;1&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; are different integers, hence different objects.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; are both integers, so Ruby assign them the same class - the &lt;code&gt;Integer&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Integer&lt;/code&gt; class holds a specific set of methods every integer can call. Developers can then expect common patterns for different objects described by the same class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# For instance, the + method is defined in the Integer class.&lt;/span&gt;
  &lt;span class="c1"&gt;# It instantiates and returns a new integer summing the previous ones.&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's call the method &lt;code&gt;.class&lt;/code&gt; on some objects to check their Ruby class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="s1"&gt;'Hello there'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;      &lt;span class="c1"&gt;# =&amp;gt; String&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;          &lt;span class="c1"&gt;# =&amp;gt; Array&lt;/span&gt;
  &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;               &lt;span class="c1"&gt;# =&amp;gt; TrueClass&lt;/span&gt;

  &lt;span class="c1"&gt;# It even works with your own classes&lt;/span&gt;
  &lt;span class="n"&gt;wood&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:species&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;Wood&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mapple'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; Wood&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Classes as blueprints
&lt;/h2&gt;

&lt;p&gt;Classes act as blueprints: you define which data they need and what they can do with it. Then, you can create as many instances - think of instances as casts shaped from a mold - from the same blueprint.&lt;/p&gt;

&lt;p&gt;Let's create a blueprint for babies. Here's what our &lt;code&gt;Baby&lt;/code&gt; class needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some data to begin with: a DNA hash should do the trick.&lt;/li&gt;
&lt;li&gt;Some basics behaviours and capabilities.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baby&lt;/span&gt;
  &lt;span class="c1"&gt;# accessor&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:dna&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:hair_color&lt;/span&gt;

  &lt;span class="c1"&gt;# constructor&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dna&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@dna&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dna&lt;/span&gt;
    &lt;span class="vi"&gt;@hair_color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@dna&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:possible_hair_colors&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;
    &lt;span class="vi"&gt;@hungry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="vi"&gt;@dirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# behavior&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drink_milk&lt;/span&gt;
    &lt;span class="vi"&gt;@hungry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pee&lt;/span&gt;
    &lt;span class="vi"&gt;@dirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_crying?&lt;/span&gt;
    &lt;span class="vi"&gt;@hungry&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="vi"&gt;@dirty&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, I now have a blueprint for babies. It's pretty limited but here's what it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When new babies are conceived, they receive a mix of information - their DNA -, and they're both hungry and clean.&lt;/li&gt;
&lt;li&gt;In utero, babies will sample the DNA and "pick" a hair color.&lt;/li&gt;
&lt;li&gt;Once they're born, babies can drink milk and not be hungry for a while, or pee themselves and get dirty.&lt;/li&gt;
&lt;li&gt;If babies get hungry or dirty, they cry to see their need met.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A baby is an "object" whose information and behaviors are specified by a class. Different babies are different "objects" but they all share the same set of basic capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HCxAIYqg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kez7b3ubkq04445b50eh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HCxAIYqg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kez7b3ubkq04445b50eh.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's recap:&lt;/p&gt;

&lt;blockquote&gt;
  So far, we have objects categorized by classes and, whose common information types and behaviors are defined by methods.
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Objects as Object (a.k.a, the mindfuck)
&lt;/h2&gt;

&lt;p&gt;Yes, I know, it seems like I'm in for the tautology of the year. And yet, different objects can have common behaviors too!&lt;/p&gt;

&lt;p&gt;Let's take an example with the method &lt;code&gt;inspect&lt;/code&gt; which returns a human-readable representation of the object. We'll make a new baby &lt;sup id="fnref1"&gt;1&lt;/sup&gt; and print her information in my console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="go"&gt;  baby = Baby.new({possible_hair_colors: ['brownish', 'pale blonde', 'a pinch of redhead']})
  baby.inspect
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="go"&gt;  "#&amp;lt;Baby:0x00007ff2934b3150 @dirty=false, @hungry=true&amp;gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But how can &lt;code&gt;inspect&lt;/code&gt; returns anything at all since it's not defined in my &lt;code&gt;Baby&lt;/code&gt; class?  If it's not defined in &lt;code&gt;Baby&lt;/code&gt; then, where is it?&lt;/p&gt;

&lt;p&gt;To find out and pull on the thread, let's get back to our console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="go"&gt;  self.inspect                             # =&amp;gt; "main"
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="go"&gt;  self.class.inspect                       # =&amp;gt; "Object"
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="go"&gt;  Object.public_methods.include? :inspect  # =&amp;gt; true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What have I just done? I've inspected &lt;a href="//%7B%7Bsite.baseurl%7D%7D/your-new-friend-self/"&gt;the current context&lt;/a&gt; - &lt;code&gt;self&lt;/code&gt; - in which I am when I open my console. The current context is the &lt;code&gt;main&lt;/code&gt; object. And in Ruby, the &lt;code&gt;main&lt;/code&gt; object is represented by the class &lt;code&gt;Object&lt;/code&gt;. Still with me?&lt;/p&gt;

&lt;p&gt;Forget about Ruby and web development for a second. Consider this &lt;code&gt;main&lt;/code&gt; object as the mother of all objects. Every object is unique, yet they all share common patterns. For instance, they can be inspected, analyzed, etc. You can inspect integers, trees, strings, and babies all the same. Nothing stops you - if you're mentally and physically able - to submit any object to your scrutiny.&lt;/p&gt;

&lt;p&gt;Well, that's the same in Ruby. Any object can be inspected. It's a common behavior shared by all objects. And this behavior is defined in the &lt;code&gt;Object&lt;/code&gt; class with the method &lt;code&gt;#inspect&lt;/code&gt; as you can see in the third line of the console screen above.&lt;/p&gt;

&lt;blockquote&gt;
  Object is the default root of all Ruby objects. [...] Methods on Object are available to all classes unless explicitly overridden.
  &lt;cite&gt;
    &lt;a href="https://ruby-doc.org/core-2.6.5/Object.html"&gt;The Ruby doc&lt;/a&gt;
  &lt;/cite&gt;
&lt;/blockquote&gt;

&lt;p&gt;It allows Ruby to define methods at appropriate levels of abstraction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5vrMP9vJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f2lao88z18p45r9crkoz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5vrMP9vJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/f2lao88z18p45r9crkoz.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can dig deeper and check the full inheritance chain by running &lt;code&gt;Object.ancestors&lt;/code&gt; in your console. For those who want the TL;DR, &lt;code&gt;Object&lt;/code&gt; inherits from &lt;code&gt;BasicObject&lt;/code&gt; and mixes in &lt;code&gt;Kernel&lt;/code&gt;'s methods (like the &lt;code&gt;p&lt;/code&gt; method, we junior developers use everywhere to debug our code).&lt;/p&gt;

&lt;p&gt;Let's sum everything we've seen so far:&lt;/p&gt;

&lt;blockquote&gt;
  Objects are pieces of data. Different objects can relate to the same class. Classes receive and handle data in their specific way. All classes inherit from the `Object` class and its methods.
&lt;/blockquote&gt;

&lt;p&gt;Haven't lost you yet, have I? Good! Then, let's talk about the object that describes all classes: the class object and its &lt;code&gt;Class&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Still there? 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  The Class class
&lt;/h2&gt;

&lt;p&gt;When you think about it, classes are nothing more than objects. If &lt;code&gt;'Hello there'&lt;/code&gt; is a string and &lt;code&gt;1&lt;/code&gt; is an integer, &lt;code&gt;String&lt;/code&gt; is a class (i.e. a blueprint). So as an object, Ruby has given it its own class: the &lt;code&gt;Class&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Class&lt;/code&gt; inherits from &lt;code&gt;Object&lt;/code&gt; but also defines some pretty common methods. Let's see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="go"&gt;  Class.public_methods.include? :new # =&amp;gt; true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Every time you're calling &lt;code&gt;#new&lt;/code&gt; on a class you want to instantiate, you're using an instance method of the &lt;code&gt;Class&lt;/code&gt; class.  Wait, what? If &lt;code&gt;#new&lt;/code&gt; is an instance method of &lt;code&gt;Class&lt;/code&gt; and if I can call it on my own &lt;code&gt;Baby&lt;/code&gt; class too, it means that all classes are instances of the &lt;code&gt;Class&lt;/code&gt; class?&lt;/p&gt;

&lt;p&gt;That's right my friend!&lt;/p&gt;

&lt;p&gt;As an instance method of &lt;code&gt;Class&lt;/code&gt;, &lt;code&gt;#new&lt;/code&gt; is accessible by all instances of &lt;code&gt;Class&lt;/code&gt; like our &lt;code&gt;Baby&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NZdjAY-v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9vnhh108gr3b30mickdo.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NZdjAY-v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9vnhh108gr3b30mickdo.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;Baby&lt;/code&gt; class does not have a &lt;code&gt;#new&lt;/code&gt; method. And yet, I can create new babies with &lt;code&gt;Baby.new(dna)&lt;/code&gt;. It's because all classes - &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Baby&lt;/code&gt;, etc - inherit from &lt;code&gt;Class&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let me show you how it works when you define a class in your code.&lt;/p&gt;

&lt;p&gt;Writing :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Baby&lt;/span&gt;
    &lt;span class="c1"&gt;# some stuff&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;baby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Baby&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;is the same as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="no"&gt;Baby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

  &lt;span class="n"&gt;baby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Baby&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So if &lt;code&gt;Baby&lt;/code&gt; and &lt;code&gt;Class&lt;/code&gt; are both classes, they're both instances of the &lt;code&gt;Class&lt;/code&gt; class? Yep. &lt;code&gt;Class.class&lt;/code&gt; returns &lt;code&gt;Class&lt;/code&gt;. It's recursive.&lt;/p&gt;

&lt;p&gt;Let's wrap up before letting you massage away that headache of yours:&lt;/p&gt;

&lt;blockquote&gt;
  Objects are pieces of data. Different objects can relate to the same class. Classes then receive and handle data in their specific way. All classes inherit from the `Object` class and its methods. Classes share common behaviors defined in the `Class` class.
&lt;/blockquote&gt;

&lt;p&gt;I hope you enjoyed the ride as much as I did!&lt;/p&gt;

&lt;p&gt;Keep in mind that this is only an introduction. There are many broad strokes and many (more or less voluntary) omissions on my part. If you enjoyed the topic, dig deeper and report back!&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a href="https://twitter.com/nicoolas25"&gt;Nicolas&lt;/a&gt; and &lt;a href="https://twitter.com/abelar_s"&gt;Sylvain&lt;/a&gt; for reading my drafts, asking a lot of questions, and making this introduction to objects and classes (much much) better.&lt;/p&gt;

&lt;p&gt;Noticed something? Lemme know in the comments or &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;create an issue on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;p&gt;&lt;a href="https://remimercier.com/beginners-introduction-to-ruby-classes-objects/"&gt;A beginners' introduction to Ruby classes and objects&lt;/a&gt; was initially published on my blog. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;My upcoming post "How to make babies in 30 seconds thanks to Ruby", soon in your RSS feed. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How does Ruby method lookup work? 🤔</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Fri, 15 Nov 2019 09:44:48 +0000</pubDate>
      <link>https://dev.to/mercier_remi/how-does-ruby-method-lookup-work-1nkj</link>
      <guid>https://dev.to/mercier_remi/how-does-ruby-method-lookup-work-1nkj</guid>
      <description>&lt;p&gt;Salut people!&lt;/p&gt;

&lt;p&gt;I'm in the process of writing &lt;a href="https://dev.to/mercier_remi/a-beginners-introduction-to-ruby-classes-and-objects-jjc"&gt;a beginners' introduction to Ruby classes and objects&lt;/a&gt; (18th Nov update: it's live!). &lt;/p&gt;

&lt;p&gt;While talking with a friend about how classes inherit from their ancestors and the parent &lt;code&gt;Class&lt;/code&gt; class, we realized we didn't know how exactly the method lookup works in Ruby.&lt;/p&gt;

&lt;p&gt;My first (and wild) guess was: Ruby uses the &lt;code&gt;method(:some_method).owner&lt;/code&gt; then check the ancestors' chain. But can't really wrap my head around this.&lt;/p&gt;

&lt;p&gt;Anyone around here would like to have a go? 🙏&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>help</category>
      <category>explainlikeimfive</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The violence within</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Sun, 13 Oct 2019 14:16:07 +0000</pubDate>
      <link>https://dev.to/mercier_remi/the-violence-within-4b3a</link>
      <guid>https://dev.to/mercier_remi/the-violence-within-4b3a</guid>
      <description>&lt;p&gt;For the past 15 years, I've had multiple encounters with the systemic violence baked in our mainstream work culture: bullying, constant competition, harassment, mocking, productivism, racism, sexism, sticks and carrots, etc. You name it.&lt;/p&gt;

&lt;p&gt;I've spent hours talking about these heart-breaking situations with friends, lawyers, psychologists, and work inspectors. All have been witnessing a shitstorm that is destroying people from all horizons.&lt;/p&gt;

&lt;p&gt;All companies indulge in it: big corporations, public services, NGOs, etc. It's everywhere, even (especially!) in those over-hyped companies called startups.&lt;/p&gt;

&lt;p&gt;Look around you for a moment. One out of three women is sexually harassed in the workplace &lt;sup id="fnref1"&gt;1&lt;/sup&gt;. One out of two men is bullied by a supervisor &lt;sup id="fnref2"&gt;2&lt;/sup&gt;. The person you're looking at right now is likely molested as we speak.&lt;/p&gt;

&lt;p&gt;I don't know if you've been there (yet), but I have. And I refuse to feel guilty about it. I refuse to wear those traumas as a shame mark.&lt;/p&gt;

&lt;p&gt;I fell prey to &lt;a href="https://dev.to/ronsoak/the-lies-and-lack-of-self-respect-that-lead-to-burnout-5007"&gt;the lies our work culture tells us&lt;/a&gt;. And our work culture has seared its own culture of silence into our collective conscience. For a long time, I felt isolated. But no more.&lt;/p&gt;

&lt;blockquote&gt;Only sitting in a circle of women, listening to similar stories, allowed her to realize that she wasn't alone, it wasn't her fault, she could speak up. &lt;cite&gt;Gloria Steinem, My Life On The Road&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;p&gt;No matter the gender you're relating to, sitting and sharing similar stories with others can be the first step to saying "No!" to this violence. This is why I want people to speak up and talk to each other. This is why I talk about it so that people will take courage from it.&lt;/p&gt;

&lt;p&gt;Silence is playing our violent working culture's game. Silence is accepting your disappearance, literally and symbolically. Silence is dying.&lt;/p&gt;

&lt;p&gt;Talking is bonding with others. Talking is organizing and exploring new paths. Talking is living.&lt;/p&gt;

&lt;p&gt;You're not alone. Help and kindness are sometimes found when most needed. Find your circle, listen, and maybe, talk.&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;

&lt;p&gt;Want to talk? My DMs are open. Noticed something? &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;Create an issue on GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Originally published on my blog 👉 &lt;a href="https://remimercier.com/the-violence-within/"&gt;remimercier.com.&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Official studies assume that most harassments are not reported for fear of retributions. For official data (in French): &lt;a href="https://www.egalite-femmes-hommes.gouv.fr/dossiers/egalite-professionnelle/lutte-contre-le-harcelement-sexuel-au-travail/les-chiffres-cles-du-harcelement-sexuel-au-travail/"&gt;https://www.egalite-femmes-hommes.gouv.fr/dossiers/egalite-professionnelle/lutte-contre-le-harcelement-sexuel-au-travail/les-chiffres-cles-du-harcelement-sexuel-au-travail/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;See Canada's official data: &lt;a href="https://www150.statcan.gc.ca/n1/pub/75-006-x/2018001/article/54982-eng.htm"&gt;https://www150.statcan.gc.ca/n1/pub/75-006-x/2018001/article/54982-eng.htm&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>career</category>
      <category>startup</category>
    </item>
    <item>
      <title>Testing railway-oriented business transactions with Rspec</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Fri, 11 Oct 2019 12:05:19 +0000</pubDate>
      <link>https://dev.to/mercier_remi/testing-railway-oriented-business-transactions-with-rspec-d52</link>
      <guid>https://dev.to/mercier_remi/testing-railway-oriented-business-transactions-with-rspec-d52</guid>
      <description>&lt;p&gt;Railway-oriented business transactions are a great way to unclutter your Rails controllers. We've already seen how to write 'em. Now let's see how we can test 'em. I'll be using &lt;a href="https://dry-rb.org/gems/dry-transaction/"&gt;dry-transaction&lt;/a&gt; as a business transaction DSL and RSpec for testing. I'm assuming that you already have RSpec set up for your app. If not, check &lt;a href="https://everydayrails.com/"&gt;Aaron Sumner's blog&lt;/a&gt; and his book &lt;a href="https://leanpub.com/everydayrailsrspec"&gt;Everyday Rails Testing With RSpec&lt;/a&gt; to saddle up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting point: a basic transaction
&lt;/h2&gt;

&lt;p&gt;Here's a basic transaction. I'll fetch some &lt;code&gt;params&lt;/code&gt; and create a new lead. Based on the database response, I'll return either a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# app/transactions/leads/create.rb&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Leads::Create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BaseTransaction&lt;/span&gt;
    &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="ss"&gt;:params&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:create_lead&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' | '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, I want to test it. So where do I start?&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing transactions: the basics
&lt;/h2&gt;

&lt;p&gt;First, I'll create a test file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;touch &lt;/span&gt;app/transactions/leads/create_spec.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, I'll write our test bare bones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# app/transactions/leads/create_spec.rb&lt;/span&gt;

  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="s1"&gt;'Steven'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="s1"&gt;'Universe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="s1"&gt;'steven@crystalgems.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What I'm doing here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;described_class.call(params: params)&lt;/code&gt; is calling my transaction with the awaited input (&lt;code&gt;params&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subject&lt;/code&gt; is a special variable that refers to my transaction being tested&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;let(:params)&lt;/code&gt; stores the hash I'm sending to my transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Covering positive scenarios
&lt;/h2&gt;

&lt;p&gt;What should I test then? The first thing I want to test is the transaction returning a &lt;code&gt;Success&lt;/code&gt; when called with valid &lt;code&gt;params&lt;/code&gt;. From this starting point, I can check if the transaction &lt;em&gt;does&lt;/em&gt; create a &lt;code&gt;Lead&lt;/code&gt; or if this lead has the proper attributes filled in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="s1"&gt;'Steven'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="s1"&gt;'Universe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="s1"&gt;'steven@crystalgems.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="s1"&gt;'+33660606060'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'a new lead signed up with valid params'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'creates a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'return a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fills in the ad hoc fields'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="n"&gt;a_string_ending_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="n"&gt;a_string_starting_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="n"&gt;be_falsey&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here I'm using various &lt;a href="https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers"&gt;RSpec built-in matchers&lt;/a&gt; to check several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what's happening to my database when the transaction is called (with &lt;code&gt;expect { subject }.to()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;if my transaction returns a &lt;code&gt;Success&lt;/code&gt; and the content of this &lt;code&gt;Success&lt;/code&gt; (with &lt;code&gt;subject.success&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the newly created &lt;code&gt;Lead&lt;/code&gt;'s attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing for successes and failures
&lt;/h2&gt;

&lt;p&gt;Say I want to send a SMS to my new lead through an external service. Let's add a step to my transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Leads::Create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BaseTransaction&lt;/span&gt;
    &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="ss"&gt;:params&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:create_lead&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:send_welcome_sms&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' | '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_welcome_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;welcome_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Easy right? But &lt;code&gt;MySmsProvider&lt;/code&gt; only provides production-ready credentials. So how can I test &lt;code&gt;MySmsProvider&lt;/code&gt;'s different responses? RSpec allows me to mock responses.&lt;/p&gt;

&lt;p&gt;Let's start with mocking a positive response. Our basic assumptions shouldn't change because whatever steps we're adding to the transaction, it should always return a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="s1"&gt;'Steven'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="s1"&gt;'Universe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="s1"&gt;'steven@crystalgems.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="s1"&gt;'+33660606060'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'a new lead signed up with valid params'&lt;/span&gt;
      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;message_id:     &lt;/span&gt;&lt;span class="mo"&gt;01234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;body:           &lt;/span&gt;&lt;span class="s1"&gt;'Hello Steven!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;message_status: &lt;/span&gt;&lt;span class="s1"&gt;'sent'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;allow_any_instance_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:deliver_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'creates a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'return a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fills in the ad hoc fields'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="n"&gt;a_string_ending_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="n"&gt;a_string_starting_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="n"&gt;be_falsey&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But what if we want to test a negative response (i.e: Steven's phone number is invalid)?&lt;/p&gt;

&lt;p&gt;I can either add a &lt;code&gt;context&lt;/code&gt; block with specific &lt;code&gt;params&lt;/code&gt; or mock a error message from &lt;code&gt;MySmsProvider&lt;/code&gt;. I'll do the former. &lt;code&gt;context&lt;/code&gt; behaves like a sub-folder where I can inherit my test's top-level information yet change it if need be.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;described_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="s1"&gt;'Steven'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="s1"&gt;'Universe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="s1"&gt;'steven@crystalgems.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="s1"&gt;'+33660606060'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'a new lead signed up with valid params'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;message_id:     &lt;/span&gt;&lt;span class="mo"&gt;01234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;body:           &lt;/span&gt;&lt;span class="s1"&gt;'Hello Steven!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;message_status: &lt;/span&gt;&lt;span class="s1"&gt;'sent'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;allow_any_instance_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:welcome_sms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'creates a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'return a new lead'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'fills in the ad hoc fields'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="n"&gt;a_string_ending_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="n"&gt;a_string_starting_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'u'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="n"&gt;be_truthy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="n"&gt;be_falsey&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'a new lead signed up with invalid params'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;# I can redefine my params here to include a nil value that'll trigger an error with my SMS provider&lt;/span&gt;
      &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;first_name:        &lt;/span&gt;&lt;span class="s1"&gt;'Steven'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;last_name:         &lt;/span&gt;&lt;span class="s1"&gt;'Universe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;email:             &lt;/span&gt;&lt;span class="s1"&gt;'steven@crystalgems.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;phone_number:      &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;opt_in_newsletter: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_failure&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'returns an error from MySmsProvider'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deliver_sms_now&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_kind_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;REST&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RestError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the last &lt;code&gt;context 'a new lead signed up with invalid params'&lt;/code&gt;, the &lt;code&gt;before do&lt;/code&gt; block defined in the first &lt;code&gt;context&lt;/code&gt; does not apply (it's context-dependent). I've decided to trigger an error based on my input rather than mocking an error with &lt;code&gt;allow_any_instance_of&lt;/code&gt;. This way, I can decide to enforce validations at the transaction level to return a &lt;code&gt;Failure&lt;/code&gt; if some data are missing.&lt;/p&gt;

&lt;p&gt;And voilà!&lt;/p&gt;

&lt;p&gt;I hope this boilerplate will help you start testing your transactions. Noticed something? Lemme know in the comments or &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;create an issue on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;p&gt;&lt;a href="https://remimercier.com/testing-business-transactions-in-rails/"&gt;Testing railway-oriented business transactions with Rspec&lt;/a&gt; was originally published on &lt;a href="https://remimercier.com"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>rspec</category>
      <category>testing</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to use transactions to unclutter your Rails controllers</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Fri, 13 Sep 2019 11:59:26 +0000</pubDate>
      <link>https://dev.to/mercier_remi/how-to-use-transactions-to-unclutter-your-rails-controllers-9mj</link>
      <guid>https://dev.to/mercier_remi/how-to-use-transactions-to-unclutter-your-rails-controllers-9mj</guid>
      <description>&lt;p&gt;When your Rails app needs to handle multiple steps, your controllers' methods can become a mess.&lt;/p&gt;

&lt;p&gt;Don't despair, though. You can delegate sequential steps to business transactions and Marie-Kondo those messy controllers. I'll show you how.&lt;/p&gt;

&lt;p&gt;Let's keep in mind that business transactions are different from ActiveRecord transactions. Business transactions allow you to create a series of steps, each resulting in a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt; object. ActiveRecord transactions are about ensuring that several database operations work as a single unit and are all rollbacked if any error occurs.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll use the &lt;a href="https://github.com/dry-rb/dry-transaction/"&gt;dry-transaction gem&lt;/a&gt; whose documentation is neat.&lt;/p&gt;

&lt;h2&gt;
  
  
  From clean to messy controllers in no time
&lt;/h2&gt;

&lt;p&gt;Let's start with coding a basic controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
      &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:new&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;lead_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lead_params&lt;/span&gt;
      &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Okay, so here's a basic &lt;code&gt;LeadsController&lt;/code&gt;. You have two actions: &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;create&lt;/code&gt;. As you can see, the &lt;code&gt;create&lt;/code&gt; method is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I create a new lead with the information filled by our lead.&lt;/li&gt;
&lt;li&gt;I handle any errors by rendering the &lt;code&gt;leads/new&lt;/code&gt; form prefilled with the information our current lead already gave us.&lt;/li&gt;
&lt;li&gt;If everything goes well, I redirect our lead to her profile page (or any page of my choosing).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what if I want to do more? Let's say I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connect to a distant CRM &lt;a href="https://remimercier.com/what-is-an-api/"&gt;through an API&lt;/a&gt; and synchronize the lead's information with my sales team&lt;/li&gt;
&lt;li&gt;send a welcome text and an email to the lead&lt;/li&gt;
&lt;li&gt;notify someone in my team
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
      &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:new&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="c1"&gt;# synchronize new lead to distant CRM&lt;/span&gt;
        &lt;span class="no"&gt;MyDistantCrm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# send welcome sms and email to new lead&lt;/span&gt;
        &lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;welcome_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;
        &lt;span class="no"&gt;LeadMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;welcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;

        &lt;span class="c1"&gt;# notify business developer&lt;/span&gt;
        &lt;span class="no"&gt;BusinessDevelopperMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;

        &lt;span class="c1"&gt;# redirect new leads to their profile page&lt;/span&gt;
        &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;lead_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# rescue any error to avoid a 500 error&lt;/span&gt;
      &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
        &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lead_params&lt;/span&gt;
      &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, there are several new steps doing very different things. In a real-life app, we could do a lot more than that: create associations, generate SKU numbers, etc. The other thing is that all these steps are dependent on the &lt;code&gt;lead&lt;/code&gt; being created without any errors. This puts a lot of stuff into an &lt;code&gt;else&lt;/code&gt; branch. This is where business transactions can come in handy.&lt;/p&gt;

&lt;p&gt;Let's see how to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transactions to the rescue
&lt;/h2&gt;

&lt;p&gt;Let's set up dry-transaction and see how we can unclutter our controller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install dry-transaction
&lt;/h3&gt;

&lt;p&gt;Add this line to your application's Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  gem &lt;span class="s1"&gt;'dry-transaction'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: General principles
&lt;/h3&gt;

&lt;p&gt;Before we dive into moving parts of our &lt;code&gt;LeadsController#create&lt;/code&gt; into a transaction, let's look at a transaction file to see what's what.&lt;/p&gt;

&lt;blockquote&gt;A business transaction is a series of operations where any can fail and stop the processing.&lt;/blockquote&gt;

&lt;p&gt;Each step is processed one at a time and must return either a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Leads::Create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BaseTransaction&lt;/span&gt;
    &lt;span class="c1"&gt;# Here, I define the operation sequence&lt;/span&gt;
    &lt;span class="n"&gt;tee&lt;/span&gt; &lt;span class="ss"&gt;:params&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:create_lead&lt;/span&gt;

    &lt;span class="c1"&gt;# Here, I define each operation&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' | '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here are a few points to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tee&lt;/code&gt; is a specific kind of step. It'll always return a &lt;code&gt;Success&lt;/code&gt;. This is fine here because I'm simply fetching an input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;step&lt;/code&gt; is the basic operation. It'll have to return either a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@params&lt;/code&gt; will be available to all other steps or methods of my transaction when &lt;code&gt;lead&lt;/code&gt; will not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Move the controller's logic into the transaction
&lt;/h3&gt;

&lt;p&gt;Now, we can move parts of our &lt;code&gt;LeadsController#create&lt;/code&gt; into a transaction.&lt;/p&gt;

&lt;p&gt;My app's architecture was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  - app
    - controllers
      - application_controller.rb
      - leads_controller.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At the end of this tutorial, it'll be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  - app
    - controllers
      - application_controller.rb
      - leads_controller.rb
    - transactions
      - base_transaction.rb
      - leads
        - create.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's build &lt;code&gt;base_transaction.rb&lt;/code&gt; first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseTransaction&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Dry&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Transaction&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;def self.call(*args, &amp;amp;block)&lt;/code&gt; will allow us to &lt;strong&gt;call&lt;/strong&gt; the transaction from our controllers with a hash of arguments.&lt;/p&gt;

&lt;p&gt;I'll start with the transaction we started earlier and I'll move parts of our &lt;code&gt;LeadsController#create&lt;/code&gt; into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Leads::Create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BaseTransaction&lt;/span&gt;
    &lt;span class="n"&gt;tee&lt;/span&gt; &lt;span class="ss"&gt;:params&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:create_lead&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:create_distant_lead&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:send_welcome_sms&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:send_welcome_email&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:notify_business_developper&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
        &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' | '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_distant_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;MyDistantCrm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_welcome_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;MySmsProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;welcome_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;

      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_welcome_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;LeadMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;welcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;

      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_business_developper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;BusinessDevelopperMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new_lead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;deliver_now&lt;/span&gt;

      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All of my &lt;code&gt;LeadsController#create&lt;/code&gt; steps are now in my transaction.&lt;/p&gt;

&lt;p&gt;Each operation handles its own errors and return a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For instance, if my &lt;code&gt;MySmsProvider.welcome_sms(@lead).deliver_now&lt;/code&gt; returns an error, my transaction will not execute the next steps and will return a &lt;code&gt;Failure&lt;/code&gt; so I know that something went wrong here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Call the transaction and handle its results
&lt;/h3&gt;

&lt;p&gt;Now that all my steps are in my transaction, what should I do with my controller? We'll start by calling the transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
      &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lead_params&lt;/span&gt;
      &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Neat right?&lt;/p&gt;

&lt;blockquote&gt;Calling a transaction will run its operations in their specified order, with the output of each operation becoming the input for the next.&lt;/blockquote&gt;

&lt;p&gt;As I said before, a transaction either returns a &lt;code&gt;Success&lt;/code&gt; or a &lt;code&gt;Failure&lt;/code&gt; object. I can handle these results in the controller.&lt;/p&gt;

&lt;p&gt;In our original controller, I would render the &lt;code&gt;new&lt;/code&gt; form if the lead creation failed. On the other hand, if the creation succeeded, I'd redirect my new lead to its profile. Let's do this now!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;
      &lt;span class="vi"&gt;@lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
      &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;lead_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:new&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lead_params&lt;/span&gt;
      &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:lead&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, my controller only handles calls to a grouped set of business operations. No more database operations mingling with sending out emails or redirection rules. There is some cohesiveness in the abstraction.&lt;/p&gt;

&lt;p&gt;This is it!&lt;/p&gt;

&lt;p&gt;Y'all go and checkout &lt;a href="https://dry-rb.org/gems/dry-transaction/"&gt;dry-transaction's documentation&lt;/a&gt; and do not hesitate &lt;a href="https://github.com/dry-rb/dry-transaction/"&gt;to read the source code&lt;/a&gt; for more magic!&lt;/p&gt;

&lt;p&gt;If you have any questions or if something is not clear enough, &lt;a href="https://twitter.com/mercier_remi"&gt;ping me on Twitter&lt;/a&gt; or &lt;a href="https://github.com/merciremi/remicodes/issues/new"&gt;create an issue on GitHub&lt;/a&gt; so we can make this tutorial better.&lt;/p&gt;

&lt;p&gt;Next time, I'll show you how to test your transactions.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;p&gt;&lt;a href="https://remimercier.com/transactions-in-rails/"&gt;How to use transactions to unclutter your Rails controllers&lt;/a&gt; was originally published on &lt;a href="https://remimercier.com"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What does PHP stand for?</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Wed, 03 Jul 2019 15:38:35 +0000</pubDate>
      <link>https://dev.to/mercier_remi/what-does-php-stand-for-195</link>
      <guid>https://dev.to/mercier_remi/what-does-php-stand-for-195</guid>
      <description>&lt;h1&gt;
  
  
  👏 People
&lt;/h1&gt;

&lt;h1&gt;
  
  
  👏 Hate
&lt;/h1&gt;

&lt;h1&gt;
  
  
  👏 PHP
&lt;/h1&gt;




&lt;p&gt;This had me rolling under the table a while back. 😄&lt;/p&gt;

</description>
      <category>jokes</category>
      <category>php</category>
    </item>
    <item>
      <title>What is an API?</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Thu, 23 May 2019 13:08:17 +0000</pubDate>
      <link>https://dev.to/mercier_remi/what-is-an-api-4ao9</link>
      <guid>https://dev.to/mercier_remi/what-is-an-api-4ao9</guid>
      <description>&lt;p&gt;Feeling queasy about explaining APIs to your grandma 👵 or a non-technical client 👔? Lemme help you out! &lt;/p&gt;

&lt;p&gt;Before we start, I’d like to ask you a few questions. Do you know how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://authenticweather.com/"&gt;Authentic Weather&lt;/a&gt; knows the weather it’ll be doing during your upcoming trip to Dunkirk?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.thetrainline.com/"&gt;Trainline&lt;/a&gt; knows if a seat is available (of that very same upcoming trip to Dunkirk)?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.airbnb.com/"&gt;Airbnb&lt;/a&gt; puts available flats on a map (do I even need to say “of Dunkirk”)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--05WLsQiF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remimercier.com/media/2017/what-is-an-api-remi-mercier.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--05WLsQiF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://remimercier.com/media/2017/what-is-an-api-remi-mercier.gif" alt="man's brain exploding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These past few years, APIs (also known as Application Programming Interfaces) have spread like wildfire in the startup growth game.&lt;/p&gt;

&lt;p&gt;To quote &lt;a href="https://twitter.com/paulrb_r"&gt;Paul Bonaud&lt;/a&gt;, back-end engineer at &lt;a href="https://twitter.com/trainline_fr"&gt;@trainline_fr&lt;/a&gt; (formerly Captain-Train):&lt;/p&gt;

&lt;blockquote&gt;
  APIs, quite an interesting and vast subject, isn’t it?
&lt;/blockquote&gt;

&lt;p&gt;Wrapping your head around APIs can be challenging for non-technical users. What’s an API? What can be shared through an API? Data? Services? How does one design an API? How do you code an API?&lt;/p&gt;

&lt;p&gt;Because I asked myself all of these questions (and many more), I’ve decided that it was time to get a better understanding of what APIs are all about. It’s a bit scary though - especially when you come from a non-technical background - but I’m sure people will find it entertaining. I plan on writing about various topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what’s an API?&lt;/li&gt;
&lt;li&gt;how does it work?&lt;/li&gt;
&lt;li&gt;who’s using it?&lt;/li&gt;
&lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But let’s start from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an API?
&lt;/h2&gt;

&lt;p&gt;APIs - or Application Programming Interfaces - are defined as a set of functions (a coded procedure performing a particular task) through which two software can talk to each other without any human intermediation. An API is an abstracted point of entry to a piece of software with a description of the open interface and its behavior.&lt;/p&gt;

&lt;p&gt;Let’s break that acronym down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt;: By application, we mean a service with which a developer wants to interact. This service can be a stream of meteorological data, an image sharing app or an open data portal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface&lt;/strong&gt;: The interface is the entry door to the service. You have to go through that door to interact with the service capabilities (e.g., filtering meteorological data for a city, publishing pictures on Instagram…)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program&lt;/strong&gt;: The program is a set of coded procedures written by a developer. The program is designed to interact with the application, so we don’t have to. For example, the program can submit a postal address to get coordinates (think Airbnb or Google Map).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gpyrxvd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remimercier.com/media/2017/what-is-an-api-diagram-remi-mercier.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gpyrxvd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://remimercier.com/media/2017/what-is-an-api-diagram-remi-mercier.png" alt="api diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To sum it up: APIs are programs using a specific point of entry (the interface, also call an end-point) to interact with an application (or some features within this application).&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok, but what does an API do?
&lt;/h2&gt;

&lt;p&gt;Nowadays, APIs are well covered. You’ll find lots of articles about the “Greatest XXX APIs every developer need to know.” But the very basics of APIs are not concisely explained and still elude non-technical users.&lt;/p&gt;

&lt;p&gt;An API allows a developer to access a service. One usually says that an API exposes a service.&lt;/p&gt;

&lt;p&gt;We’ve seen it above; the service can come in many shapes and forms: real-time data streams (e.g., Twitter), maps (OpenStreetMap), publishing a picture (Instagram).&lt;/p&gt;

&lt;p&gt;Developers write programs that consume these APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  APIs can be used in various environments:
&lt;/h3&gt;

&lt;p&gt;👉 In a closed environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to mutualize your company data across departments’ lines&lt;/li&gt;
&lt;li&gt;to expose a database’s serialization made from multiple data sources&lt;/li&gt;
&lt;li&gt;to test an API in a secure environment before releasing it publicly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 In an open environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expose data to the world: think open data portals&lt;/li&gt;
&lt;li&gt;allow other companies to offer their services within your application: think Giphy integration in Slack, Zapier…&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let's try a metaphor
&lt;/h3&gt;

&lt;p&gt;Metaphors can be tricky when it comes to technological matters. But the gist of APIs can easily be understood using the electricity network as a proxy.&lt;/p&gt;

&lt;p&gt;Let’s start with an electricity supplier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this supplier produces and distributes a service: electricity&lt;/li&gt;
&lt;li&gt;to distribute this service, the supplier relies on infrastructure: the electric network (stations, transmission lines, utility poles, sockets)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s take a lamp that needs to consume electricity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for the lamp to work, it needs to be connected to the electric grid&lt;/li&gt;
&lt;li&gt;to be connected, the lamp is sold with a plug that fits standards sockets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The socket is a standardized point of entry (an interface) through which a lamp consumes electricity. An API is a standardized point of entry (an interface) through which a program consumes an application.&lt;/p&gt;

&lt;p&gt;APIs allow developers to delegate a service they need to consume. In the same way, the lamp’s owner delegates the electricity needed by her lamp to the electricity supplier.&lt;/p&gt;

&lt;p&gt;Let’s dig further. APIs and electrical sockets both specify how the user can consume the service. Remember our lamp? It needs to respect some conditions for using the service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the number and shape of the pins&lt;/li&gt;
&lt;li&gt;voltage and frequency&lt;/li&gt;
&lt;li&gt;type of current&lt;/li&gt;
&lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;APIs will do the same and specify conditions to use them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;number of API calls for a defined lap of time&lt;/li&gt;
&lt;li&gt;what you can expect to do: read and/or write&lt;/li&gt;
&lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to the standardization of sockets, you can plug several lamps in your home without thinking twice about it. What matters is that every socket is functionally similar: it brings electricity right into your home.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APIs and sockets are abstractions for the service they expose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wait, what? Abstractions? 🤔&lt;/p&gt;

&lt;p&gt;They hide the nitty-gritty of the service the customer uses.&lt;/p&gt;

&lt;p&gt;Without sockets, you’d need to twist your lamp’s wires around those sticking out of your wall. Lamps don’t give a dime about the details of the electrical grid. They work whether the electricity comes from solar panels or wind turbines; whether the cables within the wall are black, red or pink; whether other lamps are plugged into the network or not. As long as the electricity supplier provides the lamp with its functional needs (AC and 110 volts if you live in the US), the supplier can modify its network at will. Without this abstraction, you’d need to wrap your lamp’s wires around the wires in the wall.&lt;/p&gt;

&lt;p&gt;The abstraction works the other way round. The electric grid doesn’t care about the design of your lamp. Whether your lamp is designed by Ikea or &lt;a href="http://www.tecnolumen.com/12/Wilhelm-Wagenfeld-Table-lamp.htm"&gt;Wilhelm Wagenfeld&lt;/a&gt;, the grid only cares about the plug fitting the socket. Electricity flows from the station to your socket even if no lamps are plugged in it.&lt;/p&gt;

&lt;p&gt;APIs work the same way.&lt;/p&gt;

&lt;p&gt;Without APIs, Authentic Weather would need to weather.com’s data on a regular basis (or any other meteorological data provider). Thanks to APIs, Authentic Weather doesn’t care about the nitty-gritty of the meteorological data it receives every second. As long as the data stream (accessible through the API) is functionally stable, Authentic Weather is happy (and its users are happy).&lt;/p&gt;

&lt;p&gt;The abstraction works the other way round. weather.com’s API doesn’t care about your app’s color scheme. As long as your app consumes the API within the pre-defined conditions, it’s 👌.&lt;/p&gt;




&lt;p&gt;Was this helpful? Lemme know in the comments or on &lt;a href="https://twitter.com/mercier_remi"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>api</category>
      <category>beginners</category>
      <category>explainlikeimfive</category>
    </item>
    <item>
      <title>Meet your new friend: self</title>
      <dc:creator>Rémi Mercier</dc:creator>
      <pubDate>Wed, 20 Mar 2019 20:19:58 +0000</pubDate>
      <link>https://dev.to/mercier_remi/meet-your-new-friend-self-36cl</link>
      <guid>https://dev.to/mercier_remi/meet-your-new-friend-self-36cl</guid>
      <description>&lt;p&gt;When coding, it's not always easy to know what's what. Why can't I call that method on this array? When in a method, what am I working with exactly? In these cases, &lt;code&gt;self&lt;/code&gt; can prove a super-duper friend!&lt;/p&gt;

&lt;p&gt;Even if you're a junior developer, you've probably come across &lt;code&gt;self&lt;/code&gt; in class methods definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_the_class&lt;/span&gt;
    &lt;span class="s2"&gt;"👋 from the class method."&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_the_class&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "👋 from the class method."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But that usually it.&lt;/p&gt;

&lt;p&gt;Now, &lt;code&gt;self&lt;/code&gt; can also come in handy when your understanding of what's going on is a bit muddy. Let's code something!&lt;/p&gt;

&lt;p&gt;Say I want to recode the &lt;code&gt;.map&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# Native method&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; [2, 4, 6]&lt;/span&gt;

  &lt;span class="c1"&gt;# Let's write our own!&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First thing I'll do is to start by defining &lt;code&gt;.my_map&lt;/code&gt; and have it output something nice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="s2"&gt;"Hello from my_map"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What I expect, when running this code, is to get &lt;code&gt;"Hello from my_map"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  NoMethodError: private method &lt;span class="sb"&gt;`&lt;/span&gt;.my_map&lt;span class="sb"&gt;`&lt;/span&gt; called &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;1, 2, 3]:Array
  from &lt;span class="o"&gt;(&lt;/span&gt;pry&lt;span class="o"&gt;)&lt;/span&gt;:8:in &lt;span class="sb"&gt;`&lt;/span&gt;&amp;lt;main&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;🤔 Duh.&lt;/p&gt;

&lt;p&gt;What does it mean by private method? Let's output our current context (i.e. where the hell we are) with &lt;code&gt;self&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s2"&gt;"Where are in: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="s2"&gt;"Hello from my_map"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "Where are in: main"
  NoMethodError: private method `my_map` called for [1, 2, 3]:Array
  from (pry):8:in `&amp;lt;main&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main&lt;/code&gt; means that we currently are in the context of the Object object. Remember when you were told that all things in Ruby are objects? Well, even Object is an object.&lt;/p&gt;

&lt;p&gt;Ruby top classes (or objects) are BasicObject &amp;gt; Kernel &amp;gt; Object.&lt;/p&gt;

&lt;p&gt;BasicObject is the parent class of all classes in Ruby. Basic methods like &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;equal?&lt;/code&gt; are defined there. Kernel is a module with basics public/private methods like &lt;code&gt;puts&lt;/code&gt;, &lt;code&gt;gets&lt;/code&gt; or &lt;code&gt;chomp&lt;/code&gt;. Object inherits from BasicObject and mixes in the Kernel module for good measure. All other Ruby objects inherit from Object. This way, Ruby objects get tons of methods, the latter being defined at the appropriate level of abstraction. Some methods from Object include: &lt;code&gt;to_s&lt;/code&gt; or &lt;code&gt;nil?&lt;/code&gt;. Fancy right?&lt;/p&gt;

&lt;p&gt;Ok, but what about that &lt;code&gt;NoMethodError&lt;/code&gt; of mine?&lt;/p&gt;

&lt;p&gt;Here's my mistake: I've forgotten to write &lt;code&gt;.my_map&lt;/code&gt; in a class. So it's been defined in the Object object by default. And yet, I'm trying to call &lt;code&gt;.my_map&lt;/code&gt; on an array.&lt;/p&gt;

&lt;p&gt;In order to call &lt;code&gt;.my_map&lt;/code&gt; on an array, I need to open and define it in the Array class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s2"&gt;"Where are in: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="s2"&gt;"Hello from my_map"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  Where are &lt;span class="k"&gt;in&lt;/span&gt;: Array
  Hello from my_map
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;👏 It works! Classes in Ruby can be opened and modified. Now that I've defined &lt;code&gt;.my_map&lt;/code&gt; inside the Array class, I can call it on arrays. Easy peasy!&lt;/p&gt;

&lt;p&gt;A side note: If you feel like it, you can modify the real &lt;code&gt;.map&lt;/code&gt; and make it do weird things too.&lt;/p&gt;

&lt;p&gt;Alright, now I want to pass the &lt;code&gt;{ |integer| integer * 2 }&lt;/code&gt; block to &lt;code&gt;.my_map&lt;/code&gt;. I know I should loop through the array and yield the block at some point. But since I'm not passing the array as an argument, where am I to call &lt;code&gt;.each&lt;/code&gt; on it?&lt;/p&gt;

&lt;p&gt;Let's see what &lt;code&gt;self&lt;/code&gt; has to say.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="c1"&gt;# Instantiate an empty array to store results&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Output yield to see the current context&lt;/span&gt;
    &lt;span class="s2"&gt;"Where are in: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="s2"&gt;"Where are in: [1, 2, 3]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we are in &lt;code&gt;.my_map&lt;/code&gt;, the default value we're working with is the array &lt;code&gt;.my_map&lt;/code&gt; was called upon. I now know I can call &lt;code&gt;.each&lt;/code&gt; on &lt;code&gt;self&lt;/code&gt; (i.e. &lt;code&gt;[1, 2, 3]&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Loop through the array and output yield just to see what's what&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  NoMethodError: undefined method &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s1"&gt;' for nil:NilClass
  from (pry):94:in `block in &amp;lt;class:Array&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, I can read from the error message that I'm in the &lt;code&gt;&amp;lt;class:Array&amp;gt;&lt;/code&gt;. That's good. Now, what about this &lt;code&gt;NoMethodError: undefined method '*' for nil:NilClass&lt;/code&gt;? Well, it simply says that in the NilClass &lt;sup id="fnref1"&gt;1&lt;/sup&gt;, there are no methods &lt;code&gt;*&lt;/code&gt; defined &lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;It means that my block &lt;code&gt;{ |integer| integer * 2 }&lt;/code&gt; can't execute the multiplication because the &lt;code&gt;integer&lt;/code&gt; variable inside it is &lt;code&gt;nil&lt;/code&gt;. &lt;code&gt;yield&lt;/code&gt; can take arguments though. So inside the loop, I'll just pass the current integer - &lt;code&gt;i&lt;/code&gt; - to &lt;code&gt;yield&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Loop through the array and execute the block&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# Give yield the current integer and store result in array&lt;/span&gt;
      &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# Return final array&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="o"&gt;[&lt;/span&gt;2, 4, 6]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which can be refactored like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_map&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Loop through the array and execute the block&lt;/span&gt;
    &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# self is implicite so I can remove it&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;my_map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;🥳 Done!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; is also pretty useful to figure out the scopes of your variables. But that'll do for another article.&lt;/p&gt;

&lt;p&gt;The key takeaway for today is: Next time you don't know where the fuck you are in your code, call &lt;code&gt;self&lt;/code&gt; to the rescue!&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Rémi&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Yes, &lt;code&gt;nil&lt;/code&gt; also has its own class. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Yes, &lt;code&gt;*&lt;/code&gt; is a method defined on specific objects 🤪. To check if NilClass has the &lt;code&gt;*&lt;/code&gt; method defined, run &lt;code&gt;NilClass.public_methods.include? '*'&lt;/code&gt; and &lt;code&gt;NilClass.private_methods.include? '*'&lt;/code&gt; in &lt;code&gt;irb&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ruby</category>
      <category>tips</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
