<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://yboulkaid.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://yboulkaid.com/" rel="alternate" type="text/html" /><updated>2026-06-05T20:00:06+00:00</updated><id>https://yboulkaid.com/feed.xml</id><title type="html">Rubber Ducky</title><subtitle>Youssef Boulkaid&apos;s blog: Developer, rubyist, photographer and occasional writer.</subtitle><author><name>Youssef Boulkaid</name></author><entry><title type="html">RailsConf 2024: a recap</title><link href="https://yboulkaid.com/2024/05/15/railsconf.html" rel="alternate" type="text/html" title="RailsConf 2024: a recap" /><published>2024-05-15T08:51:00+00:00</published><updated>2024-05-15T08:51:00+00:00</updated><id>https://yboulkaid.com/2024/05/15/railsconf</id><content type="html" xml:base="https://yboulkaid.com/2024/05/15/railsconf.html"><![CDATA[<p>I came back from RailsConf 2024 a couple days ago. The experience was amazing, and I feel both energized and socially exhausted, in a good way. Here’s a recap of my experience while it’s still fresh.</p>

<h2 id="first-days-detroit--talk-preparation">First days: Detroit &amp; talk preparation</h2>
<p>I got in three days before the beginning of the conference, both to give myself some time to explore the city and to better prepare and rehearse the talk I was giving.</p>

<p>Though I ended up doing a lot more talk preparation than city exploring, I loved the energy of downtown Detroit! The city sometimes gets a bad reputation (“isn’t that the city that went bankrupt?”, “don’t drink the water there!”), but my experience was very different. It was a lively city, with plenty of cafés, bars and attractions. Though as with many American cities, it’s not the most walkable. It’s the Motor City for a reason, after all.</p>

<p>The conference hotel was in the same building as the <a href="https://en.wikipedia.org/wiki/Renaissance_Center">General Motors Headquarters</a>, which explained the classic cars <em>inside</em> the building. The building was also notoriously hard to navigate, which at least gave an easy ice-breaker for conversations.</p>

<p><a href="/assets/images/railsconf-2024/rencen.jpg" data-glightbox="" data-description="The Renaissance Center, HQ of General Motors and location of the conference hotel.">
  <img class="image-overflow" src="/assets/images/railsconf-2024/rencen.jpg" />
</a>
<span class="image-caption text-muted"> The Renaissance Center, HQ of General Motors and location of the conference hotel. </span></p>

<p><a href="/assets/images/railsconf-2024/pizza.jpg" data-glightbox="" data-description="Detroit-style pizza at Buddy&#39;s">
  <img class="image-overflow" src="/assets/images/railsconf-2024/pizza.jpg" />
</a>
<span class="image-caption text-muted"> Detroit-style pizza at Buddy’s </span></p>

<p><a href="/assets/images/railsconf-2024/canada.jpg" data-glightbox="" data-description="Canada is one bridge away... to the South">
  <img class="image-overflow" src="/assets/images/railsconf-2024/canada.jpg" />
</a>
<span class="image-caption text-muted"> Canada is one bridge away… to the South </span></p>

<h2 id="the-talk">The talk</h2>
<p>I had given talks at smaller local meetups before, but this was my first time giving a “legit”, 30-minute talk in a conference. Preparing it consumed almost all my free time in the weeks beforehand, and I was pretty nervous beforehand.</p>

<p>Shout out to the RailsConf organizers for giving speakers all the tools we needed to have the best experience. They paired me with a mentor speaker to get feedback on it. I was matched with <a href="https://noelrappin.com/">Noel Rappin</a> and his feedback was very helpful as I was struggling to structure a longer talk. The speaker liaisons were also very present and helpful, and I never felt I was on my own.</p>

<p>Also, I draw what probably is the best slot for a speaker: the first talk of the first day! I could then attend the rest of the conference freely, and skip the stress. Whoever gave me that slot, thank you!</p>

<p><a href="/assets/images/railsconf-2024/talk.jpg" data-glightbox="" data-description="Picture of the audience during my talk">
  <img class="image-overflow" src="/assets/images/railsconf-2024/talk.jpg" />
</a>
<span class="image-caption text-muted"> Picture of the audience during my talk </span></p>

<h2 id="the-last-hurrah">The last hurrah</h2>
<p>On the very first day, Ruby Central announced that <a href="https://rubycentral.org/news/anewearforrubycentralevents/">next year will be the last RailsConf</a>. This came as a shock to many in the audience who either attended RailsConf regularly or, like me, watched the recordings every year. We realized that we were taking the conference for granted, and hearing the news was hard but made this one felt special.</p>

<p>Ruby Central hosted a Q&amp;A panel for the community and shared their plans for the future. Organizing both RubyConf and RailsConf every year was eating up all their energy and bandwidth and they couldn’t focus on other things that mattered, like supporting the local ruby communities, fundraising, building ties with the Ruby Core team and improving Ruby documentation.</p>

<p>While I’m sad to see RailsConf disappear, I completely understand RubyCentral’s decision and agree with their long-term strategy for keeping the Ruby language and ecosystem healthy. It also made me think about all the work that goes on behind the scenes to keep basic infrastructure like rubygems.org running 24/7.</p>

<h2 id="talks-and-keynotes">Talks and keynotes</h2>
<p>All four keynotes were all amazing. We got:</p>
<ul>
  <li>The inspiring story of the solo-founder behind <a href="https://www.thestorygraph.com/">The StoryGraph</a></li>
  <li>Many stories about Startups choosing Rails in 2024. As someone who wants to do more advocacy for Rails but doesn’t know how, this one hit hard.</li>
  <li>A look at a new ruby profiler, <a href="https://github.com/jhawthorn/vernier">Vernier</a></li>
  <li>The classic tenderlove closing keynote, which starts with a stand-up comedy routine and ends deep in the ruby C internals. Honestly, by now I don’t know which one of the two parts is harder to pull off, but they’re both executed really well.</li>
</ul>

<p>The talks I attended were also good, though I always get massive FOMO at multiple-track conferences. I’m looking forward to catching up on the ones I missed when the recordings are available.</p>

<h2 id="rubyfriends">#RubyFriends</h2>
<p>It’s almost an overused sentence by now but it’s still very true. What makes ruby amazing is its community. Everyone I met was open, welcoming, kind and optimistic.</p>

<p>I especially liked seeing how much the community and the conference welcomed juniors and ruby beginners. There was a <a href="https://rubycentral.org/scholars_guides_program/">special program</a> to provide free tickets and mentorships for juniors who applied, and pair them with more experienced developers.</p>

<p>I really <em>feel</em> this because when I reflect on what my best time was during the conference, it’s whenever I was interacting with the people. The hallway track, game night, speaker dinner and late-night-drinks were all highlights.</p>

<h2 id="hack-day">Hack day</h2>
<p>One new experiment for this conference was a talk-free Hack Day, where attendees could participate in more hands-on activities:</p>
<ul>
  <li>Coding on open-source projects with their maintainers</li>
  <li>2-hour hands-on workshops</li>
  <li>A dedicated session for meeting book authors</li>
</ul>

<p>My social and coding state of minds are not super compatible, so I did not code myself. But I enjoyed talking to maintainers of various open-source projects and telling them that their projects mattered and were useful to me, and I heard that people who coded really enjoyed it.</p>

<p>Hack day also allowed for some talk-free time to enjoy the hallway track or rest, which is more than welcome at a 3-day conference.</p>

<h2 id="optimism-and-gratefulness">Optimism and gratefulness</h2>
<p>As I’m coming off the conference high, I feel very grateful and thankful to RubyCentral for the amazing work they have been doing behind the scenes, keeping the community and infrastructure running all these years. Thank you.</p>

