<?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: Alexandre Ignjatovic</title>
    <description>The latest articles on DEV Community by Alexandre Ignjatovic (@bankair).</description>
    <link>https://dev.to/bankair</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%2F405152%2Fe810c4bd-3a22-4da6-893a-2af7ea442f01.jpg</url>
      <title>DEV Community: Alexandre Ignjatovic</title>
      <link>https://dev.to/bankair</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bankair"/>
    <language>en</language>
    <item>
      <title>Ruby's discreet argument forwarding shorthand...</title>
      <dc:creator>Alexandre Ignjatovic</dc:creator>
      <pubDate>Fri, 08 Mar 2024 09:14:22 +0000</pubDate>
      <link>https://dev.to/eltesla/rubys-discreet-argument-forwarding-shorthand-12i3</link>
      <guid>https://dev.to/eltesla/rubys-discreet-argument-forwarding-shorthand-12i3</guid>
      <description>&lt;p&gt;&lt;em&gt;Yes, those three dots are intentional. Yes it's a pun. No I won't stop. Yes, you'll understand if you read this article to the end.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Have you ever ended up writing tons of methods doing mostly parameter forwarding?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;Foo&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;

  &lt;span class="c1"&gt;# That's the one:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;Ruby's &lt;code&gt;Forwardable&lt;/code&gt; module may be the solution to writing simpler code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;'forwardable'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Forwardable&lt;/span&gt;
  &lt;span class="n"&gt;def_delegator&lt;/span&gt; &lt;span class="ss"&gt;:@bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:do_stuff&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 I'd like to "do stuff" twice? Or add a log line?&lt;/p&gt;

&lt;h2&gt;
  
  
  Triple dots to the rescue
&lt;/h2&gt;

&lt;p&gt;Recently, I learned that Ruby includes an &lt;a href="https://docs.ruby-lang.org/en/master/syntax/methods_rdoc.html#label-Argument+Forwarding"&gt;argument forwarding shorthand&lt;/a&gt; since its version 2.7! (Which exists since 2019)&lt;/p&gt;

&lt;h3&gt;
  
  
  The syntax
&lt;/h3&gt;

&lt;p&gt;This shorthand is &lt;code&gt;...&lt;/code&gt;. Simple as that, and you can add your log line without bothering with how the arguments are going to evolve in the future:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'My log line'&lt;/span&gt;
  &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The good thing is: if &lt;code&gt;bar#do_stuff&lt;/code&gt; is added another argument, my &lt;code&gt;foo#do_stuff&lt;/code&gt; method do NOT have to change!&lt;/p&gt;

&lt;h3&gt;
  
  
  Leading arguments
&lt;/h3&gt;

&lt;p&gt;But what if I'd like to access one of the arguments before forwarding it?&lt;/p&gt;

&lt;p&gt;Since its version 3.0, Ruby gained support for leading arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do_stuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope you'll use it a lot...&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>webdev</category>
      <category>rails</category>
    </item>
    <item>
      <title>Efficient time management for curious Techies</title>
      <dc:creator>Alexandre Ignjatovic</dc:creator>
      <pubDate>Fri, 22 Sep 2023 16:35:18 +0000</pubDate>
      <link>https://dev.to/bankair/efficient-time-management-for-curious-techies-24dc</link>
      <guid>https://dev.to/bankair/efficient-time-management-for-curious-techies-24dc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Oh great, another article explaining how to be a turbocharged productivity monster...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;In this article, you won't learn how to become the proverbial 10X developer, or how to be the fastest DevOps of the planet earth.&lt;/p&gt;

&lt;p&gt;Because the secret to efficient time management is not doing more, it's actually doing less (and if you don't want to read this long form article, you can skip to the 'wrap up section' ;) ).&lt;/p&gt;

&lt;p&gt;As a tech person, your activities usually can be split in 3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build: Adding new things to your stack, software, infrastructure, team&lt;/li&gt;
&lt;li&gt;Run: Fixing bugs, Running your software, keep things updated&lt;/li&gt;
&lt;li&gt;Learn: Grow your expertise, in order to solve new classes of problems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is true for devs, DevOps, SREs, engineering managers, and probably most of the jobs you can imagine in tech.&lt;/p&gt;

