<?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>Forem: Corey Alexander</title>
    <description>The latest articles on Forem by Corey Alexander (@coreyja).</description>
    <link>https://forem.com/coreyja</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%2F40335%2Fbd633f76-aef5-43e5-be8f-91117a7f62f2.png</url>
      <title>Forem: Corey Alexander</title>
      <link>https://forem.com/coreyja</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/coreyja"/>
    <language>en</language>
    <item>
      <title>Introducing Byte Code Review Challenges</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Thu, 05 Sep 2024 14:04:04 +0000</pubDate>
      <link>https://forem.com/coreyja/introducing-byte-code-review-challenges-48l9</link>
      <guid>https://forem.com/coreyja/introducing-byte-code-review-challenges-48l9</guid>
      <description>&lt;p&gt;Hey Team!&lt;/p&gt;

&lt;p&gt;Today I'm excited to launch Bytes!&lt;/p&gt;

&lt;p&gt;Interactive coding games, with the first ones focusing on Code Review, which I think is a super important if under-appreciated part of software development&lt;/p&gt;

&lt;p&gt;Here is the first game if you are too impatient to read farther: &lt;a href="https://coreyja.com/bytes/level-0-0" rel="noopener noreferrer"&gt;https://coreyja.com/bytes/level-0-0&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is a Bug Hunt, where you are presented with a code diff that contains in this case 2 bugs that you need to find and leave comments on! You'll be scored based on the bugs you find and how fast you are! There is even a leaderboard to see how you stack up against your friends!&lt;/p&gt;

&lt;p&gt;Check out my introduction blogpost for the backstory and to learn more! &lt;a href="https://coreyja.com/posts/introducing-bytes/" rel="noopener noreferrer"&gt;https://coreyja.com/posts/introducing-bytes/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Introducing Bytes</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Tue, 03 Sep 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/introducing-bytes-kkp</link>
      <guid>https://forem.com/coreyja/introducing-bytes-kkp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey Team! 👋&lt;/p&gt;

&lt;p&gt;Been awhile; too long really! Life got in the way, but I’m back and ready to do more streams and write more posts.&lt;/p&gt;

&lt;p&gt;And today I’m super excited to introduce one of the things that got be back and excited about making content again!&lt;/p&gt;

&lt;p&gt;Today I’m launching Byte Challenges, or Bytes for short! These are going to be short ‘games’, designed to test your programming and code review skills. We are launching with a “Bug Hunt” but hope to have different formats in the future.&lt;/p&gt;

&lt;p&gt;If you want to skip right to the game you can find the &lt;a href="https://coreyja.com/bytes/level-0-0" rel="noopener noreferrer"&gt;first Byte here&lt;/a&gt;! Be sure to checkout the leaderboard too, and see how you stack up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background and Concept
&lt;/h2&gt;

&lt;p&gt;These challenges are using a platform one of my friends, &lt;a href="https://x.com/alialobai1" rel="noopener noreferrer"&gt;Ali&lt;/a&gt;, is working on called, &lt;code&gt;cookd&lt;/code&gt;!&lt;code&gt;cookd&lt;/code&gt; as a platform currently focuses on code review and reviewing diffs. It’s built as an interviewing tool, and it thats interesting to you definitely reach out to Ali, he’d love to give you a demo! But the interviewing angle isn’t as fun to me personally, I’m here for the games!&lt;/p&gt;

&lt;p&gt;I’ve always said that one of the most important skills for a software developer working with a team, is the ability to read code well and provide code review to their teammates. As I’ve become a more senior engineer I’ve seen how good Pull Request reviews can be a tool to teach and mentor others. But the flip side to that is reading code and reviewing others work, is also a skill that needs practice to get better.&lt;/p&gt;

&lt;p&gt;So when Ali reached out to show me &lt;code&gt;cookd&lt;/code&gt; and it’s focus on Pull Request reviews, I knew he was onto something and I wanted to integrate it into my site!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Birth of Bytes
&lt;/h2&gt;

&lt;p&gt;Ali explained the platform to me, but it wasn’t until I was solving my first puzzle that I fell in love with the format.&lt;/p&gt;

&lt;p&gt;We were on a video call chatting about what each of us had been up to recently, and Ali shared a link and told me to share me screen when I clicked on it. He wanted to see my live reaction to what we’d been cooking up, and I don’t think I disappointed him. The premise of the game was simple, he had taken a bit of open source code me and our mutual friend Seif had been working on and hidden a few bugs in it.&lt;/p&gt;

&lt;p&gt;Ali wanted to get my take on the platform, and see what I thought of everything. But I was way too distracted by the puzzle to care about anything else, it was a perfect Nerd Snipe for me. Especially with the bit of gamification thrown in; the counter on the side telling me how many bugs I had left to find and the timer constantly ticking down were all I could pay attention to. I turned on my internal ‘streamer mode’, and started thinking out loud trying to track down the third and final bug that was hidden. I was instantly hooked and after I failed to find the third bug we chatted about how I could start building these on my own and even integrate them into my site!&lt;/p&gt;

&lt;p&gt;We talked about the types of bug that I thought were good for this format, and the ones I thought were less fun and more annoying. For example that third bug that I was searching for, was a syntax error with the Rust turbo fish operator. The code read something like &lt;code&gt;collect::Vec&amp;lt;i32&amp;gt;()&lt;/code&gt; when it should have been &lt;code&gt;collect::&amp;lt;Vec&amp;lt;i32&amp;gt;&amp;gt;()&lt;/code&gt;, note the missing &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; around the &lt;code&gt;Vet&amp;lt;i32&amp;gt;&lt;/code&gt;. While that &lt;em&gt;was&lt;/em&gt; a bug in the code, it wasn’t one I would expect a human reviewer to catch. That’s the compilers job after all!&lt;/p&gt;

&lt;p&gt;Ali had been working on AI assisted tools to help create these games at scale, but I knew I was more interested in making hard crafted artisanal challenges for all of you, and with the Bytes were born!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Level 0-0
&lt;/h2&gt;