<p>I’m also more optimistic about the future of Ruby and Rails than ever. The community is strong, and the joy of writing ruby is still here. It’s up to us to spread it and be vocal about it. The future of ruby is bright, and the people amazing.</p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[I came back from RailsConf 2024 a couple days ago. The experience was amazing, and I feel both energized and socially exhausted, in a good way. Here’s a recap of my experience while it’s still fresh.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2024-05-15-railsconf.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2024-05-15-railsconf.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Hands-off eclipse photography with ruby and gphoto</title><link href="https://yboulkaid.com/2024/04/10/eclipse.html" rel="alternate" type="text/html" title="Hands-off eclipse photography with ruby and gphoto" /><published>2024-04-10T18:51:00+00:00</published><updated>2024-04-10T18:51:00+00:00</updated><id>https://yboulkaid.com/2024/04/10/eclipse</id><content type="html" xml:base="https://yboulkaid.com/2024/04/10/eclipse.html"><![CDATA[<p>For the 2024 eclipse, my wife and I decided to make the trip from Stockholm to Texas to get a chance to witness it. Being a photographer, I also wanted to try my hand at shooting the event.</p>

<p>At the same time, I knew that totality would only last for about 3.5 minutes, and I sure didn’t want to spend all of it staring at my camera. So I decided to automate the process.</p>

<h2 id="the-challenge">The challenge</h2>

<p>When you only have three minutes to shoot an event, preparation is key. I wouldn’t have the time to fiddle with settings, everything should be set by the time totality comes.</p>

<p>A challenge when photographing an eclipse is that there is a large difference in the brightness between the lightest and darkest parts of the sun. The outer ring is very bright (you’re still looking at the sun, after all), but the corona extends pretty far and gets dim very quickly at the edges. In photography parlance, the scene is said to have <strong>high dynamic range</strong>.</p>

<p>Because of that, one shot is not enough to capture the full extent of the scene. So what I would need to do is you take multiple shots at different levels of luminosity to capture details in different aspects of the scene (a.k.a. <strong>braketing</strong>), then I could stitch them together in post-processing. Or just select one that I liked best.</p>

<h2 id="preparation">Preparation</h2>

<p>MrEclipse.com has an <a href="https://www.mreclipse.com/SEphoto/SEphoto.html">excellent guide</a> to eclipse photography, which includes different camera settings to use when bracketing shots.</p>

<p>My lens had a fixed aperture of f/16, so at ISO 400, looking up the information in the table, I would need to have exposures from <strong>1/4000 sec to 4sec</strong>.</p>

<p><a href="/assets/images/eclipse/table.gif" data-glightbox="" data-description="The lookup table I used as a reference for the different shutter speeds when bracketing">
  <img class="image-overflow" src="/assets/images/eclipse/table.gif" />
</a>
<span class="image-caption text-muted"> The lookup table I used as a reference for the different shutter speeds when bracketing </span></p>

<h3 id="automation">Automation</h3>

<p>I first tried different remote shooting apps but none of them was flexible enough to allow for this level of bracketing. Many of them were also unstable and and I didn’t want to take the risk of an app crashing on me or losing connection when my phone went to sleep.</p>

<p>This is when I decided to automate the process myself. After some research, I found <a href="http://www.gphoto.org/">gPhoto2</a> a long-standing library that can talk to cameras and control them remotely. I also found a <a href="https://github.com/zaeleus/ffi-gphoto2">ruby gem</a> that provides ruby bindings to use it.</p>

<p>The next step was to create a ruby script to capture the different exposures needed for the bracketing. For safety and to cover for e.g. clouds, I made it so that every shot was taken four times, and ran the whole bracketing loop four times too.</p>

<p>The final script looked like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'gphoto2'</span>

<span class="no">GPhoto2</span><span class="o">::</span><span class="no">Camera</span><span class="p">.</span><span class="nf">first</span> <span class="k">do</span> <span class="o">|</span><span class="n">camera</span><span class="o">|</span>
  <span class="n">speeds</span> <span class="o">=</span> <span class="sx">%w[
    1/60
    1/4000
    1/2000
    1/500
    1/250
    1/15
    1/4
    1
    2
    4
  ]</span>
  <span class="mi">4</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
    <span class="n">speeds</span><span class="p">.</span><span class="nf">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">speed</span><span class="o">|</span>
      <span class="n">camera</span><span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="ss">iso: </span><span class="mi">400</span><span class="p">,</span> <span class="ss">shutterspeed: </span><span class="n">speed</span><span class="p">)</span>
      <span class="mi">4</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
        <span class="nb">puts</span> <span class="s2">"Taking exposure at </span><span class="si">#{</span><span class="n">speed</span><span class="si">}</span><span class="s2">s"</span>
        <span class="n">camera</span><span class="p">.</span><span class="nf">capture</span>
      <span class="k">rescue</span> 
        <span class="kp">nil</span> <span class="c1"># Cover for unexpected cases when e.g. the camera is busy</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<h2 id="result">Result</h2>
<p>Once totality started, I ran <code class="language-plaintext highlighter-rouge">ruby totality.rb</code>, left the laptop and enjoyed the moment with my family.</p>

<p>I returned to it afterwards, and… everything had worked 🎉 Though many of the shots were black because of cloud coverage, I still got more than enough properly exposed shots to make up for it. And I didn’t need to be at the camera for any of it!</p>

<p><a href="/assets/images/eclipse/lr-screenshot.jpg" data-glightbox="" data-description="All the pictures taken by the script">
  <img class="image-overflow" src="/assets/images/eclipse/lr-screenshot.jpg" />
</a>
<span class="image-caption text-muted"> All the pictures taken by the script </span></p>

<p><a href="/assets/images/eclipse/totality-2.jpg" data-glightbox="" data-description="Shot at 1/60s">
  <img class="image-overflow" src="/assets/images/eclipse/totality-2.jpg" />
</a>
<span class="image-caption text-muted"> Shot at 1/60s </span></p>

<p><a href="/assets/images/eclipse/totality-1.jpg" data-glightbox="" data-description="Shot at 1/15s">
  <img class="image-overflow" src="/assets/images/eclipse/totality-1.jpg" />
</a>
<span class="image-caption text-muted"> Shot at 1/15s </span></p>

<p><a href="/assets/images/eclipse/totality-3.jpg" data-glightbox="" data-description="Shot at 2sec, you can see the corona extend longer">
  <img class="image-overflow" src="/assets/images/eclipse/totality-3.jpg" />