&lt;p&gt;Considering this, efficient time management boils down to two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be pragmatic and don't waste time by doing useless tasks&lt;/li&gt;
&lt;li&gt;Preserve the balance of your investment between Run, Build and Learn&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  A time for building
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Happily write pragmatic software&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Software is immaterial, so how can I be pragmatic while crafting it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My answer to this is dead simple: challenge the why and the impact of the project&lt;/p&gt;

&lt;h2&gt;
  
  
  Why am I building this?
&lt;/h2&gt;

&lt;p&gt;If the answer to this is not serving the company's mission, you are wasting your time.&lt;/p&gt;

&lt;p&gt;When you answered to this question, if you still don't know if your company need this, use the &lt;a href="https://en.wikipedia.org/wiki/Five_whys"&gt;5 whys method&lt;/a&gt;. If your answers don't climb up to the company strategy after 5 steps, you are most probably doing something useless.&lt;/p&gt;

&lt;p&gt;And killing useless tasks is the easiest way to free up time for more relevant tasks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Estimate project impact
&lt;/h2&gt;

&lt;p&gt;Software is a tool, and not a end goal in itself.&lt;/p&gt;

&lt;p&gt;Identify your end-user. Measure what you are willing to change and estimate impact.&lt;/p&gt;

&lt;p&gt;A common bias is seeing problems closer to us as more important than problems that don't impact us. &lt;strong&gt;Challenge that inclination by estimating business impact of fixing both&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In one of my teams, there was 2 competing productivity problems to solve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The test suite of the CI was running in 40 minutes, which was painful and frustrating for developers (they had to wait 40 minutes to know if the CI was green and if their work was finished)&lt;/li&gt;
&lt;li&gt;The Customer Success Manager team had no proper tools, and were wasting time on brainless tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CI problem was raised at almost all developers' retrospective meetings, and was considered by most of the team as the most pressing problem to solve.&lt;br&gt;
Nobody ever spoke of adding admin tooling for CSMs people.&lt;/p&gt;

&lt;p&gt;I taught my team to do a reality-check when setting up priorities by adding numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I opened GitHub in front of them: Each dev was producing one or two PR per week. There was six devs in the team. In a month, that makes 36 opportunities for the whole dev team to tackle another subject (self-training, small bugfixes, quickwins, etc) while the CI runs. &lt;strong&gt;This is 24 hours, where devs had to work on "something else than my current task"&lt;/strong&gt; (easily fixed by giving each of them backlog of tiny tasks to juggle with)&lt;/li&gt;
&lt;li&gt;Each people of the CSM team was doing between 200 and 500 phone calls a month. There was 3 of them, which makes around 1000 calls per month. Each call needed to be prepared a couple of minutes ahead (for full context) and could last from a few seconds (if the user does not answer) up to half an hour. Each time a user does not answer the CSM person, it means 2 minutes and 30 seconds have been just lost by that CSM. And conversion rate was very low (less than 1/3 of the users were answering). Each month, &lt;strong&gt;CSMs were losing more than 40 hours working on users that never answered calls&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The farthest problem, was deemed the less important by the team, but was costing way more to the company than the closest problem.&lt;/p&gt;

&lt;p&gt;Ultimately, we found a way to provide a properly ordered list of people to reach out for the CSMs (the most likely to answer at the top of this list), and this led to a tremendous decrease in time spent waiting for users to answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand exactly what you have to build and deliver
&lt;/h2&gt;

&lt;p&gt;Spending time on something that will not be used is a waste of your time. If you spent a day working on something "that we are going to need in the future", I can guarantee you that you could have more fun and have pretty much the same impact by going to the park.&lt;/p&gt;

&lt;p&gt;Things that we build "because we may use it at some point" are useless today, and will probably stay useless forever.&lt;/p&gt;

&lt;p&gt;Don't build for the future. Solve your actual problems instead of your probable future problems.&lt;/p&gt;

&lt;p&gt;Also be sure to double check your understanding of what needs to be built with your stakeholders. You don't want to spend time on something that nobody is waiting for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before climbing a mountain, prepare for mountain climbing
&lt;/h2&gt;

&lt;p&gt;To go for a short 1 hour walk in the city, you only need a handful of things: your keys, some change and you are good to go!&lt;/p&gt;

&lt;p&gt;But it would be foolish to climb the Everest with only your keys and a few coins.&lt;/p&gt;