&lt;p&gt;Today I am very excited to introduce to you all the first Byte challenge! The first few of these will be in Rust, but I plan to branch out to other languages soon. Reach out and let me know what languages and types of puzzles you are interested in seeing!&lt;/p&gt;

&lt;p&gt;The first puzzle is titled &lt;code&gt;Level 0-0&lt;/code&gt; and I think its a great into to the platform and concept. It is in Rust, but I promise none of the bugs will be syntax errors, and I tried my best to make it pretty language agnostic as well. Even if you aren’t super familiar with Rust I encourage you to give this one a try, I think you’ll be surprised how approachable it is!&lt;/p&gt;

&lt;p&gt;I don’t want to spoil too much about this puzzle, you’ll just have to play it for yourself!&lt;/p&gt;

&lt;p&gt;You can try your Bug Hunting skills on this first challenge here: &lt;a href="https://coreyja.com/bytes/level-0-0" rel="noopener noreferrer"&gt;https://coreyja.com/bytes/level-0-0&lt;/a&gt;And after you’ve given it your best shot, check out the Leaderboard to see how others have done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Plans for “Bytes”
&lt;/h2&gt;

&lt;p&gt;The plan is to publish these one a week, on Monday’s. (This one is coming out on Tuesday, because it was a US holiday yesterday and definitely not because I hadn’t written this post yet!)&lt;/p&gt;

&lt;p&gt;On Monday’s a new Byte will be released, and I’ll spam it across my social media accounts!&lt;/p&gt;

&lt;p&gt;To follow up on Friday’s I’ll post a video ‘wrap-up’ talking about this weeks challenge, and showing the answers. For the one’s my friends write, I’ll do a live attempt at trying to solve it myself as part of the wrap-up!&lt;/p&gt;

&lt;p&gt;If you can’t wait till Friday to get the solution, consider sponsoring my work on Github Sponsors and you’ll get private access to the solution video as soon as the challenges come out on Monday.&lt;/p&gt;

&lt;p&gt;The leaderboards will based on the honor system. If you’ve watched the solution videos, please don’t go solve the challenge to get a perfect score on the leaderboard. Don’t be the reason I need to implement safe guards to keep this fun for everyone!&lt;/p&gt;

&lt;h2&gt;
  
  
  Call to Action
&lt;/h2&gt;

&lt;p&gt;And this is the part of the blog where I kinda want you to click away.&lt;/p&gt;

&lt;p&gt;To try this first challenge click here: &lt;a href="https://coreyja.com/bytes/level-0-0" rel="noopener noreferrer"&gt;https://coreyja.com/bytes/level-0-0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or to view the leaderboards head over here:&lt;a href="https://coreyja.com/bytes/level-0-0/leaderboard" rel="noopener noreferrer"&gt;https://coreyja.com/bytes/level-0-0/leaderboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to sponsor my check out my Github Sponsors Profile: &lt;a href="https://github.com/sponsors/coreyja" rel="noopener noreferrer"&gt;https://github.com/sponsors/coreyja&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you have feedback reach out! You can join my Discord sever and we can chat live: &lt;a href="https://coreyja.club/" rel="noopener noreferrer"&gt;https://coreyja.club&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can send me an &lt;a href="//mailto:bytes-feedback@coreyja.com"&gt;email&lt;/a&gt; or send a toot via one of my social media channels. I’ll be most active on Mastodon, but will do my best to respond on all platforms! &lt;a href="https://toot.cat/@coreyja" rel="noopener noreferrer"&gt;https://toot.cat/@coreyja&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And don’t forget to come back for the wrap-up video this Friday! If you want to be notified for each future Byte challenge, consider subscribing to my newsletter and each new challenge will land right in your inbox every Monday morning!&lt;/p&gt;

&lt;p&gt;I’m really excited to see what you all think about these challenges! Please do reach out and share your thoughts.&lt;/p&gt;

&lt;p&gt;In the meantime, I’m doing to be watching the leaderboard to see how everyone does! Good luck!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Easily use Github Avatars</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/easily-use-github-avatars-3j60</link>
      <guid>https://forem.com/coreyja/easily-use-github-avatars-3j60</guid>
      <description>&lt;p&gt;tldr: You can use avatars from Github by adding &lt;code&gt;.png&lt;/code&gt; to the end of a profile url. For instance this will show you my Github Avatar: &lt;code&gt;https://github.com/coreyja.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On stream on Sunday I was working on adding a Leaderboard for some coding 'games' that I'm going to be adding to the site soon! It's all based on Github usernames, and thats what I am displaying on the Leadboard. And I wanted to also include a Users github avatar!&lt;/p&gt;

&lt;p&gt;I had assumed I was going to need to hit the API to get an avatar for the user, and probably cache that somewhere on my side to avoid needing to make an API call for each page view.&lt;/p&gt;

&lt;p&gt;But it turns out there is an easier way!&lt;/p&gt;

&lt;p&gt;Github makes it really easy to grab a Users avatar, no API calls needed! You can just append &lt;code&gt;.png&lt;/code&gt; to a users profile URL to get their avatar. This worked great in an &lt;code&gt;img&lt;/code&gt; HTML tag!&lt;/p&gt;

&lt;p&gt;Here is an HTML &lt;code&gt;img&lt;/code&gt; tag that will display my Github Profile avatar!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="https://github.com/coreyja.png"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>github</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Make the Change Easy, Then Make the Easy Change</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Fri, 26 Jul 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/make-the-change-easy-then-make-the-easy-change-11be</link>
      <guid>https://forem.com/coreyja/make-the-change-easy-then-make-the-easy-change-11be</guid>
      <description>&lt;p&gt;A manta I’ve repeated for a while in my software career has been &lt;strong&gt;Make the Change Easy, Then make the Easy Change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This phrase is about adding new features to your code, but what it really gets at is the constant need to refactor your code to make it more amendable to the changes you want to make.&lt;/p&gt;

&lt;p&gt;When you go to add a new feature to your codebase, you are often faced with a decision:&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Hack in the needed functionality to the existing structure&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Refactor some stuff to make the new feature fit nicely&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Me and this mantra are advocating for the second option here. And that’s not to say that there aren’t times when the first “hacky” option is the right choice. But more often than not doing one hacky thing is a slippery slope to continuing to hack in new features, since each time you are in those code paths they are worse than the time before.&lt;/p&gt;