</a>
<span class="image-caption text-muted"> Shot at 2sec, you can see the corona extend longer </span></p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[For the 2024 eclipse, my wife and I decided to make the trip from Stockholm to Texas to get a chance to witness it. Being a photographer, I also wanted to try my hand at shooting the event.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2024-03-10-eclipse.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2024-03-10-eclipse.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">I built a new tab page to look at my old pictures</title><link href="https://yboulkaid.com/2023/02/06/new-tab-picture.html" rel="alternate" type="text/html" title="I built a new tab page to look at my old pictures" /><published>2023-02-06T18:53:00+00:00</published><updated>2023-02-06T18:53:00+00:00</updated><id>https://yboulkaid.com/2023/02/06/new-tab-picture</id><content type="html" xml:base="https://yboulkaid.com/2023/02/06/new-tab-picture.html"><![CDATA[<p>Photography is my main hobby. I have been taking pictures for 17 years now, and while I do have a selection of <a href="https://yboulkaid.com/photography.html">my best work</a>, 17 years worth of pictures is <em>a lot</em> more than that.</p>

<p>This means that there are thousands upon thousands of image files gathering digital dust on a spinning cobalt disk inside my NAS. Each one of those pictures was shot at a moment where I thought it was important, passed the culling process then carefully processed in Lightroom. Realizing that all these pictures will probably never be looked at again made me sad, so I decided to do something about it.</p>

<h2 id="the-idea">The idea</h2>
<p>Over the weekend, I had a thought: what if I could make my browser’s new tab page display a random picture from my stash? The image would change at regular intervals, keeping the novelty factor high and blowing some digital dust off the hard drive.</p>

<p>This had me think back to the old <a href="https://en.wikipedia.org/wiki/Webshots">Webshots desktop</a> setup I had growing up, that would change my desktop wallpaper every hour. It also incidentally turned me into a desktop image hoarder, but that’s a story for another time.</p>

<p>I rarely look at my desktop wallpaper these days, so I kept the idea but switched the canvas to be the browser new tab page, which gets opened dozens of times per day.</p>

<h2 id="prototype">Prototype</h2>
<p>The first step is to build a database of all the source pictures. A text file is enough:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ find /Volumes/home/Pictures/Processed -type f -name '*.jpg' &gt; all_pictures.txt
$ wc -l all_pictures.txt
    32588 all_pictures.txt
</code></pre></div></div>

<p>There are 32,588 pictures to chose from. To get one from the set, I can use <code class="language-plaintext highlighter-rouge">shuf</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ shuf -n 1 all_pictures.txt
/Volumes/home/Pictures/Processed/2013/décembre/NNC 2013/IMG_7683-3.jpg
</code></pre></div></div>

<p>All that’s left is to wrap this in a web server with some minimal styling, and voilà:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'bundler/inline'</span>

<span class="n">gemfile</span> <span class="k">do</span>
  <span class="n">source</span> <span class="s1">'https://rubygems.org'</span>
  <span class="n">gem</span> <span class="s1">'sinatra'</span>
  <span class="n">gem</span> <span class="s1">'puma'</span>
<span class="k">end</span>

<span class="k">class</span> <span class="nc">App</span> <span class="o">&lt;</span> <span class="no">Sinatra</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">get</span> <span class="s1">'/'</span> <span class="k">do</span>
    <span class="c1"># Need to copy the image to the `public` folder because browsers</span>
    <span class="c1"># cannot load local files.</span>
    <span class="sb">`cp "$(shuf -n 1 all_pictures.txt)" public/chosen.jpg`</span>
    
    <span class="s2">"&lt;img src='chosen.jpg' style='max-width: 90%; display: block; margin: auto;'/&gt;"</span>
  <span class="k">end</span>

  <span class="n">run!</span> <span class="k">if</span> <span class="n">app_file</span> <span class="o">==</span> <span class="vg">$0</span>
<span class="k">end</span>
</code></pre></div></div>

<p><a href="/assets/images/new-tab-picture/prototype.jpg" data-glightbox="" data-description="I now had a page that displayed a random image, loaded on every refresh">
  <img class="image-overflow" src="/assets/images/new-tab-picture/prototype.jpg" />
</a>
<span class="image-caption text-muted"> I now had a page that displayed a random image, loaded on every refresh </span></p>

<h2 id="bells-and-whistles">Bells and whistles</h2>
<h3 id="caching">Caching</h3>
<p>Loading a different image on each reload is fun, but also very distracting and bandwidth-heavy. The solution was a simple in-memory cache to keep the same image loaded:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># cache.rb</span>
<span class="k">class</span> <span class="nc">Cache</span>
  <span class="k">def</span> <span class="nf">initialize</span>
    <span class="vi">@store</span> <span class="o">=</span> <span class="p">{}</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">with_cache</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
    <span class="n">cache_hit</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">cache_hit</span> <span class="k">if</span> <span class="n">cache_hit</span>

    <span class="n">value</span> <span class="o">=</span> <span class="n">block</span><span class="p">.</span><span class="nf">call</span>
    <span class="n">set</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
    <span class="n">value</span>
  <span class="k">end</span>

  <span class="kp">private</span>

  <span class="no">TTL_SECONDS</span> <span class="o">=</span> <span class="mi">5</span>

  <span class="nb">attr_reader</span> <span class="ss">:store</span>

  <span class="k">def</span> <span class="nf">set</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
    <span class="n">store</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">value: </span><span class="n">value</span><span class="p">,</span> <span class="ss">expires_at: </span><span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">to_i</span> <span class="o">+</span> <span class="no">TTL_SECONDS</span> <span class="p">}</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="k">return</span> <span class="k">if</span> <span class="n">store</span><span class="p">[</span><span class="n">key</span><span class="p">].</span><span class="nf">nil?</span>
    <span class="k">return</span> <span class="k">if</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">to_i</span> <span class="o">&gt;=</span> <span class="n">store</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="ss">:expires_at</span><span class="p">]</span>

    <span class="n">store</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="ss">:value</span><span class="p">]</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="c1"># server.rb</span>
<span class="n">set</span> <span class="ss">:cache</span><span class="p">,</span> <span class="no">Cache</span><span class="p">.</span><span class="nf">new</span>

<span class="n">get</span> <span class="s1">'/'</span> <span class="k">do</span>
  <span class="no">App</span><span class="p">.</span><span class="nf">cache</span><span class="p">.</span><span class="nf">with_cache</span><span class="p">(</span><span class="ss">:image</span><span class="p">)</span> <span class="k">do</span>
    <span class="c1"># ...</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<h3 id="styling-and-metadata-extraction">Styling and metadata extraction</h3>
<p>Using the <a href="https://github.com/tonytonyjan/exif">exif</a> gem, I could extract some EXIF metadata from the image file to provide more context about the image.</p>

<p>Add some extra styling and you have the final look of the page:</p>

<p><a href="/assets/images/new-tab-picture/final.jpg" data-glightbox="" data-description="The final picture, with a full-width picture and metadata at the bottom">
  <img class="image-overflow" src="/assets/images/new-tab-picture/final.jpg" />
</a>
<span class="image-caption text-muted"> The final picture, with a full-width picture and metadata at the bottom </span></p>

<h3 id="setting-the-new-tab-page">Setting the new tab page</h3>
<p>This proved surprisingly harder that I expected, for a couple reasons:</p>
<ul>
  <li>Firefox <a href="https://support.mozilla.org/en-US/questions/1162532">doesn’t support for custom urls for new tabs anymore</a>, and recommends using browser extensions instead.</li>
  <li>When I tried some extensions, the behavior was odd: The new page opened, but it also focused the url and you’d have to manually clear the address bar before you can enter a new address. I lasted exactly 4 minutes before uninstalling them. There’s even a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1409675">long-standing bug report</a> about this.</li>
</ul>

<p>After trying multiple extensions, I found <a href="https://addons.mozilla.org/en-GB/firefox/addon/custom-new-tab-page">one</a> that managed to bypass this by embedding the desired page in an iframe.</p>

<p>This came with its own challenges, as browsers don’t allow pages to be embedded in arbitrary iframes anymore (nor should they). The solution is to set the CSP <code class="language-plaintext highlighter-rouge">frame-ancestors</code> directive on the server response to allow this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">response</span><span class="p">.</span><span class="nf">headers</span><span class="p">[</span><span class="s1">'Content-Security-Policy'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'frame-ancestors *;'</span>
</code></pre></div></div>

<p>This was the last piece of the puzzle, and I can now enjoy a new picture from my archive every hour.</p>

<h2 id="epilogue">Epilogue</h2>

<h3 id="a-few-hours-in">A few hours in</h3>
<p>In the beginning, the time between each new picture was set to 5 minutes. After a couple hours, I found myself compulsively reaching for my laptop to open a new tab and check the new picture. I accidentally hooked myself on a picture-induced dopamine rush!</p>

<p>When I realized that, I switched the timer from 5 minutes to 1 hour and that feeling disappeared.</p>

<h3 id="a-few-days-in">A few days in</h3>
<p>After a couple days using it, I have:</p>
<ul>
  <li>Had many trips down memory lane.</li>
  <li>Sent some of the pictures to people I was with in the pictures, usually traveling.</li>
  <li>Looked up way too many people online to see what they were up to now.</li>
</ul>

<p>I do have some ideas for future improvements, if I ever get to them:</p>
<ul>
  <li>Also set the picture as a desktop background?</li>
  <li>Dockerizing the server so it can be run directly on the NAS instead of locally</li>
  <li>Saving the metadata along with the images to enable functionalities like “On this day”</li>
  <li>Adding a way to skip pictures that I don’t want to look at (I just restart the server when it happens)</li>