&lt;p&gt;It's pretty much the same things with tasks: If you start a huge task with no preparation, it's going to end up badly.&lt;/p&gt;

&lt;p&gt;As a preliminary task to your huge task, split your huge task in more manageable tasks, and schedule them. If your split tasks are still huge, do it again!&lt;/p&gt;

&lt;p&gt;This is what I do when I write a long form article. I split it into several manageable task that I can do under an hour. For example, for this article, I went:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Brainstorm: Collect ideas and tips about time management&lt;/li&gt;
&lt;li&gt;Structure: identify my main messages and the plan of the article&lt;/li&gt;
&lt;li&gt;Write: Write each section of the article&lt;/li&gt;
&lt;li&gt;Edit: Review and edit the article once it's fully written&lt;/li&gt;
&lt;li&gt;Publish: Success!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A great side effect of having planned the execution of this task was the ability to pause/resume. Since the plan is written down, I can work on something else without forgetting about what I wanted to write next.&lt;/p&gt;

&lt;p&gt;Which leads us to my next advice: &lt;strong&gt;Always go from abstract to concrete&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you notice that you are already deep down in the implementation details without having yet figured out the global plan of execution, you need to take a step back.&lt;/p&gt;

&lt;p&gt;Don't start the work on the architecture if you are not 100% clear on the requirements. And don't work on the code if you are not 100% clear about your architecture.&lt;/p&gt;

&lt;h1&gt;
  
  
  A time for operations
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Run this software without blasting your productivity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing code is cool, but it's nothing if you don't end up with users.&lt;/p&gt;

&lt;p&gt;It's OK to build things that are not meant to be deployed as a production environment, as long are you are aware that you are just "practicing".&lt;/p&gt;

&lt;p&gt;And as soon as you have end users, you have to keep the pot boiling.&lt;/p&gt;

&lt;p&gt;Let's see what we can do to avoid spending too much time on this pot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure operations time costs and optimize your run
&lt;/h2&gt;

&lt;p&gt;While keeping a production up, some things are significative time sinks.&lt;/p&gt;