&lt;p&gt;By refactoring BEFORE you add a new feature your codebase is getting cleaner and cleaner as you go! As opposed to creating more tech debt with each PR, you can actually clean up your codebase as you go! This will pay for itself in the long run, AND has the benefit of making the work more “predictable”. In a clean, well organized code base there are less chances of running into something unexpected that drastically shifts the timelines for a project. In a messy codebase it’s common to find issues buried, or things that take longer to untangle than expected.&lt;/p&gt;

&lt;p&gt;Not only does cleaning up the codebase allow you to be more productive, it also helps be more predictable! And predictability is sometimes even more important than raw speed. Sometimes being finished a day or two earlier is not a deal breaker, but missing an agreed upon deadline because of a spagehti code bug put you off timeline can cause issues for the organization.&lt;/p&gt;

&lt;p&gt;I'm a firm believer that in 90% of circumstances its better to refactor the code ahead of an expected change, instead of hacking it in and just kicking the cleanup can down the road.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fallback Routing with Axum</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Tue, 27 Feb 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/fallback-routing-with-axum-4fm</link>
      <guid>https://forem.com/coreyja/fallback-routing-with-axum-4fm</guid>
      <description>&lt;p&gt;Yesterday I ran into a small problem with my Axum routing for my blog. So today I wanted to take 10 minutes and do quick write up about it!&lt;/p&gt;