</ul>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[Photography is my main hobby. I have been taking pictures for 17 years now, and while I do have a selection of my best work, 17 years worth of pictures is a lot more than that.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2023-02-06-new-tab-picture.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2023-02-06-new-tab-picture.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Photography assignment: Paraphrase</title><link href="https://yboulkaid.com/2023/02/06/hand.html" rel="alternate" type="text/html" title="Photography assignment: Paraphrase" /><published>2023-02-06T18:53:00+00:00</published><updated>2023-02-06T18:53:00+00:00</updated><id>https://yboulkaid.com/2023/02/06/hand</id><content type="html" xml:base="https://yboulkaid.com/2023/02/06/hand.html"><![CDATA[<p>So, the assignment was to “paraphrase” a portrait, by drawing inspiration from another portrait (could be a photo, painting, sculpture etc) and make your version of it.</p>

<p>As an inspiration, I chose a photography by Yusuf Karsh. He was a photographer who took portraits of statesmen and artists in the 40s to 80s. He has a series where he took pictures of hands, this one is Eleanor Roosevelt’s.</p>

<p><a href="/assets/images/photofeed/2023-12-06-hand/hand-yusuf-karsh.jpeg" data-glightbox="" data-description="">
  <img class="image-overflow" src="/assets/images/photofeed/2023-12-06-hand/hand-yusuf-karsh.jpeg" />
</a>
<span class="image-caption text-muted">  </span></p>

<p>My version of it is me holding the fountain pen that I used during my university studies. French schools have a fascination for fountain pens, so I have memories of struggling to use one when I was in primary school.</p>

<p><a href="/assets/images/photofeed/2023-12-06-hand/hand-youssef.jpg" data-glightbox="" data-description="">
  <img class="image-overflow" src="/assets/images/photofeed/2023-12-06-hand/hand-youssef.jpg" />
</a>
<span class="image-caption text-muted">  </span></p>

<p>Then this was one of the first items I bought when I landed in France, because I knew I would be using it a lot. Fountain pens adapt to your handwriting so you feel a special connection with them after using them for a while.</p>

<p>It’s also the pen that was with me during my formative years, when I left my teenage years to become a “real adult”, and I used that same pen to sign the paperwork that would take me to Texas then to Sweden.</p>

<p>It carries so much of my history that I felt like I was taking a portrait of myself even without having my face on the picture.</p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[So, the assignment was to “paraphrase” a portrait, by drawing inspiration from another portrait (could be a photo, painting, sculpture etc) and make your version of it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2023-12-06-hand.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2023-12-06-hand.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Principles and mental models from the Internet</title><link href="https://yboulkaid.com/2022/04/23/principles.html" rel="alternate" type="text/html" title="Principles and mental models from the Internet" /><published>2022-04-23T17:19:00+00:00</published><updated>2022-04-23T17:19:00+00:00</updated><id>https://yboulkaid.com/2022/04/23/principles</id><content type="html" xml:base="https://yboulkaid.com/2022/04/23/principles.html"><![CDATA[<p>This is a collection of principles and mental models I find useful or
interesting. I might not 100% adhere to all of them and it serves mostly as a
written document I can revisit to remind myself of those concepts.</p>

<h3 id="personal-development">Personal development:</h3>
<ul>
  <li>Money is life energy. <a href="https://www.goodreads.com/book/show/78428.Your_Money_or_Your_Life">Vicki Robin - Your Money or Your Life</a></li>
  <li>Keep your identity small. <a href="http://www.paulgraham.com/identity.html">Paul Graham</a></li>
  <li>Taming your inner mammoth. <a href="https://waitbutwhy.com/2014/06/taming-mammoth-let-peoples-opinions-run-life.html">Wait but why</a></li>
  <li>Solitude can mean introspection, it can mean the concentration of focused work, and it can mean sustained reading. It can also mean friendship. <a href="https://theamericanscholar.org/solitude-and-leadership/">Solitude and leadership</a></li>
</ul>

<h3 id="work">Work:</h3>
<ul>
  <li>Strong opinions, loosely held.</li>
  <li>It’s your professional obligation to push back on unreasonable expectations. Your bosses may not like it at first, but they will respect you for it. <a href="https://gist.github.com/bricker/cb811b3b86d767124801">Source</a></li>
  <li>If you do the same thing as everyone else, you’re going to be average.</li>
  <li>Everything is a system. Think in systems.</li>
  <li><a href="https://commoncog.com/blog/heuristics-are-ok/">Heuristics Are OK</a>:
Heuristics (“mental shortcuts”) are have two sides you have to balance between:
    <ul>
      <li>a bad thing (base of cognitive biases)</li>
      <li>a good thing (pattern matching, base of “gut feeling” in experts, aka tacit knowledge)</li>
    </ul>
  </li>
</ul>

<h3 id="time-management">Time management:</h3>
<ul>
  <li>Saying yes to something means saying no to something else</li>
  <li>Doing something good but not essential is saying no to doing something essential</li>
  <li>If you’re doing the right things, it doesn’t matter how much time you spend on them. <a href="https://tim.blog/2019/01/09/greg-mckeown-essentialism/">Podcast: How to Master Essentialism</a></li>
  <li>“Don’t be a donkey” aka <a href="https://en.wikipedia.org/wiki/Buridan%27s_ass">Buridan’s ass</a>. You can have everything, if you do one thing at a time.</li>
  <li>Other People’s Problems (OPP): Recognize them when they hit your inbox and ignore them.</li>
</ul>

<h3 id="management">Management:</h3>
<ul>
  <li>Culture is determined by which info you share and how decisions are made</li>
  <li>Delegate outcomes, not tasks:
    <ul>
      <li><a href="https://m.signalvnoise.com/delegate-outcomes-not-activities/">SvN blog</a></li>
      <li><a href="https://youtu.be/qOTYgcdNrXE?t=1200">Example in the military</a></li>
    </ul>
  </li>
</ul>

<h3 id="learning">Learning:</h3>
<ul>
  <li><a href="https://www.lesswrong.com/posts/4FZfzqMtwQZES3eqN/slow-is-smooth-and-smooth-is-fast">Slow is smooth, and smooth is fast</a></li>
  <li><a href="https://commoncog.com/blog/get-numb-get-good/">Get numb before you get good</a></li>
  <li><a href="https://skepticalinquirer.org/1987/10/the-burden-of-skepticism/">Balancing openness and skepticism</a></li>
</ul>

<blockquote>
  <p>It seems to me what is called for is an exquisite balance between two conflicting needs: the most skeptical scrutiny of all hypotheses that are served up to us and at the same time a great openness to new ideas. Obviously those two modes of thought are in some tension. But if you are able to exercise only one of these modes, which ever one it is, you’re in deep trouble. If you are only skeptical, then no new ideas make it through to you. You never learn anything new. You become a crotchety old person convinced that nonsense is ruling the world. (There is, of course, much data to support you.) But every now and then, maybe once in a hundred cases, a new idea turns out to be on the mark, valid and wonderful. If you are too much in the habit of being skeptical about everything, you are going to miss or resent it, and either way you will be standing in the way of understanding and progress. On the other hand, if you are open to the point of gullibility and have not an ounce of skeptical sense in you, then you cannot distinguish the useful ideas from the worthless ones. If all ideas have equal validity then you are lost, because then, it seems to me, no ideas have any validity at all.</p>
</blockquote>

<ul>
  <li>Consume books and art that stood the test of time.</li>
  <li>Thinking from first principles.</li>
</ul>

<h3 id="arguing">Arguing:</h3>
<ul>
  <li>When arguing, always consider the best version of the opposing argument (steel man argument):</li>
</ul>

<blockquote>
  <p>The most powerful way to avoid using bad arguments and to discourage their use by others is to follow the principle of charity and to argue against the strongest and most persuasive version of their grounds.</p>
</blockquote>

<p><a href="https://fs.blog/2020/05/bad-arguments/">source</a></p>

<h3 id="creative-work">Creative work:</h3>
<ul>
  <li>Ira Glass’ <a href="https://www.brainpickings.org/2014/01/29/ira-glass-success-daniel-sax/">taste gap</a></li>
  <li>Writing <a href="https://medium.com/swlh/fast-bad-and-rong-a-mantra-for-creating-the-new-and-impossible-bdd22da52e3f">FBR (Fast, Bad and Rong)</a></li>
</ul>

<h3 id="people">People:</h3>
<ul>
  <li><a href="https://seths.blog/2013/07/people-like-us-do-stuff-like-this/">People like us, do things like this</a></li>
  <li><a href="https://moretothat.com/the-power-of-the-dissenting-voice">The banality of evil</a></li>
</ul>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[This is a collection of principles and mental models I find useful or interesting. I might not 100% adhere to all of them and it serves mostly as a written document I can revisit to remind myself of those concepts.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2022-04-23-principles.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2022-04-23-principles.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">When Moroccan music crosses borders</title><link href="https://yboulkaid.com/2022/04/13/moroccan-music.html" rel="alternate" type="text/html" title="When Moroccan music crosses borders" /><published>2022-04-13T19:45:00+00:00</published><updated>2022-04-13T19:45:00+00:00</updated><id>https://yboulkaid.com/2022/04/13/moroccan-music</id><content type="html" xml:base="https://yboulkaid.com/2022/04/13/moroccan-music.html"><![CDATA[<p>Morocco has an <a href="https://en.wikipedia.org/wiki/Music_of_Morocco">extensive range of musical
styles</a>, most of them regional
and hard for newcomers to discover and appreciate. In recent years,
musicians started experimenting mixing traditional music with other genres,
which helps make it more accessible. This is a curated selection of such
crossovers, which I hope will make you curious about Moroccan music. Happy listening!</p>

<p><strong>Note: Gnawa music</strong><br />
Probably the most exported style of Moroccan music,
<a href="https://en.wikipedia.org/wiki/Gnawa_music">Gnawa</a> is a genre with
religious roots and is still played in spiritual ceremonies today.</p>

<p>After the 90s, Gnawa music has been modernized and it is now played outside
of religious ceremonies. Many musicians, both local and foreign, experimented
with mixing Gnawa rythms with other styles. The first three entries of this
list are examples of this.</p>

<hr />

<p><strong>1. Majid Bekkas &amp; Louis Sclavis, Minino Garay - Boulila</strong><br />
<em>Gnawa + Jazz trio</em></p>

<p>Musician Majid Bekkas combines blues, jazz and gnawa music.</p>
<iframe class="d-block mx-auto" width="560" height="315" src="https://www.youtube-nocookie.com/embed/-fSvROELuU0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<hr />

<p><strong>2. Jimmy Page, Robert Plant - Wah Wah</strong><br />
<em>Gnawa + Rock</em></p>

<p>14 years after Led Zeppelin‘s dissolution, former members Jimmy Page and Robert
Plant recorded the live album “No Quarter”. The album was partly recorded in
Morocco with a Gnawa band. “Wah Wah” is one of the songs they recorded
together. You can listen to it <a href="https://youtu.be/_13C5L9Lx8s">here</a>.</p>

<hr />

<p><strong>3. Snarky Puppy &amp; Hamid El Kasri - Lalla Aicha + Lingus</strong><br />
<em>Gnawa + Jazz ensemble</em></p>

<p>During the the 2018 Essaouira Gnawa festival, award-winning jazz collective
Snarky Puppy collaborated with a prominent Gnawa band for a unique concert. The
set’s finale is a crossover of popular Snarky Puppy song Lingus with a staple
of Gnawa music, Lalla Aicha.</p>

<iframe class="d-block mx-auto" width="560" height="315" src="https://www.youtube-nocookie.com/embed/cCZJ_f29Lyg?start=2078" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<hr />

<p><strong>4. Aza - Tifiras</strong><br />
<em>Tamazight music + Jazz</em></p>

<p>AZA unites traditional Tamazight (Berber) music, indigenous to the Atlas
Mountains of Morocco, with the jazz and soul influences of its diverse members.
Although they are now US-based, the founding members originally come from the
small town of Imintanoute, my father’s hometown.</p>

<iframe class="d-block mx-auto" width="560" height="315" src="https://www.youtube-nocookie.com/embed/PgFFgskYQEw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<hr />

<p><strong>5. Oum - Lágrimas negras</strong><br />
<em>Moroccan soul + Cuban trova</em></p>

<p>Lágrimas negras is a popular Cuban song first recorded in the 1930s. Moroccan
singer Oum covers this song, and translates parts of it to
<a href="https://en.wikipedia.org/wiki/Moroccan_Arabic">Darija</a>, the moroccan dialect
of Arabic. This is one of my favorite pieces, and combines elements from
Morocco, Cuba and France.</p>

<iframe class="d-block mx-auto" width="560" height="315" src="https://www.youtube-nocookie.com/embed/rsTOMQoRY4I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<hr />

<p><strong>6. Abdessadeq Cheqara - Bent Bladi</strong><br />
<em>Andalusi music + Flamenco</em></p>

<p><a href="https://en.wikipedia.org/wiki/Andalusi_classical_music">Andalusi music</a>
is more than a thousand years old, and is in its traditional form a very formal
genre, akin to classical music. Abdessadeq Cheqara, during a trip to
Spain in 1982, collaborated to produce a combination of andalusi music and
flamenco, with intertwining Arabic and Spanish lyrics. This has become one of
his most popular songs and a tune most Moroccans instantly recognize.</p>

<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;overflow:hidden" frameborder="0" type="text/html" src="https://www.dailymotion.com/embed/video/x8yuuq?autoplay=1" width="100%" height="100%" allowfullscreen="" allow="autoplay"> </iframe> </div>

<hr />

<p><strong>7. Hindi zahra - Imik Si Mik</strong><br />
<em>Tamazight music + Folk</em></p>

<p>Hindi Zahra is one of the first artists to mix tamazight music and Western-inspired folk, and sings in both berber and english in the same song.</p>
<iframe class="d-block mx-auto" width="560" height="315" src="https://www.youtube-nocookie.com/embed/-ik1xGwpUeQ " title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[Crossovers between traditional Moroccan music and other genres]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2022-04-13-moroccan-music.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2022-04-13-moroccan-music.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Silencing the Kinesis Advantage 2</title><link href="https://yboulkaid.com/2022/03/15/kinesis.html" rel="alternate" type="text/html" title="Silencing the Kinesis Advantage 2" /><published>2022-03-15T18:10:00+00:00</published><updated>2022-03-15T18:10:00+00:00</updated><id>https://yboulkaid.com/2022/03/15/kinesis</id><content type="html" xml:base="https://yboulkaid.com/2022/03/15/kinesis.html"><![CDATA[<p>After years of typing on thin Apple keyboards, my fingers started to hurt. First a little, then badly. Fearing for my career, I looked for solutions to fix that, and ended up splurging on a Kinesis Advantage 2.</p>

<p>I justified the expense by the fact that the praise for that piece of hardware is <a href="https://news.ycombinator.com/item?id=12237890">almost</a> <a href="https://old.reddit.com/r/ergodox/comments/m28rfi/after_a_decade_of_using_a_kinesis_advantage_i/">universal</a>, and even our beloved <em><a href="https://avdi.codes/why-you-should-spend-350-on-a-computer-keyboard">thought</a> <a href="https://martinfowler.com/articles/kinesis-advantage2.html">leaders</a></em>™️ seem to be in on it.</p>

<p>I swear by it now, but damn, that thing is <strong>loud</strong>.</p>

<h2 id="where-does-the-noise-come-from">Where does the noise come from?</h2>

<p>As with all mechanical keyboards, there are two main sources for the noise:</p>
<ul>
  <li><strong>The case</strong>, which acts as an echo chamber amplifying the vibrations from the keys. This is particularly bad on the Advantage, with its large hollow space between the keywells.</li>
  <li>The <strong>MX switches</strong> themselves, especially if you’re bottoming out when typing.</li>
</ul>

<p>To get rid of the noise, both of these problems have to be addressed.</p>

<h2 id="1-dampening-the-case">1. Dampening the case</h2>

<p>The best way to reduce the vibrations from the case is to line it with dampening foam. The dampening material will absorb the vibrations instead of letting them bounce around until they hit your ears.</p>

<p>There are various options here: Dynamat, Sorbothane, Neoprene or plain old packing foam. The trade-offs are cost and weight: the heavier the lining is, the stronger the dampening — more weight equals more vibrations absorbed. But these materials can get expensive pretty quickly.</p>

<p>I lucked out and found some cheap Dynamat Xtreme on a small local auto parts website, and installed it inside the case:</p>

<p><a href="/assets/images/silencing-kinesis/kinesis_6.jpg" data-glightbox="" data-description="The Kinesis Advantage with the Dynamat Xtreme.">
  <img class="image-overflow" src="/assets/images/silencing-kinesis/kinesis_6.jpg" />
</a>
<span class="image-caption text-muted"> The Kinesis Advantage with the Dynamat Xtreme. </span></p>

<p><a href="/assets/images/silencing-kinesis/kinesis_3.jpg" data-glightbox="" data-description="The inside of the case, with the PCB exposed.">
  <img class="image-overflow" src="/assets/images/silencing-kinesis/kinesis_3.jpg" />
</a>
<span class="image-caption text-muted"> The inside of the case, with the PCB exposed. </span></p>

<p><a href="/assets/images/silencing-kinesis/kinesis_4.jpg" data-glightbox="" data-description="The case, lined with Dynamat Xtreme.">
  <img class="image-overflow" src="/assets/images/silencing-kinesis/kinesis_4.jpg" />
</a>
<span class="image-caption text-muted"> The case, lined with Dynamat Xtreme. </span></p>

<h2 id="2-the-switches">2. The switches</h2>

<p>A classic drawback of mechanical keyboards is that the switches themselves are loud. Fortunately, this is an almost-solved problem, with solutions like the 
<a href="https://uniqey.net/en/accessories/17/qmx-clips-pcb-mount-110-pcs.">Uniqey QMX clips</a> made to solve exactly this problem. So we can just throw money at it.</p>

<p>The clips come in two flavors: plate mounted and PCB mounted. The Kinesis Advantage <strong>needs both variants</strong>: the thumb cluster switches are mounted directly on the PCB, whereas the keywell ones are mounted on a plate.</p>

<p><a href="/assets/images/silencing-kinesis/kinesis_2.jpg" data-glightbox="" data-description="Keycaps removed.">
  <img class="image-overflow" src="/assets/images/silencing-kinesis/kinesis_2.jpg" />
</a>
<span class="image-caption text-muted"> Keycaps removed. </span></p>

<p><a href="/assets/images/silencing-kinesis/kinesis_5.jpg" data-glightbox="" data-description="All keycaps in place. Note the colors: white keycaps are plate-mounted, transparent are PCB-mounted.">
  <img class="image-overflow" src="/assets/images/silencing-kinesis/kinesis_5.jpg" />
</a>
<span class="image-caption text-muted"> All keycaps in place. Note the colors: white keycaps are plate-mounted, transparent are PCB-mounted. </span></p>

<h2 id="result">Result</h2>

<p>After putting everything back together, the keyboard is much more silent. It’s also significantly heavier — and expensive 😬.</p>

<p>Here’s a before/after audio sample. Unfortunately the levels between recordings aren’t normalized, so the “after” doesn’t sound much quieter :( It’s definitely the case in real life though! If you pay attention, you can notice that the sound got less “clicky” after the modifications.</p>

<div class="text-center">
  <audio controls=""> 
  <source src="/assets/audio/Kinesis.m4a" type="audio/mp4" />
  <source src="/assets/audio/Kinesis.mp3" type="audio/mpeg" />
  Your browser does not support the <code>audio</code> element.
  </audio>
</div>

<p>Overall I’m really happy with the result and it made for a good weekend project!</p>

<p><strong>Notes:</strong></p>

<p>I considered other alternatives to further silence the keyboard, but ultimately decided against them because I was happy enough with the result:</p>
<ul>
  <li>Getting <a href="https://keycap.sh/">PBT keycaps</a>, which are heavier and produce a slightly quieter (and deeper) sound.</li>
  <li>Getting the Advantage with the quiet LF switches rather than the Cherry MX brown switches. This model was not available when I ordered mine, and I didn’t want to wait for it to arrive, for the sake of my fingers.</li>
</ul>

<p><strong>Links:</strong></p>
<ul>
  <li>The main inspiration for this project was <a href="https://www.reddit.com/r/kinesisadvantage/comments/indito/keynoise_modifications/g49tb8d/">this comment</a> on reddit.</li>
  <li>A <a href="https://blog.wooting.nl/how-to-silence-and-sound-dampen-your-mechanical-keyboard/">good overview</a> of noise sources in mechanical keyboards and how to counter them.</li>
</ul>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[After years of typing on thin Apple keyboards, my fingers started to hurt. First a little, then badly. Fearing for my career, I looked for solutions to fix that, and ended up splurging on a Kinesis Advantage 2.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2022-03-15-kinesis.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2022-03-15-kinesis.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">My Software Engineering Values</title><link href="https://yboulkaid.com/2022/03/11/values.html" rel="alternate" type="text/html" title="My Software Engineering Values" /><published>2022-03-11T18:10:00+00:00</published><updated>2022-03-11T18:10:00+00:00</updated><id>https://yboulkaid.com/2022/03/11/values</id><content type="html" xml:base="https://yboulkaid.com/2022/03/11/values.html"><![CDATA[<h2 id="software-should-empower-people">Software should empower people</h2>

<p>Production software should empower users to do things that were once painful or
impossible. There are far too many paper cuts in the software around us today,
and I want the product I work on to be a well-deserved break from them.</p>

<p>Software that doesn’t make people’s life easier isn’t worth writing.</p>

<h2 id="start-with-why">Start with why</h2>

<p>Whenever working on a feature, I want to understand why it is needed, what
value it is providing, to whom, etc…</p>

<p>This helps me get to the core issue I am trying to solve, guide my work and
understand which tradoffs are possible to make. If you work with me, “why are
we doing this?” will be by far the question you will hear the most.</p>

<h2 id="i-take-pride-in-my-work">I take pride in my work</h2>

<p>Any piece of code I write reflects on me and my ability to write good,
maintainable code.</p>

<p>I strive to be nice to myself and my fellow colleagues by writing code that’s
clear, well-designed, readable and even boring.</p>

<h2 id="code-is-a-liability">Code is a liability</h2>

<p>I think of every line of code written as a liability to the team that will have to
understand and maintain it.</p>

<p>As a software engineer, my goal is to provide business value, not to write
code. If I can provide the same value without writing code, I will try to do
so.</p>

<h2 id="the-value-of-good-enough">The value of good-enough</h2>

<p>A good-enough solution today is more valuable than a perfect solution tomorrow.</p>

<p>I believe in shipping early, scoped down, solutions that can be used as a basis
for iteration. Then iterating just enough to provide the business value that
makes sense for the current need and scope.</p>

<p>Shipping is a goldilocks game, and the product should be neither rough on the
edges nor an overengineered page that will delight its users on every click
when it’s shipped, one year from now.</p>

<h2 id="there-is-no-right-or-wrong-only-tradeoffs">There is no right or wrong, only tradeoffs</h2>

<p>In software and in life, the answer to many questions is “it depends”. Every
choice made involves tradeoffs, wether explicit or implicit.</p>

<p>I strive to always be aware of this, and ask which tradeoffs will help my case
and my users best in any given situation.</p>

<h2 id="some-strong-opinions-strongly-held">Some strong opinions, strongly held</h2>

<p>I try to be not opinionated about too many things, and <a href="http://www.paulgraham.com/identity.html">keep my identity
small</a>.</p>

<p>In the areas where I do have opinions, I believe in them enough to act on them
with confidence and argue my stance strongly.</p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[Software should empower people]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2022-03-11-values.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2022-03-11-values.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">An ode to Ruby</title><link href="https://yboulkaid.com/2022/01/10/ode-to-ruby.html" rel="alternate" type="text/html" title="An ode to Ruby" /><published>2022-01-10T14:35:00+00:00</published><updated>2022-01-10T14:35:00+00:00</updated><id>https://yboulkaid.com/2022/01/10/ode-to-ruby</id><content type="html" xml:base="https://yboulkaid.com/2022/01/10/ode-to-ruby.html"><![CDATA[<div class="text-center">
  <p>‘tis Christmas season, time for snow, carols and joy,<br />
  The code freeze is here, yesterday was my last deploy.<br />
  Still my favorite moment is when under the tree,<br />
  I always find a new version of ruby.</p>

  <p>Today I take this opportunity to reflect on the past<br />
  Where my journey began, not knowing how long it would last.<br />
  _why’s poignant guide was an amusing read<br />
  It made me smile and think: “wow, this language is weird!”</p>

  <p>Writing programs soon felt simple, elegant and natural.<br />
  No convoluted syntax here. Trust me, I looked.<br />
  It was the best of perl, lisp and smalltalk,<br />
  And none of the quirks. That’s it, I was hooked!</p>

  <p>And then there was this thing called Rails,<br />
  A blog in ten minutes, could this be possible?<br />
  It was a lot to take in, but I hung in there<br />
  The tutorial helped a lot, thank you Michael Hartl!</p>

  <p>Years have passed, and Rails is now my daily craft<br />
  I still enjoy every moment of it. Yes, even ActiveRecord.<br />
  And when people ask me “is ruby dead?”, I just answer:<br />
  No. It’s just boring, in the best sense of the word.</p>

  <p>Don’t get me wrong, I love innovation and new ideas<br />
  But it sometimes seems like the web has jumped the shark<br />
  So I’m happy to get off the new framework treadmill<br />
  No web3 for me, thanks. I’m off to the park!</p>

  <p>For I don’t want shiny. I want productive and simple.<br />
  What I need is to write code, and maybe be weird once or twice.<br />
  Join us under our big tent, you are more than welcome<br />
  For Matz is nice and so we are nice.</p>

  <p>So here’s to you, Ruby, Rails and the whole community,<br />
  May you still thrive and make people cheery.<br />
  I leave you now, and go back to my desk<br />
  For I once again have trouble installing Nokogiri.</p>
</div>

<hr />

<p>Edit: Hello <a href="/assets/images/ode-to-ruby/hn.png">hacker news</a>! 👋 You can find the discussion <a href="https://news.ycombinator.com/item?id=29874616">here</a></p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[A love letter to Ruby and Rails.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2022-01-10-ode-to-ruby.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2022-01-10-ode-to-ruby.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Letter to a junior web developer</title><link href="https://yboulkaid.com/2021/12/17/letter-junior.html" rel="alternate" type="text/html" title="Letter to a junior web developer" /><published>2021-12-17T21:35:00+00:00</published><updated>2021-12-17T21:35:00+00:00</updated><id>https://yboulkaid.com/2021/12/17/letter-junior</id><content type="html" xml:base="https://yboulkaid.com/2021/12/17/letter-junior.html"><![CDATA[<p>Hi there,</p>

<p>So you have just accepted your first job offer in tech. Maybe you even updated your Linkedin profile to say “Junior web developer”.</p>

<p>First of all, congratulations for making it to this point! Whether this is your first job or you have transitioned from another career, I know that looking for that first job is not easy.</p>

<p>Welcome to the web development industry. We’re a young field, and we’re collectively still figuring some things out, as you are. For example, you might have noticed that we tend to suck at hiring processes.</p>

<p>There is one thing we know for sure: <strong>we need you</strong>. We need way, way more members in our community than we currently have, and almost all teams I talk to are understaffed. This is a great time to join us.</p>

<p>This is the beginning of a long journey for you. “Web development” is a broad topic, and there is enough material for a lifetime. I mean, look at this:</p>

<p><a href="/assets/images/letter-junior/Rails_Competencies.png" data-glightbox="" data-description="Image from the Hack Reactor (formerly MarkerSquare) 6-week bootcamp">
  <img class="image-overflow" src="/assets/images/letter-junior/Rails_Competencies.png" />
</a>
<span class="image-caption text-muted"> Image from the Hack Reactor (formerly MarkerSquare) 6-week bootcamp </span></p>

<p>If you think this is overwhelming, I completely agree. But the key thing is that you <strong>don’t need to know all of this to be a good developer</strong>. Not only that, it’s actually rare to find someone who’s fluent in all these aspects. From now on, you will slowly pick up some branches of that tree, expanding your knowledge bit by bit, day by day.</p>

<p>The journey you embarked on is one of learning. Faced with this, I imagine your next questions are: how do you even take on something so huge? What to learn? How? Where to start? When to stop?</p>

<p>This is what I am going to cover in the rest of this letter. This is the advice I wish I had when I started my own carrer.</p>

<hr />

<h2 id="1-what-to-learn">1. What to learn?</h2>
<h3 id="basic-fluency-in-the-core-technologies-of-your-stack">Basic fluency in the core technologies of your stack</h3>
<p>As with everything, we start with the basics: understand what technologies you are going to be using in your daily work, and become fluent in them. This means understanding the syntax of most of the code you’re reading and have a general idea of how different parts of the system fit together.</p>

<p>A common mistake I see is new developers learning new programming languages or frameworks before spending meaningful time with the one they started with. Stick to one and become proficient in it. This will make you build the foundational knowledge you need to progress.</p>

<h3 id="the-fundamentals">The fundamentals</h3>
<p>Fundamentals are the basic concepts that are used all over the place, regardless of technology. They are valuable to learn because:</p>
<ul>
  <li>They don’t depend on any specific technology, programming language or framework. This means that you <strong>only need to learn them once</strong>, then that knowledge can be reused for other jobs, projects and teams.</li>
  <li>New concepts “click” easier when you can see the big picture. The more you know, the easier it is to learn new things.</li>
</ul>

<p>Examples of fundamental concepts:</p>
<ul>
  <li>The HTTP request/response cycle</li>
  <li>The server/client architecture. What is a web server, a client?</li>
  <li>The DOM and its interaction with the browser API</li>
  <li>HTML/CSS</li>
  <li>Git</li>
</ul>

<p>Thoughbot <a href="https://thoughtbot.com/blog/what-technologies-should-i-learn#evergreen-skills">has a good list covering these</a>, what they call “evergreen skills”.</p>

<p>This is often a place I suggest beginners to focus on as they are often skipped by education programs: fresh graduates tend to have a more computer sciency background, whereas many bootcamps focus on teaching you the tools that you need on your CV to get a job, but skip the fundamentals.</p>

<h3 id="learn-your-tools">Learn your Tools</h3>

<p>By tools, I mean anything that <em>use to do</em> the job, but are not part of the job assignment per se. You are going to spend a lot of time using your tools, so invest some time in learning them so you can be fluent using them.</p>

<p>Some examples are:</p>
<ul>
  <li>Possibly a <strong>new operating system</strong> (if you’re transitioning from Windows to Mac for example).</li>
  <li>Your <strong>text editor</strong>. Text editors are packed full of features that are sometimes not very discoverable. You will spend most of your time in them, reading and writing code. Being comfortable in your editor will help you in many, many ways, so it’s worth it to spend some time building up your skills there.</li>
  <li>The <strong>terminal/shell</strong>. This is a daunting one for beginners, again because of the poor discoverability. However, you only need to know the basics to get you started, you pick up the rest as you go. I recommend the <a href="https://www.learnenough.com/command-line-tutorial">learn enough book series</a> as a starting point.</li>
  <li><strong>Git</strong>: this is also one that has scarred many beginners, and the mere mention of a big merge conflict will make any developer’s heart sink a little. It’s one of these tools that is more complex than they need to be, but there are some ways to make your work easier:
    <ul>
      <li>learn the basic concepts, they’re enough to get you out of many situations. Here too, I recommend the <a href="https://www.learnenough.com/git">Learn Enough</a> book.</li>
      <li>You could use a GUI program like <a href="https://www.git-tower.com/">Tower</a>, <a href="https://git-fork.com/">Fork</a> or <a href="https://www.gitkraken.com/">GitKraken</a> to help you visualize what’s happening.</li>
    </ul>
  </li>
  <li><strong>Debugging tools</strong> in your language of choice: learn how to inspect variables, stop the code at any point, look around. Debugging is a whole skillset that is often overlooked, but it can help a lot when things don’t work the way you think they should.</li>
  <li><strong>Internal tools</strong> for the company, e.g. project management like Jira or Github.</li>
</ul>

<h3 id="learn-to-communicate">Learn to communicate</h3>
<p>Learning how to communicate with your team and peers is one of the most useful skills you can learn, as it will have ripple effects on everything else.</p>

<p>Learn to <strong>express what you don’t know</strong>. Learn to <a href="https://jvns.ca/blog/2021/10/21/how-to-get-useful-answers-to-your-questions/">ask questions</a> in a way that make them easy to answer. Try to explain things to yourself so you can clarify what you don’t know.</p>

<p>This becomes even more important when working remotely, because communication isn’t instantaneous. One well formulated question can avoid some frustrating back and forth, so be generous on details. When in doubt, lean towards overcommunicating. What’s obvious to you might not be to anothers.</p>

<h2 id="2-your-learning-tools-how-to-learn">2. Your learning tools: how to learn?</h2>

<h3 id="learn-to-learn">Learn to learn</h3>
<p>Learning is itself a skill — talk about meta! This is another one of those areas that has ripple effects throughout everything you do. Learning to learn is too broad a subject to fully cover here, but here are some pointers I found useful:</p>
<ul>
  <li>Mix <a href="https://www.joshwcomeau.com/blog/how-to-learn-stuff-quickly/">structured and unstructured learning</a>, by alternating guided tutorials and small independent projects.</li>
  <li>Find your style of learning:
    <ul>
      <li>Do you prefer to learn the fundamentals of a subject and build up from there (“bottom up”)? Or are you more likely to learn by doing and practice (“top-down”).</li>
      <li>Do you prefer learning from written material (blog posts, books) or from video courses?</li>
    </ul>
  </li>
</ul>

<p>This is of course highly personal. Be mindful about how you learn most effectively and seek learning material that fits your style.</p>

<h3 id="get-help">Get help</h3>
<p>If you’re in a good team, they will guide you through your learning journey. Don’t be afraid to ask questions and seek feedback from them.</p>

<p>On top of that, <strong>find a mentor</strong> if you can. Maybe several. They will be someone who you can turn to when you have questions and will have the bandwidth and patience to help you. Having this relationship with someone makes it less scary to “ask stupid questions” (which you should absolutely do!). It’s important to find someone who you click with, and whose style of teaching you like. The same way different people learn in different styles, not all mentors fit everyone.</p>

<p>A couple reasons why mentors help in ways that are hard to replace:</p>
<ul>
  <li>There is a lot of content on the web of dubious quality. It’s hard for a newcomer to distinguish the good from the bad when reading blog posts and StackOverflow answers.</li>
  <li>They help you see the big picture when you’re stuck on a detail. This way, you not only get an answer to your immediate question, but you also get to know <em>why</em> things are a certain way.</li>
</ul>

<h3 id="keep-a-learning-diary">Keep a learning diary</h3>

<p>Recording notes, ideas and questions is a practice that can be find in many disciplines, for example <a href="https://en.m.wikipedia.org/wiki/Inventor%27s_notebook">engineering notebooks</a> or <a href="https://en.m.wikipedia.org/wiki/Sketchbook">sketchbooks</a> for artists.</p>

<p>A learning diary is a key tool in your learning process. It’s what you use to offload your brain and keep track of:</p>
<ul>
  <li>What you have learned today.</li>
  <li>Questions or foreign concepts you have at the moment that you want to look up or ask someone about later.</li>
</ul>

<p>It helps you not get overwhelmed by all the things you don’t know yet and keep track of your progress. Looking back on last month’s entries and seeing how much you have evolved feels very rewarding, even though you may feel you haven’t progressed much.</p>

<p>The diary itself can be either a physical notebook or digital notes, up to you! The important thing is that you keep one.</p>

<h3 id="how-to-pick-learning-resources">How to pick learning resources</h3>
<p>There is no shortage of learning resources on the web today, but that doesn’t mean they’re all equal in quality. Here are a couple rules of thumb when it comes to choosing your learning resources:</p>

<ul>
  <li>Aim for complete books or courses rather than short blog posts or videos if you want to have a solid understanding of a concept. Blog posts or short videos are fine if you need to quickly look up a specific aspect or feature of a library or tool, but lack the in-depth elements that make for a complete understanding. To make things worse, some companies have a tendency to post low quality technical blog posts for SEO and visibility purposes, which can harm your understanding.</li>
  <li>Ask around for good learning resources in your specific domain. I recommend <a href="https://frontendmasters.com">Frontend Masters</a> for anything frontend and <a href="https://thoughtbot.com/upcase">Upcase</a> for ruby on rails.</li>
  <li>Learn to read technical documentation. You will have to read a lot of technical documentation as you work, and it can be hard to figure out what the relevant parts are.</li>
</ul>

<p>Other resources that newcomers tend to underestimate are <strong>podcasts</strong> and recording of <strong>conference talks</strong>. Here you don’t usually chose the exact subject, but instead trust the speaker or podcast hosts to do it for you. This can be very helpful for broadening your horizons to ideas you were not aware of, but it’s also what makes these very hit or miss: listen to a talk without having the necessary background knowledge and you’re not going to take away much from it.</p>

<p>So if you’re going this way, ask around you for podcasts or talks that fit your current level.</p>

<p><strong>A note on tutorials</strong>: Tutorials are a good resource to first get started with a new tool or technology, but it’s very easy to abuse them. You can end up writing the same app over and over again, without really gaining more value or understanding from the process (a.k.a. <em>tutorial hell</em>).</p>

<h2 id="3-programming-and-you">3. Programming and you</h2>
<h3 id="unlearning-bad-habits">Unlearning bad habits</h3>
<p>On your journey here you might have picked up some bad habits. You’ll need to unlearn them, as they will make life harder for you and can slow down your learning. Some common ones are:</p>

<ul>
  <li>Treating code as “magic incantations” and copy pasting code or commands you don’t understand. This is necessary in the beginning when you don’t have enough background to understand everything that’s happening. But after a certain point, you should grow weary of these and seek to understand the concepts behind everything you see or type.</li>
  <li>Making technical decisions because of what other people or organizations have done, without understanding why. Figure out why and how technical decisions are made, and what trade-offs are involved. Knowing the fundamentals helps tremendously here.</li>
</ul>

<h3 id="impostor-syndrome-and-you">Impostor syndrome and you</h3>
<p>This is not an easy profession to get into, and the amount of knowledge needed to tackle some apparently trivial issues is sometimes staggering and intimidating to a newcomer.</p>

<p>This might make you wonder if you’re smart enough for this job, and why you are the only one that doesn’t seem to “get it”. This especially applies if you come from a non-traditional background, such as a bootcamp after a career switch.</p>

<p>Impostor syndrome is real, and it’s not just you. Many people —including me— have dealt with this at some point in our lives, along with <a href="https://blog.sidebits.tech/programmers-emotions/">other not-so-nice emotions</a>. Don’t let that discourage you. It’s okay to not know everything, that’s why you are a junior after all.</p>

<p>Don’t compare yourself to people who have been doing this for a long time, they have had the time and space to practice and digest the knowledge bit by bit. You should, however, compare yourself to yesterday you, and make sure you’re continuously learning new things. This is the only comparison that matters or makes sense.</p>

<p><strong>Note on the complexity of the web today</strong>: At times you might feel that things are too complex, especially if you’re working in the javascript ecosystem. It’s not just you. This has been an ongoing gripe of web developers for years: our tools have become way too convoluted. <a href="https://rubyonrails.org/">Some</a> <a href="https://www.phoenixframework.org/">communities</a> are fighting back, but this is a story for another post.</p>

<h3 id="find-the-fun-in-programming">Find the fun in programming</h3>

<p>Depending on your background, you may or may not have programmed purely for fun. Having an idea in your head and making it come to life is a wonderful thing, and can be the source of a lot of creativity and joy.</p>

<p>Unfortunately this gets lost in the complexity of the tools and the pressure to code for a career. It’s hard to see the fun when your day job is making small changes in a large codebase where everything takes way longer than it should.</p>

<p>There’s nothing wrong with doing this purely for the money, but it’s missing out on the best part.</p>

<p>So, once in a while, try to make your own little thing, for you or someone you care about. Maybe make them an online picture gallery for their birthday. Or write a facebook chat bot filled with your in-jokes. An app doesn’t have to be used by millions to be successful, it can be a <a href="https://www.robinsloan.com/notes/home-cooked-app/">home cooked meal</a> for a selected few who will appreciate it and bring you joy.</p>

<p>The possibilities are endless, and this what attracted many of us in the first place. I hope you get to experience this too.</p>

<hr />

<p>Again, welcome to our industry and community, and I wish you a wonderful career!</p>

<p>Youssef</p>]]></content><author><name>Youssef Boulkaid</name></author><summary type="html"><![CDATA[The advice I wish I had when I started my carrer]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://yboulkaid.com/assets/images/social/2021-12-17-letter-junior.md.jpg" /><media:content medium="image" url="https://yboulkaid.com/assets/images/social/2021-12-17-letter-junior.md.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>