&lt;p&gt;When facing such situation, I ask myself the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this task useless? (kill it)&lt;/li&gt;
&lt;li&gt;Can somebody else do it? (delegate it)&lt;/li&gt;
&lt;li&gt;Can something else do it? (automate it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: If your support team is asking quite often your tech team to investigate why some users can't use some features of your product, you can either delegate (teach your support team to understand your product configuration and workflows) or automate (build a technical diagnostic page).&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch small mindless operations to save your deep work time
&lt;/h2&gt;

&lt;p&gt;One underestimated time thief is the context switching. It's commonly accepted that you need between 15 to 30 minutes to be properly focused on a topic while doing deep work (coding or writing for example).&lt;/p&gt;

&lt;p&gt;Assuming you worked on 8 different topics on a single day, that's between 2 and 4 hours of concentration time gone with the wind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you need to achieve deep work, don't multitask, and avoid context switching.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But wait, there is more!&lt;/p&gt;

&lt;p&gt;Let's say that you decided to dedicate your whole day to a deep work task.&lt;/p&gt;

&lt;p&gt;Breaking news: &lt;strong&gt;you need to refocus even after the most trivial mundane interruption&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your coworker ask you a question about a technical detail? at least 15 minutes were just tossed into the bin. Your support team ask you to start some jobs in production 8 times in a day? Again, that's between 2 and 4 hours of time lost in refocusing.&lt;/p&gt;

&lt;p&gt;The easy solution is to batch non-urgent but important &amp;amp; trivial tasks that don't require deep focus. This way, you limit the interruptions of your deepwork, and you'll get more done at the end of the day (or you will be able to get home earlier, which is a nice bonus, innit?).&lt;/p&gt;

&lt;h1&gt;
  
  
  A time for learning
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Don't let run and build tasks preventing you from growing, for yourself and your company&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While working in tech, you will have to work with lots of different stakeholders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your project or product manager want you to build tons of things, as fast as possible&lt;/li&gt;
&lt;li&gt;Your end users want to use a reliable and nice tool&lt;/li&gt;
&lt;li&gt;Your manager want you to reach the goals he gave you&lt;/li&gt;
&lt;li&gt;And &lt;strong&gt;yourself as well are a stakeholder&lt;/strong&gt;, since you want to grow and be successful in this company and in your career&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trap is, while trying to meet expectations of all your other stakeholders, you end up being quite the busy person, and &lt;strong&gt;you probably forgot to be the own stakeholder of your personal development&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Don't do that! Reserve time for your growth.&lt;/p&gt;

&lt;p&gt;Also, be sure to have a sensible training plan: &lt;strong&gt;curiosity is not a purpose&lt;/strong&gt;. Make the better out of your learning time by investing it into something that will serve you, not something shiny.&lt;/p&gt;

&lt;p&gt;Learning about a cool tech that nobody heard about 1 year ago is a bet. Sometime you can win and be one of the first to be fluent in an interesting emerging technology, but if can also be a major waste of time.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;before learning about cool tech, learn about plain old boring ones&lt;/strong&gt; ;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understand your ecosystem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some company value a lot personal learning time, especially if it serves the company mission. Some other don't. and expect you to grow on your own personal time.&lt;/p&gt;

&lt;p&gt;Be sure to understand for which of those two you work for.&lt;/p&gt;

&lt;p&gt;And once you know, reserve, formally, some time for learning. Your internal stakeholder will thank you later.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap up
&lt;/h1&gt;

&lt;p&gt;Here is a digest of the time management principles I use on a daily basis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the why&lt;/li&gt;
&lt;li&gt;Challenge tasks usefulness&lt;/li&gt;
&lt;li&gt;Set priorities based on impact&lt;/li&gt;
&lt;li&gt;Do a reality-check from time to time&lt;/li&gt;
&lt;li&gt;Reserve time for deep work&lt;/li&gt;
&lt;li&gt;Reserve time for batch of brainless tasks&lt;/li&gt;
&lt;li&gt;Reserve time for learning&lt;/li&gt;
&lt;li&gt;Split big tasks in smaller tasks&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unito.io/blog/eat-the-frog/"&gt;Eat the frog in the morning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What are yours?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>learning</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Learn about Ractors and build a mini sidekiq</title>
      <dc:creator>Alexandre Ignjatovic</dc:creator>
      <pubDate>Wed, 10 Mar 2021 10:31:35 +0000</pubDate>
      <link>https://dev.to/doctolib/learn-about-ractors-and-build-a-mini-sidekiq-3ba2</link>
      <guid>https://dev.to/doctolib/learn-about-ractors-and-build-a-mini-sidekiq-3ba2</guid>
      <description>&lt;p&gt;&lt;em&gt;In this article, you'll learn more about Ractor, and how you can use them to build your own clone of &lt;a href="https://sidekiq.org/"&gt;sidekiq&lt;/a&gt; (a background processing framework for Ruby).&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Ractor?
&lt;/h1&gt;

&lt;p&gt;Ruby 3.0 introduced the &lt;a href="https://github.com/ruby/ruby/blob/master/doc/ractor.md"&gt;Ractor&lt;/a&gt; class. This is Ruby's Actor-like concurrent abstraction, and its goal is to provide a parallel execution feature of Ruby without thread-safety concerns.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Actor_model"&gt;wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The actor model in computer science is a mathematical model of concurrent computation that treats actor as the universal primitive of concurrent computation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Actors are able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create more actors&lt;/li&gt;
&lt;li&gt;Receive messages&lt;/li&gt;
&lt;li&gt;Send messages&lt;/li&gt;
&lt;li&gt;Take local decisions &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Be aware that the Ractor implementation is not stable yet, do &lt;strong&gt;NOT&lt;/strong&gt; use them for production code. See the warning displayed when you use them if you still need to be convinced to not use it (yet) in production:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating a ractor
&lt;/h2&gt;

&lt;p&gt;Creating a ractor is as simple as using &lt;code&gt;Ractor.new&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&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="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'Hello Ractor!'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Receiving a message
&lt;/h2&gt;

&lt;p&gt;There are two ways to receive a message, depending if you have a reference on the ractor sending it.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;Ractor.receive&lt;/code&gt; if you don't know who is sending the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use &lt;code&gt;Ractor#take&lt;/code&gt; if you have a reference on the ractor sending the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As those method calls are blocking until you receive a message, &lt;strong&gt;avoid expecting a message from a ractor that will never send one&lt;/strong&gt;, or your program is going to be stuck forever.&lt;/p&gt;

&lt;p&gt;Also, please be aware that the &lt;a href="https://docs.ruby-lang.org/en/3.0.0/Ractor.html#class-Ractor-label-Shareable+and+unshareable+objects"&gt;objects you are sending must be shareable&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending a message
&lt;/h2&gt;

&lt;p&gt;If you know your recipient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# or&lt;/span&gt;
&lt;span class="n"&gt;ractor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="c1"&gt;# `&amp;lt;&amp;lt;` is an alias to `send`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you don't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Ractor.yield&lt;/code&gt; is blocking as well until some ractor receive your message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking local decision
&lt;/h2&gt;

&lt;p&gt;You can do pretty much anything you want in the block given to &lt;code&gt;Ractor.new&lt;/code&gt;. &lt;strong&gt;Unless accessing shared objects&lt;/strong&gt;. An exception will be raised if you try to use a variable defined outside of your block. In order to share a variable between several ractors, you can, for example, use the &lt;a href="https://github.com/ko1/ractor-tvar"&gt;Ractor::TVar gem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting method I'm going to use later on is the &lt;code&gt;Ractor.select(*actors)&lt;/code&gt; method. It takes several ractors as an input, and returns the first ractor to send something, and its output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;slow_ractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&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="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:too_late&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;fast_ractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&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="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:fast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;ractor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slow_ractor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fast_ractor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# output == :fast &amp;amp;&amp;amp; ractor == fast_ractor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Let's build a mini sidekiq!
&lt;/h1&gt;

&lt;p&gt;Please be aware that this crude POC will only allow you to use a pool of 10 ractors to achieve parallel execution of jobs. It won't handle error flow control, statistics, queueing and all the other features that make sidekiq a super useful project.&lt;/p&gt;

&lt;p&gt;We'll build a simple design with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;WorkerPool&lt;/code&gt;, taking care of our pool of ractors&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Job&lt;/code&gt; base class, that all our dedicated jobs will inherit from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal being to allow people to easily implement their own jobs without having to handle all the pool logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  WorkerPool
&lt;/h2&gt;



&lt;div class="highlight js-code-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;WorkerPool&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:ractors&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="vi"&gt;@ractors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&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="n"&gt;spawn_worker&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;spawn_worker&lt;/span&gt;
    &lt;span class="no"&gt;Ractor&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;do&lt;/span&gt;
      &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ready&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="no"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;)&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="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ractor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ignored_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="no"&gt;Ractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@instance&lt;/span&gt; &lt;span class="o"&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;ractors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ractor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;parameters&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;There is a trick here. When using &lt;code&gt;Ractor.yield(:ready)&lt;/code&gt;, we are just making sure that the ractors of the pool have something to send for the initial &lt;code&gt;Ractor.select&lt;/code&gt; to work (remember, it's blocking).&lt;/p&gt;