&lt;p&gt;My blog uses &lt;code&gt;Axum&lt;/code&gt; as its Web Framework of choice. I was looking through some old emails and found one where a reader reached out about a post I made! (It was &lt;a href="https://coreyja.com/posts/vim-spelling-suggestions-fzf/" rel="noopener noreferrer"&gt;this one about FZF Spell Checking in VIM&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;But I realized that it was linking to an older URL format, The link was to &lt;code&gt;https://coreyja.com/blog/2018/11/10/vim-spelling-suggestions-fzf.html&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;And you can see I was using a different URL structure then, and my current blog didn't have a redirect setup!&lt;/p&gt;

&lt;p&gt;And that was our goal! I wanted &lt;code&gt;https://coreyja.com/blog/2018/11/10/vim-spelling-suggestions-fzf.html&lt;/code&gt; to redirect to &lt;code&gt;/posts/vim-spelling-suggestions-fzf&lt;/code&gt;. And I also decided that I wanted &lt;code&gt;blog/anything-else-here&lt;/code&gt; to redirect to &lt;code&gt;/posts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Simple enough!&lt;/p&gt;

&lt;p&gt;I added these two routes to my Axum Router function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.route("/blog/:year/:month/:date/:slug", get(redirect_to_new_post_url))
.route("/blog/*catchall", get(redirect_to_posts_index))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I expected this to work out of the box! But it didn't :sadnerd:&lt;/p&gt;

&lt;p&gt;Instead I got an error about conflicting routes. Luckily the answer is relatively easy, at least in my case! I just needed to use &lt;code&gt;nest&lt;/code&gt; to target all the &lt;code&gt;/blog&lt;/code&gt; urls and then use a &lt;code&gt;fallback&lt;/code&gt;. Here is what I ended up with!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.nest(
  "/blog",
  Router::new()
    .route("/:year/:month/:date/:slug", get(redirect_to_new_post_url))
    .fallback(redirect_to_posts_index)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now I was able to get all the redirects working as I wanted! Go check out that 'old' URL above now and with any luck you should be redirected to the right post!&lt;/p&gt;

</description>
      <category>axum</category>
      <category>rust</category>
      <category>webdev</category>
      <category>routing</category>
    </item>
    <item>
      <title>Video from Screenshots in Git History</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Sat, 13 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/video-from-screenshots-in-git-history-2999</link>
      <guid>https://forem.com/coreyja/video-from-screenshots-in-git-history-2999</guid>
      <description>&lt;p&gt;Here is a quick view of this Rust powered site as its been built! It does that annoying jumping in the middle when I didn't have consistent font loading, all fixed now!&lt;/p&gt;

&lt;p&gt;I've been using &lt;a href="https://shot-scraper.datasette.io/en/stable/" rel="noopener noreferrer"&gt;shot-scraper&lt;/a&gt; by simonw to take screenshots of my blog and save them to my repo.&lt;/p&gt;

&lt;p&gt;That means I have a history of what my site has been looking in prod!&lt;/p&gt;

&lt;p&gt;So I throw together a &lt;a href="https://github.com/coreyja/coreyja.com/blob/main/scripts/create_blog_history_video.rs" rel="noopener noreferrer"&gt;small Rust script&lt;/a&gt; calls out to &lt;code&gt;ffmpeg&lt;/code&gt; that compiles all the screenshots I have saved into a short movie&lt;/p&gt;

&lt;p&gt;I'll try to post a new one at the end of the year and we can see how it changes!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>coreyja weekly - January 12th</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Fri, 12 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/coreyja-weekly-january-12th-54pn</link>
      <guid>https://forem.com/coreyja/coreyja-weekly-january-12th-54pn</guid>
      <description>&lt;p&gt;Hey Team, let’s see if we can’t get back to doing these weekly!&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Week Recap
&lt;/h2&gt;

&lt;p&gt;](#week-recap)[&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Pillars of a Web App
&lt;/h3&gt;

&lt;p&gt;](#three-pillars-of-a-web-app)&lt;/p&gt;

&lt;p&gt;I don’t think this was technically this week, but I hadn’t mentioned it here so might as well now!&lt;/p&gt;

&lt;p&gt;I published a new Blog Post titled “Three Pillars of a Web App” of a web app, where I talk about my ideal web app structure. And the three processes to go into that: Server, worker and cron.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://coreyja.com/posts/three-pillars/" rel="noopener noreferrer"&gt;Check out the full post on my blog!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h3&gt;
  
  
  Sunday Stream
&lt;/h3&gt;

&lt;p&gt;](#sunday-stream)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/jdjxuU0kSRc" rel="noopener noreferrer"&gt;Watch the full stream on YouTube here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did my first stream of the New Year last Sunday the 7th! Was good to get back to streaming more ‘normal’ projects after doing Advent of Code in December and then taking a bit of a break for the Holidays.&lt;/p&gt;

&lt;p&gt;On this stream we worked on creating a small “framework” for my Cron and Worker processes in Rust. It’s following the same patterns from my “The Pillars of a Web App” post that I mentioned above.&lt;/p&gt;

&lt;p&gt;We broke out a small crate called &lt;code&gt;cja&lt;/code&gt;, which holds the code for our custom Cron and Job framework!&lt;/p&gt;

&lt;p&gt;SideNote: I’m really happy with the &lt;code&gt;cja&lt;/code&gt; name for that crate! Because it stands for “Cron, Jobs and Axum” and just so happens to perfectly match my initials!&lt;/p&gt;

&lt;p&gt;We used this new &lt;code&gt;cja&lt;/code&gt; framework to add Cron and Jobs to a new app I’m working on called &lt;code&gt;status&lt;/code&gt;. That app isn’t ready for prime time yet, but it will be an uptime monitoring service that will hopefully grow into a more full features monitoring platform!&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I Saw This Week
&lt;/h2&gt;

&lt;p&gt;](#things-i-saw-this-week)&lt;/p&gt;

&lt;p&gt;I’m still experimenting with the format of this blog, and this week I want to try a small section about news or projects that I came across recently that looked interesting!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;quickwit&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Quickwit is a project that came across my feeds this week, and I immediately knew I was going to have to check it out. They advertise themselves as: “Quickwit is the fastest search engine on cloud storage. It's the perfect fit for observability use cases”&lt;/p&gt;

&lt;p&gt;This sounded perfect to me! Back many moons ago now I was working on a small side project to make log data cheaper to store for my scale of projects. It used S3 as a storage backend, and I think that direction is really powerful in terms of controlling cost especially!&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;quickwit&lt;/code&gt; takes the same approach but are MUCH farther along than I ever made it!&lt;/p&gt;

&lt;p&gt;It provides a pretty all included DB, specifically tailored to Logs and Traces. I’m pretty excited about it but haven’t tried it out at all yet. I’m thinking I might try to integrate it with &lt;code&gt;status&lt;/code&gt; up above once that is off the ground a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Challenging projects every programmer should try&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://austinhenley.com/blog/challengingprojects.html" rel="noopener noreferrer"&gt;https://austinhenley.com/blog/challengingprojects.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a blog post from a couple years back now, and it’s simply a list of “challenging” projects for you to try and experiment with! I’m not sure I agree with the ‘every programmer should try’ bit, but if you are interested in them the challenges do seem fun!&lt;/p&gt;

&lt;p&gt;I’m going to keep them in my back pocket for a rainy day when I’m bored. Definitely let me know if you try any out!&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Github Sponsors
&lt;/h2&gt;

&lt;p&gt;](#github-sponsors)&lt;/p&gt;

&lt;p&gt;If you enjoy this newsletter and my other content, please consider sponsoring me on &lt;a href="https://github.com/sponsors/coreyja" rel="noopener noreferrer"&gt;Github Sponsors!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every sponsor helps me be able to continue to working on all these projects I love, and creating posts and videos for all of you!&lt;/p&gt;

&lt;p&gt;I also want to give all my Sponsors a bit of a bonus for helping support me and my content. Right now if you sponsor me you’ll get access to a super special private channel in my Discord, where you’ll be able to interact with me directly and ask questions or get help!&lt;/p&gt;

&lt;p&gt;And in the future I plan on giving Sponsors access to my side projects! &lt;code&gt;status&lt;/code&gt; that I mentioned earlier might be the first example of this, and I will likely go back and get &lt;code&gt;caje&lt;/code&gt; ready for users too and add that.&lt;/p&gt;

&lt;p&gt;So, sponsor me on Github to have access to all my projects and apps! I haven’t decided on a price point for the “all inclusive” sponsorship yet, but if you sponsor &lt;em&gt;before&lt;/em&gt; I get that added you’ll be grandfathered into “all access” for the life of your subscription!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sponsors/coreyja" rel="noopener noreferrer"&gt;Sponsor now!&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why can't I mutate this HashMap - References in Rust</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Sat, 06 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/why-cant-i-mutate-this-hashmap-references-in-rust-n6n</link>
      <guid>https://forem.com/coreyja/why-cant-i-mutate-this-hashmap-references-in-rust-n6n</guid>
      <description>&lt;p&gt;Note: This is an older video I made for TikTok and never posted as a TIL so posting now&lt;/p&gt;

&lt;p&gt;In a discord I'm in someone just posted this question about Rust.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm trying to iterate through the keys of a hash map in rust. And then if a certain thing is true, change the value of that key. I don't see why we need to clone the keys. Since I'm only changing values. Is there a way to get around cloning? And here's the code that they left in that snippet?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the answer to the specific question was to you, something like iter_mut() to loop over the iterator and still be able to edit the data underneath. But that alone doesn't really explain why, why do we need to clone the keys before we can change the values of the map? If you don't do this, Rust will complain about having an immutable borrow to keys when trying to create a mutable borrow for the insert method call. And if you're not really used to references and Rust, that can sound like a bunch of gibberish.&lt;/p&gt;

&lt;p&gt;So let's try an analogy. We have some data, let's say it's a list of numbers and we want to remember it. So we take our own personal whiteboard and we write down our list of numbers. And now we want to share this list with Frank. We don't want to give Frank our whole whiteboard. We just want them to have the list of numbers. So we take a piece of paper out and we write down the list of numbers. And this is our reference. Frank can take this piece of paper and with just that he can read the list of numbers that we have on our whiteboard.&lt;/p&gt;

&lt;p&gt;And Frank can now share this with Kim. He can take a photocopy of this piece of paper, give it to Kim. And now Kim can see the list of numbers that we have on our whiteboard to. But what if we want to add a number to this list? We could just walk to our whiteboard and write a new number down. But now Kim and Frank's papers, aren't going to be right. They're not going to know about this extra number we added. And so Rust is going to stop us Rust. Isn't going to let us write on our whiteboard just yet. We have to make sure all of the pieces of paper, all of the references are cleaned up first. So if all of those pieces of paper are thrown away and Rust doesn't see any pieces of paper anywhere, now we can finally write on our whiteboard again and change the data.&lt;/p&gt;

&lt;p&gt;So if we go back to the sample code that we were looking at before, when we asked for the keys that was creating a reference, we've got a piece of paper with all the keys in our hash map. So since we have that reference, that piece of paper, we can't add new things to the hash map and we can't change the values of anything. Because we have a reference to it. So, what we need to do is we need to get rid of that reference and how we are doing that is we're cloning it. So we take that list. That's on our piece of paper and basically we rewrite it down on our whiteboard and now it's a separate piece of data we could add to it separately than our hash. And then things like might be out of whack. We might have something in one list that isn't in the other, but as far as Rust is concerned, those are two completely separate pieces of data. So we took the reference and put it on our whiteboard, and then we threw away that piece of paper and got rid of the reference. And now we're allowed to mutate our hash map again, because there are no references hanging around. There are no pieces of paper. We just have the one data structure and we can mutate it as we, as we want.&lt;/p&gt;

&lt;p&gt;Hopefully that analogy was helpful to someone. And this helps explain Rust references to you. Let me know in the comments, if this helped you out or if it didn't, I'd like to know how we can do something better next time. Thanks.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>coreyja - 2023 Review and 2024 Preview</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Sat, 06 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/coreyja-2023-review-and-2024-preview-23nl</link>
      <guid>https://forem.com/coreyja/coreyja-2023-review-and-2024-preview-23nl</guid>
      <description>&lt;p&gt;Hey Team!&lt;/p&gt;

&lt;p&gt;It's the first week of 2024 and I wanted to write something to kick off the New Year! I'd also like to try and get one of these newsletters out each month, so let's call this the January Edition!&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  2023 In Review
&lt;/h2&gt;

&lt;p&gt;](#2023-in-review)&lt;/p&gt;

&lt;p&gt;2023 was an awesome year!&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h3&gt;
  
  
  Lavender Iguana
&lt;/h3&gt;

&lt;p&gt;](#lavender-iguana)&lt;/p&gt;

&lt;p&gt;Brandi and I launched Lavender Iguana, our Design and Development business. And through that we've been producing our first podcast, which has been a learning experience and a great time! If anyone reading this is looking to make a podcast and doesn't know where to start, reach out and I'll connect you with Brandi to get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://coreyja.com/projects/caje" rel="noopener noreferrer"&gt;caje&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;caje&lt;/code&gt; was one of the most comprehensive projects we tackled this year! It all started with a comment on an existing video, asking about making a CDN in Rust.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PL0FtqJaYsqZ2v0FezJa15ynwBpo7KE8Xa" rel="noopener noreferrer"&gt;YouTube Playlist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And from there we made &lt;em&gt;eight&lt;/em&gt; full length streams where we build up &lt;code&gt;caje&lt;/code&gt; from scratch in Rust!&lt;/p&gt;

&lt;p&gt;We work on sitting in the middle between users and the origin servers, and saving any request we see to a file system based cache. But from there we had to make it a bit more global, after all this is supposed to be a Content Distribution Network, we can't be only in a single region! So we expanded &lt;code&gt;caje&lt;/code&gt; to run in multiple regions, and share the state of all files in the cache with SQLite. We are using &lt;a href="https://fly.io/docs/litefs/" rel="noopener noreferrer"&gt;&lt;code&gt;LiteFS&lt;/code&gt;&lt;/a&gt; to make our SQLite file distributed across our &lt;code&gt;caje&lt;/code&gt; cluster!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://coreyja.com/projects/moodboards" rel="noopener noreferrer"&gt;Moodboard App&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;At the end of the year we started on this new app that Brandi is helping plan out and design!&lt;/p&gt;

&lt;p&gt;The idea is to create an app to help designers and their clients get on the same page for imagery on the site! The goal is to build a "dating-app" like experience where the Client can swipe through a set of photos and choose if they do or do not like them for the aesthetic of their site or brand!&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.youtube.com/playlist?list=PL0FtqJaYsqZ0V50h8Qt6pDWhKryfFxMsU" rel="noopener noreferrer"&gt;YouTube Playlist for the build is here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h3&gt;
  
  
  Advent of Code
&lt;/h3&gt;

&lt;p&gt;](#advent-of-code)&lt;/p&gt;

&lt;p&gt;And in December this year I started Advent of Code again! I say 'started' because, as is tradition, I only got part of the way through with doing these as streams. You can see my solutions for the first half-ish of December before I ran out of steam &lt;a href="https://www.youtube.com/playlist?list=PL0FtqJaYsqZ2-Bms2mSVvn08bVdAMmp2j" rel="noopener noreferrer"&gt;on YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking forward to 2024
&lt;/h2&gt;

&lt;p&gt;](#looking-forward-to-2024)&lt;/p&gt;

&lt;p&gt;While I'm sure I'll find many small projects to fill my time, there is one big one on the horizon I'm really excited to get started on and share more about!&lt;/p&gt;

&lt;p&gt;In 2024 I'm going to be working on my video course currently titled "Writing a Web Framework in Rust"! The goal is to be a course for people who may not know Rust, but are interested in learning both about Rust and seeing how to build a Web framework from the ground up! We are going to only use the Standard Library and build everything up for ourselves. The first chapter starts by opening a TcpStream and looping over the lines until we can parse an HTTP message, I think you all are going to love it!&lt;/p&gt;

&lt;p&gt;If you want to get a sneak peek at that course be sure to &lt;a href="https://coreyja.com/newsletter" rel="noopener noreferrer"&gt;Subscribe to my Newsletter&lt;/a&gt; and/or &lt;a href="https://discord.gg/RrXRfJNQJX" rel="noopener noreferrer"&gt;Join my Discord&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'll be giving my Sponsors a sneak peek while I record episodes so if you don't want to miss anything, be sure to help support me in making these videos and courses and sign up for my &lt;a href="https://github.com/sponsors/coreyja" rel="noopener noreferrer"&gt;Github Sponsors&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Three Pillars of a Web App</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Wed, 03 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/my-three-pillars-of-a-web-app-5ado</link>
      <guid>https://forem.com/coreyja/my-three-pillars-of-a-web-app-5ado</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bpg2j6opsmq48dwfr2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bpg2j6opsmq48dwfr2h.png" alt="Cover Photo" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I'm writing a web app there is an architecture I always gravitate too. It's simple yet scalable, and fits a wide array of use cases. It involves three distinct processes and one queue, in addition to whatever datastore you want to use. You can reduce the number of moving pieces by using your primary datastore as your queue, I often do this with Postgres.&lt;/p&gt;

&lt;p&gt;As for the processes I like to call them &lt;code&gt;server&lt;/code&gt;, &lt;code&gt;worker&lt;/code&gt; and &lt;code&gt;cron&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;server&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;server&lt;/code&gt; is responsible for serving your web requests. This is probably the most familiar of the three services, and is what all web frameworks will provide. It listens for new HTTP requests, and returns responses to the browser.&lt;/p&gt;

&lt;p&gt;You want to keep those web requests as fast as possible for a good user experience. And to do that you'll often have some work that you don't want to do during a web request. The common example is sending an email after signup. We want this to happen, but we don't necessarily want to make the user wait for the email to be sent to see the next page.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;worker&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;And this is where the &lt;code&gt;worker&lt;/code&gt; process comes in! This process is responsible for working of a queue of jobs. Each job should define its type and any arguments that are needed to run the job. The worker process sits in a loop looking for new things to be added to the queue and process them.&lt;/p&gt;

&lt;p&gt;I often find it useful to give jobs a priority and work them off in some way based on that, but we'll call that an optimization. A first in first out queue is where I would start with if building a worker from scratch. Which is exactly what I'm doing for this site!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cron&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;And the final process is &lt;code&gt;cron&lt;/code&gt;. Cron's job is simple, to put new jobs in the queue based on some schedule. I often have jobs that run on some interval, like every hour. And then some that run on a specific schedule, like every morning at 6am.&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontal Scaling
&lt;/h2&gt;

&lt;p&gt;](#horizontal-scaling)&lt;/p&gt;

&lt;p&gt;One thing I like about this approach is that is horizontally scales well! Both &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;worker&lt;/code&gt; scale horizontally to fit demand. If you have more web requests, or more jobs you can simply spin up more &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;worker&lt;/code&gt; processes. And importantly, you scale these two processes independently! If you have more jobs than web requests, you can keep your &lt;code&gt;server&lt;/code&gt; process count consistent and increase your &lt;code&gt;worker&lt;/code&gt; processes. Both of these also work well with auto-scaling if that suits the use case.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; is the exception here. You do &lt;em&gt;not&lt;/em&gt; want to naively horizontally scale your &lt;code&gt;cron&lt;/code&gt; process, or else you'll end up with duplicate jobs in the queue. Luckily &lt;code&gt;cron&lt;/code&gt; doesn't often have scaling concerns, as it's "only" responsible for looping and enqueuing jobs when needed. If you do need to horizontally scale your cron, you can find a way to partition the jobs and assign a portion to each process you spin up.&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Guarantees
&lt;/h2&gt;

&lt;p&gt;](#guarantees)&lt;/p&gt;

&lt;p&gt;Another cool aspect of this is that you can have different durability guarantees, depending on exactly how you implement each process and which datastore you use.&lt;/p&gt;

&lt;p&gt;For instance if you need guarantees about Cron jobs definitely being enqueued, you can write the state of the cron to your favorite data store and make sure that even if your cron goes down it can enqueue any jobs it misses when it comes back up.&lt;/p&gt;

&lt;p&gt;You can use a durable store for your queue too, so you don't risk losing jobs. This is one reason I like Postgres queue. They are durable 'by default.'&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple
&lt;/h2&gt;

&lt;p&gt;](#simple)&lt;/p&gt;

&lt;p&gt;These three processes are relatively easy to manage, and can be applied to just about every project. I've found that basically every web app I've needed to build fits nicely into this mold, and most don't require any additional infrastructure.&lt;/p&gt;

&lt;p&gt;My goal with setting up these three processes early, is that it reduces decision making in the future. If you already have a job queue, it's easy to take advantage of it. You never have to rely on 'hacks' like sending emails in web requests, since it's easy to offload that work to the worker process.&lt;/p&gt;

&lt;p&gt;Like I mentioned earlier I'm currently building out these three processes for this site! It's been a lot of fun to stand up these processes from first principles, instead of using frameworks. If you want to follow along, be sure to subscribe to my newsletter or checkout my Discord!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Autoformat in VSCode on Auto-Saves</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Fri, 08 Sep 2023 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/autoformat-in-vscode-on-auto-saves-g4a</link>
      <guid>https://forem.com/coreyja/autoformat-in-vscode-on-auto-saves-g4a</guid>
      <description>&lt;p&gt;I've had VS Code setup to format my code on save for a while now, and I love it!&lt;/p&gt;

&lt;p&gt;Recently though I had a few files slip through my auto-formatting and be caught in CI. When I investigated it turns out that my VS Code settings were prevening auto-formatting from running on auto-save.&lt;/p&gt;

&lt;p&gt;I had &lt;code&gt;files.autoSave&lt;/code&gt; set to &lt;code&gt;afterDelay&lt;/code&gt; and &lt;code&gt;files.autoSaveDelay&lt;/code&gt; set to &lt;code&gt;300&lt;/code&gt;. Which meant that after 300ms my code would auto-save. However, auto-formatting would only run on manual saves, not auto-saves triggered by &lt;code&gt;afterDelay&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix was pretty simple! I switched from &lt;code&gt;afterDelay&lt;/code&gt; to &lt;code&gt;onFocusChange&lt;/code&gt;! Now my files get changed anytime I switch to a different window or file, and even better auto-formatting runs as well!&lt;/p&gt;

&lt;p&gt;Here is a snippet from my new config with a comment I left for future me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"files.autoSave": "onFocusChange",
// By setting files.autoSave to `onFocusChange` the delay below isn't needed
// We need to use `onFocusChange` (or `onWindowChange`) since auto formatting isn't
// applied when using `afterDelay` :sadnerd:
// "files.autoSaveDelay": 300,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Sept 1st Update - Lockfiles</title>
      <dc:creator>Corey Alexander</dc:creator>
      <pubDate>Fri, 01 Sep 2023 00:00:00 +0000</pubDate>
      <link>https://forem.com/coreyja/sept-1st-update-lockfiles-39e2</link>
      <guid>https://forem.com/coreyja/sept-1st-update-lockfiles-39e2</guid>
      <description>&lt;p&gt;Hey Team! Its September now, so how was everyones August?&lt;/p&gt;

&lt;p&gt;Today I want to talk a little about lock files, especially since the Cargo Team just updated their guidance about them in this blog post: &lt;a href="https://blog.rust-lang.org/2023/08/29/committing-lockfiles.html" rel="noopener noreferrer"&gt;Change in Guidance on Committing Lockfiles&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  This Week
&lt;/h2&gt;

&lt;p&gt;We had two good stream this week!&lt;/p&gt;

&lt;h3&gt;
  
  
  Sunday, Aug 27th
&lt;/h3&gt;

&lt;p&gt;Link: &lt;a href="https://youtu.be/EBmDL9ZYI_Y" rel="noopener noreferrer"&gt;https://youtu.be/EBmDL9ZYI_Y&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Sunday we worked more on our Bot Byte! We fixed some issues I had introduced since the previous stream, and got Byte able to listen to my audio again nicely!&lt;/p&gt;

&lt;p&gt;After that we made use of our new neon.tech powered DB to save and store chatters preferred nicknames. We also use this to customize how Byte pronounces your name! For instance I set my nickname to &lt;code&gt;Corey Jay Aye&lt;/code&gt; so that it would pronounce my username correctly.&lt;/p&gt;

&lt;p&gt;I'm really excited to keep improving Byte and using them as I stream! Let me know what else we should teach Byte to do on upcoming streams!&lt;/p&gt;

&lt;h3&gt;
  
  
  Wednesday Aug 30th
&lt;/h3&gt;

&lt;p&gt;Link: &lt;a href="https://youtu.be/oTS7LB2ChK8" rel="noopener noreferrer"&gt;https://youtu.be/oTS7LB2ChK8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Wednesday we got back to my most requested topic recently, Building a CDN in Rust!&lt;/p&gt;

&lt;p&gt;Previously we had gotten our server stood up to Proxy requests to our origin server, and cache each request without checking its cache ability, And on Wesnesday we fixed that! Now we check the &lt;code&gt;Cache-Control&lt;/code&gt; and other relevant headers to determine if a resource is cachable. If it isn't we always make the live request from the origin server!&lt;/p&gt;

&lt;p&gt;While streaming we found out that Chromium in developer mode always adds &lt;code&gt;Max-Age=0&lt;/code&gt; as a header, which was forcibly 'shutting down' my caching proxy! We switched over to Firefox and were better able to test the caching behavior.&lt;/p&gt;

&lt;p&gt;The brains of our header checking were done by the&lt;a href="https://docs.rs/http-cache-semantics/latest/http_cache_semantics/" rel="noopener noreferrer"&gt;&lt;code&gt;http-cache-semantics&lt;/code&gt; crate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We wrapped up this stream by making a plan for next time! We still want to add a 'manifest' of cached pages, and a way to share this manifest between nodes so that different nodes can cache the content without it being requested through them!&lt;/p&gt;

&lt;h2&gt;
  
  
  coreyja's Ramblings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lockfiles
&lt;/h3&gt;

&lt;p&gt;Today I want to talk about package manager lockfiles! In particular I'm going to focus on the two languages and package managers I have the most experience with Ruby and Rust.&lt;/p&gt;

&lt;p&gt;Ruby with Bundler and Rust with Cargo have very similar philosophies. And that makes sense knowing that Cargo was written by some of the same people who developed Bundler for Ruby! Here is the announcement post for &lt;a href="https://archive.ph/Cox1H" rel="noopener noreferrer"&gt;Cargo (on archived version)&lt;/a&gt; which mentions the dev Bundler roots.&lt;/p&gt;

&lt;p&gt;Lockfiles are an important part of the Cargo and Bundler designs. In Ruby we have the &lt;code&gt;Gemfile.lock&lt;/code&gt; and in Rust we have the &lt;code&gt;Cargo.lock&lt;/code&gt; file. These files specify the exact version of your dependencies that you have installed.&lt;/p&gt;

&lt;p&gt;When you add a dependency to Cargo or Bundler you specify a range of versions that your code can work with. In Bundler you might add some a range like this &lt;code&gt;~&amp;gt; 1.1.0&lt;/code&gt;. This range means that we need AT LEAST version &lt;code&gt;1.1.0&lt;/code&gt;, and that we also allow any version where the last digit is higher. So &lt;code&gt;~&amp;gt; 1.1.0&lt;/code&gt; allows version &lt;code&gt;1.1.1&lt;/code&gt; or even &lt;code&gt;1.1.99&lt;/code&gt;. Cargo does a very similar thing, but you don't need the &lt;code&gt;~&amp;gt;&lt;/code&gt; operator as this is Cargo's default behavior!&lt;/p&gt;

&lt;p&gt;These version ranges live in either the &lt;code&gt;Cargo.toml&lt;/code&gt; or &lt;code&gt;Gemfile&lt;/code&gt;, and when you install the dependencies for the first time a lock file is created, that lists the exact version of the dependency that was installed. So if your version range was &lt;code&gt;~&amp;gt; 1.1.0&lt;/code&gt; the lock file might specify &lt;code&gt;1.1.99&lt;/code&gt; if that was the latest matching version at the time you installed.&lt;/p&gt;

&lt;p&gt;If you committed your lock file to version control, any other developers on your project would get the EXACT same version of the dependencies. Even if &lt;code&gt;1.1.100&lt;/code&gt; comes out, without updating the lock file everyone will still get &lt;code&gt;1.1.99&lt;/code&gt; when they install dependencies.&lt;/p&gt;

&lt;p&gt;And this can be really powerful! It allows all the developers to have the same version of every dependency so as to avoid issues cause by differences in versions. Or cases where something works for one developer but not for another. Having and committing a lock file can eliminate a whole class of issues in dependency management.&lt;/p&gt;

&lt;p&gt;And when you want to start using a new version, you can have your tool of choice update the lock file to a new compatible version! And every developer will install that new version when they pull that lock file from version control.&lt;/p&gt;

&lt;p&gt;What I described above is considered the "best practice" for applications, where the final result is an application to run and not a library.&lt;/p&gt;

&lt;p&gt;Libraries are a bit different.&lt;/p&gt;

&lt;p&gt;See in a library you don't have as much control over what versions of dependencies are installed. This is because these package managers &lt;strong&gt;do not take lockfiles into account when installing a library&lt;/strong&gt;. This is often something that trips people up at first when they haven't run into it before. But libraries &lt;em&gt;only&lt;/em&gt; use the version ranges in your &lt;code&gt;Cargo.toml&lt;/code&gt; or &lt;code&gt;Bundler&lt;/code&gt; file to decide what version of dependencies to install. This is because both of these package managers try to install dependency versions that work for your whole tree of dependencies. This is more exaggerated in Ruby and Bundler, where you can only have a single version of any dependency.&lt;/p&gt;

&lt;p&gt;Let's say we have 3 gems (what Ruby calls packages). &lt;code&gt;base_library&lt;/code&gt; has no dependencies. &lt;code&gt;lib_a&lt;/code&gt; depends on &lt;code&gt;base_library ~&amp;gt; 1.0&lt;/code&gt; and &lt;code&gt;lib_b&lt;/code&gt; depends on &lt;code&gt;base_library &amp;lt;= 1.2&lt;/code&gt;. Since we can only have one version of &lt;code&gt;base_libary&lt;/code&gt; installed we have to find one that matches both &lt;code&gt;~&amp;gt; 1.0&lt;/code&gt; and &lt;code&gt;&amp;lt;= 1.20&lt;/code&gt;. This might be &lt;code&gt;1.2.0&lt;/code&gt; which satisfies both ranges. If thought &lt;code&gt;lib_b&lt;/code&gt; depended on &lt;code&gt;base_library &amp;lt; 1.0&lt;/code&gt; we'd have a problem. There isn't any version that can match both &lt;code&gt;~&amp;gt; 1.0&lt;/code&gt; and &lt;code&gt;&amp;lt; 1.0&lt;/code&gt; at the same time. Here Bundler will blow up, saying it couldn't find matching dependencies.&lt;/p&gt;

&lt;p&gt;Cargo is a little more lenient here as it allows multiple versions of the same dependency to be installed. Though you might run into issues later if you try to pass Structs from one version to methods from a different version.&lt;/p&gt;

&lt;p&gt;Since libraries don't use the lock file for resolving dependency trees, there is debate on what you should do with lockfiles in libraries.&lt;/p&gt;

&lt;p&gt;Until recently the &lt;code&gt;Cargo&lt;/code&gt; teams advice has been to commit lockfiles for applications, but NOT for libraries.&lt;/p&gt;

&lt;p&gt;This is so that when CI runs, it will always pull the latest possible version of your dependencies. This lets you know what a user of you package might get if they installed it for the first time. It can help find incompatibilities and bugs with the newest versions of your deps.&lt;/p&gt;

&lt;p&gt;But of course, this does mean that different developers working on the same project won't have the same exact versions of things. Each individual will have their own local lock file.&lt;/p&gt;

&lt;p&gt;And Cargo recently amended their stance to say that it's ok to commit the lock file for libraries too, and to consider it for your project. This is a very reasonable answer because each project is different. On some projects keeping all the developers on the same version might outweigh the benefits of potentially finding issues earlier in CI. The "don't commit" for libraries advice also kinda implies that you have a working CI that could potentially catch issues early. If you don't then some of the benefits of not committing your lock file are lost. And on the flip side it's possible to get the benefits of not committing your lock file in other ways. I've recently heard of a project that commits their lock file, but has an automation that periodically updated the lock file with the latest releases. Or a different project that has two CI jobs setup, one that uses the committed lock file and one that does NOT and grabs the latest compatible versions.&lt;/p&gt;

&lt;p&gt;I like this new advice in that it acknowledges that there are tradeoffs that might not apply to everyone. However I do like that the old advice as a bit more universal. Universal standards are nice in that they can reduce the number of things someone starting out has to think about.&lt;/p&gt;

&lt;p&gt;And I'm really glad to hear from different people around the internet, and hear their tips and tricks for dealing with dependency versioning!&lt;/p&gt;

&lt;p&gt;I was firmly in the "don't commit for libraries" camp, and think I still lean that way. But I am very intrigued by the idea of committing the lock file and having automation to update it on some cadence. I think I'll play around with this more sometime!&lt;/p&gt;

&lt;p&gt;And finally there is one piece to this puzzle that I didn't get today and that is Cargo Workspaces. These allow you to bundle a bunch of crates together into a workspace, and have a single lock file for the whole workspace! This is really nice and has quickly become my default for Rust projects. But it is very interesting as it relates to this topic, cause now you have a single lock file potentially for both apps AND libraries. And I think in this case the tradeoffs are different. So far I've always committed lockfiles in workspaces, and I think that makes the most sense. Since there are applications in my workspaces, it makes sense to lock the deps for those versions. This works great for me because most of the library style crates in my workspaces aren't published externally so their versioning isn't super important. But I think I want to expand on this topic focusing on workspaces for an upcoming newsletter, so be on the lookout for that!&lt;/p&gt;

&lt;p&gt;And with that I'm going to wrap up for the day. Thanks for reading team, and see ya online this week!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