&lt;h2&gt;
  
  
  Job base class
&lt;/h2&gt;



&lt;div class="highlight js-code-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;Job&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;process&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="no"&gt;WorkerPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;args: &lt;/span&gt;&lt;span class="n"&gt;args&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="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;
      &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;args: &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;klass&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="nf"&gt;process&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="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;Be aware that anything you will provide as argument must be shareable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a specific job
&lt;/h2&gt;

&lt;p&gt;Let's say that we'd like to create an asynchronous job that prints something:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-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;PrintJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Job&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;message&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;Using it asynchronously is now as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;PrintJob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Hello World!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Ractor introduces a new and interesting model for parallel execution in Ruby.&lt;/p&gt;

&lt;p&gt;If you found the ractor topic interesting, I suggest you check out these interesting resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ruby/ruby/blob/master/doc/ractor.md"&gt;https://github.com/ruby/ruby/blob/master/doc/ractor.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ruby-lang.org/en/3.0.0/Ractor.html"&gt;https://docs.ruby-lang.org/en/3.0.0/Ractor.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you liked this post, check out our &lt;a href="https://doctolib.engineering/engineering-news-ruby-rails-react"&gt;awesome weekly tech newsletter&lt;/a&gt;. We are regularly sharing top ruby &amp;amp; javascript content!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/photos/QM3suFW_Y4E"&gt;Mark Thompson&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
