<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Out of my mind...</title>
  <subtitle>Frederic Jean's blog</subtitle>
  <id>https://fredjean.net</id>
  <link href="https://fredjean.net/"/>
  <link href="https://fredjean.net/feed.xml" rel="self"/>
  <updated>2026-02-15T21:49:00-07:00</updated>
  <author>
    <name>Frederic Jean</name>
  </author>
  <entry>
    <title>middleman-s3_sync 4.7.0 released</title>
    <link rel="alternate" href="/middleman-s3-sync-4-7-0-released/"/>
    <id>/middleman-s3-sync-4-7-0-released/</id>
    <published>2026-02-15T21:49:00-07:00</published>
    <updated>2026-02-15T21:49:00-07:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;I&amp;rsquo;ve just released version 4.7.0 of &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;middleman-s3_sync&lt;/a&gt;, a gem that synchronizes Middleman-built websites to Amazon S3, with optional CloudFront invalidation. This is a feature release with several new capabilities.&lt;/p&gt;

&lt;h2&gt;New Features&lt;/h2&gt;

&lt;h3&gt;&lt;code&gt;after_s3_sync&lt;/code&gt; Callback&lt;/h3&gt;

&lt;p&gt;You can now run custom code after sync completes—perfect for notifications, webhooks, or post-deployment tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;activate&lt;/span&gt; &lt;span class="ss"&gt;:s3_sync&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after_s3_sync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Created: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:created&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; files"&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Updated: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:updated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; files"&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Deleted: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:deleted&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; files"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The callback receives a hash with sync statistics and the list of CloudFront invalidation paths.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;scan_build_dir&lt;/code&gt; Option&lt;/h3&gt;

&lt;p&gt;Sync files that exist in your build directory but aren&amp;rsquo;t tracked by Middleman&amp;rsquo;s sitemap (e.g., files generated by external tools):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;activate&lt;/span&gt; &lt;span class="ss"&gt;:s3_sync&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan_build_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;S3 Website &lt;code&gt;routing_rules&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Configure S3 website redirect rules directly from your Middleman config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;activate&lt;/span&gt; &lt;span class="ss"&gt;:s3_sync&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s3_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routing_rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;condition: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;key_prefix_equals: &lt;/span&gt;&lt;span class="s1"&gt;'old/'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="ss"&gt;redirect: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;replace_key_prefix_with: &lt;/span&gt;&lt;span class="s1"&gt;'new/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;http_redirect_code: &lt;/span&gt;&lt;span class="s1"&gt;'301'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Improved Content Type Detection&lt;/h3&gt;

&lt;p&gt;Better MIME type detection using the mime-types gem as a fallback, with support for custom content types via the &lt;code&gt;content_types&lt;/code&gt; option.&lt;/p&gt;

&lt;h2&gt;Other Improvements&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reliability&lt;/strong&gt;: Proper sitemap population before sync ensures all resources are captured&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;: GitHub Actions workflows for continuous integration and automated releases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;: Tightened gemspec with bounded dependency versions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ruby&lt;/strong&gt;: Now requires Ruby &amp;gt;= 3.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Upgrading&lt;/h2&gt;

&lt;p&gt;Update your Gemfile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'middleman-s3_sync'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 4.7'&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;bundle update middleman-s3_sync
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;p&gt;As always, the source is on &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;GitHub&lt;/a&gt; and the gem is on &lt;a href="https://rubygems.org/gems/middleman-s3_sync"&gt;RubyGems&lt;/a&gt;. Feedback and PRs welcome!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>middleman-s3_sync 4.6.5 released</title>
    <link rel="alternate" href="/middleman-s3-sync-4-6-5-released/"/>
    <id>/middleman-s3-sync-4-6-5-released/</id>
    <published>2026-02-15T16:29:00-07:00</published>
    <updated>2026-02-15T16:29:00-07:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;I&amp;rsquo;ve just released version 4.6.5 of &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;middleman-s3_sync&lt;/a&gt;, a gem that synchronizes Middleman-built websites to Amazon S3, with optional CloudFront invalidation.&lt;/p&gt;

&lt;h2&gt;Highlights&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Thread-safe CloudFront invalidation path tracking (use Set + mutex) when running in parallel&lt;/li&gt;
&lt;li&gt;Cache CloudFront client for fewer re-instantiations (with a reset helper for tests)&lt;/li&gt;
&lt;li&gt;Single-pass resource categorization to reduce repeated scans&lt;/li&gt;
&lt;li&gt;Batch S3 deletes with &lt;code&gt;delete_objects&lt;/code&gt; (up to 1000 keys per request)&lt;/li&gt;
&lt;li&gt;Stream uploads to S3 for lower memory usage; compute MD5s in a single read when possible&lt;/li&gt;
&lt;li&gt;Faster CloudFront redundant-path pruning (O(n × path_depth))&lt;/li&gt;
&lt;li&gt;CLI/extension now delegates option writers (e.g., &lt;code&gt;verbose=&lt;/code&gt;, &lt;code&gt;dry_run=&lt;/code&gt;) to avoid &lt;code&gt;NoMethodError&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes preserve default behavior but should improve efficiency and stability—especially on larger syncs with many deletes/invalidations or large assets.&lt;/p&gt;

&lt;h2&gt;Upgrading&lt;/h2&gt;

&lt;p&gt;Update your Gemfile to track any &lt;code&gt;4.6.x&lt;/code&gt; release:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'middleman-s3_sync'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 4.6'&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;bundle update middleman-s3_sync
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Performance note&lt;/h2&gt;

&lt;p&gt;On my blog (light update set), wall time was essentially unchanged (≈7.7s new vs ≈7.7s old). The benefits primarily appear on larger deployments, where batching, single-pass categorization, and streaming help more.&lt;/p&gt;

&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;p&gt;As always, the source is on &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;GitHub&lt;/a&gt; and the gem is on &lt;a href="https://rubygems.org/gems/middleman-s3_sync"&gt;RubyGems&lt;/a&gt;. Feedback and PRs welcome!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>middleman-s3_sync 4.6.4 released</title>
    <link rel="alternate" href="/middleman-s3-sync-4-6-4-released/"/>
    <id>/middleman-s3-sync-4-6-4-released/</id>
    <published>2026-01-03T10:00:00-07:00</published>
    <updated>2026-01-03T10:00:00-07:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;I&amp;rsquo;ve just released version 4.6.4 of &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;middleman-s3_sync&lt;/a&gt;, a gem that synchronizes Middleman-built websites to Amazon S3.&lt;/p&gt;

&lt;p&gt;This release completely removes the &lt;code&gt;map&lt;/code&gt; gem dependency and replaces it with a native Ruby implementation.&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/ahoward/map"&gt;map gem&lt;/a&gt; provides a string/symbol indifferent hash implementation. After being stable at version 6.6.0 for about a decade, the original author unexpectedly released version 8.x, which introduced breaking changes that caused installation failures.&lt;/p&gt;

&lt;p&gt;While we temporarily locked the dependency to version 6.6.0 in &lt;a href="https://fredjean.net/middleman-s3-sync-4-6-3-released"&gt;v4.6.3&lt;/a&gt;, it became clear that relying on an unmaintained library was not a sustainable solution.&lt;/p&gt;

&lt;h2&gt;What Changed&lt;/h2&gt;

&lt;p&gt;Version 4.6.4 introduces &lt;code&gt;IndifferentHash&lt;/code&gt;, a simple native Ruby class that provides the same functionality as the map gem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;String/symbol indifferent key access&lt;/li&gt;
&lt;li&gt;Dot notation for accessing values&lt;/li&gt;
&lt;li&gt;Zero external dependencies&lt;/li&gt;
&lt;li&gt;Fully tested with the existing test suite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation is straightforward and maintainable, living entirely within the gem&amp;rsquo;s codebase.&lt;/p&gt;

&lt;h2&gt;Benefits&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;More stable&lt;/strong&gt;: No dependency on unmaintained external libraries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fewer dependencies&lt;/strong&gt;: One less gem to install and manage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better control&lt;/strong&gt;: The functionality is now part of the gem itself&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No breaking changes&lt;/strong&gt;: The API remains exactly the same&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Upgrading&lt;/h2&gt;

&lt;p&gt;To upgrade to the latest version, update your Gemfile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'middleman-s3_sync'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 4.6.4'&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;bundle update middleman-s3_sync
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a drop-in replacement with no breaking changes—your existing code will continue to work exactly as before.&lt;/p&gt;

&lt;h2&gt;Acknowledgments&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/chadlwilson"&gt;Chad Wilson&lt;/a&gt; for identifying the issue in &lt;a href="https://github.com/fredjean/middleman-s3_sync/pull/165"&gt;PR #165&lt;/a&gt; and proposing the initial workaround.&lt;/p&gt;

&lt;p&gt;As always, the source code is available on &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;GitHub&lt;/a&gt;, and the gem is available on &lt;a href="https://rubygems.org/gems/middleman-s3_sync"&gt;RubyGems&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>middleman-s3_sync 4.6.3 released</title>
    <link rel="alternate" href="/middleman-s3-sync-4-6-3-released/"/>
    <id>/middleman-s3-sync-4-6-3-released/</id>
    <published>2026-01-03T09:34:00-07:00</published>
    <updated>2026-01-03T09:34:00-07:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;I&amp;rsquo;ve just released version 4.6.3 of &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;middleman-s3_sync&lt;/a&gt;, a gem that synchronizes Middleman-built websites to Amazon S3.&lt;/p&gt;

&lt;p&gt;This is a maintenance release that addresses a dependency issue. Thanks to &lt;a href="https://github.com/chadlwilson"&gt;Chad Wilson&lt;/a&gt; for identifying and fixing the problem in &lt;a href="https://github.com/fredjean/middleman-s3_sync/pull/165"&gt;PR #165&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What Changed&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;map&lt;/code&gt; gem, a dependency of middleman-s3_sync, had been stable at version 6.6.0 for about a decade. Recently, Ara unexpectedly released version 8.x, which introduced breaking changes that caused installation failures.&lt;/p&gt;

&lt;p&gt;This release locks the &lt;code&gt;map&lt;/code&gt; dependency to version 6.6.0 to ensure stable installations until the compatibility issues with the newer version can be resolved.&lt;/p&gt;

&lt;h2&gt;Upgrading&lt;/h2&gt;

&lt;p&gt;To upgrade to the latest version, update your Gemfile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'middleman-s3_sync'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 4.6.3'&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;bundle update middleman-s3_sync
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As always, the source code is available on &lt;a href="https://github.com/fredjean/middleman-s3_sync"&gt;GitHub&lt;/a&gt;, and the gem is available on &lt;a href="https://rubygems.org/gems/middleman-s3_sync"&gt;RubyGems&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>It's like riding a bicycle: relearning how to work with Gems</title>
    <link rel="alternate" href="/its-like-riding-a-bicycle-relearning-how-to-work-with-gems/"/>
    <id>/its-like-riding-a-bicycle-relearning-how-to-work-with-gems/</id>
    <published>2025-05-26T13:51:00-06:00</published>
    <updated>2025-05-26T13:51:00-06:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;They say it&amp;rsquo;s like riding a bicycle - once you learn, you never forget. But after nearly 8 years at Amazon, I&amp;rsquo;m discovering that muscle memory can get pretty rusty when it comes to Ruby gems and the broader open source ecosystem.&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t get me wrong - Amazon&amp;rsquo;s internal tooling is impressive. When you&amp;rsquo;re building systems at AWS scale, you need tools that can handle the complexity, the security requirements, and the operational rigor that comes with serving millions of customers. Internal package managers, build systems, and deployment pipelines are all optimized for that environment. They work incredibly well for what they&amp;rsquo;re designed to do.&lt;/p&gt;

&lt;p&gt;But stepping back into the world of &lt;code&gt;bundle install&lt;/code&gt; and &lt;code&gt;gem update&lt;/code&gt; feels&amp;hellip; different. Foreign, almost.&lt;/p&gt;

&lt;h2&gt;The Small Frictions Add Up&lt;/h2&gt;

&lt;p&gt;It started with something simple - updating this very blog. The &lt;code&gt;middleman-s3_sync&lt;/code&gt; gem I wrote years ago needed some attention. What should have been a quick &lt;code&gt;bundle update&lt;/code&gt; turned into an afternoon of reacquainting myself with dependency resolution, version constraints, and the subtle art of Gemfile management.&lt;/p&gt;

&lt;p&gt;Inside Amazon, dependency management is largely abstracted away. The build systems handle most of the complexity, and when they don&amp;rsquo;t, there are teams of people whose job it is to resolve conflicts and ensure compatibility. You focus on your business logic, not on whether your JSON parsing library plays nicely with someone else&amp;rsquo;s HTTP client.&lt;/p&gt;

&lt;p&gt;But in the gem ecosystem, you &lt;em&gt;are&lt;/em&gt; that person. You&amp;rsquo;re the one making decisions about semantic versioning, evaluating the trade-offs between features and stability, and sometimes diving into someone else&amp;rsquo;s code to understand why your tests are failing after an update.&lt;/p&gt;

&lt;h2&gt;The Muscle Memory Returns&lt;/h2&gt;

&lt;p&gt;The interesting thing is how quickly it comes back. After that first afternoon of frustration, I found myself falling back into familiar patterns. Reading changelogs with a critical eye. Understanding the implications of a major version bump. Appreciating the elegance of a well-crafted API.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s something deeply satisfying about working with gems that embody the Ruby philosophy of developer happiness. The expressiveness, the focus on making common tasks simple, the assumption that you&amp;rsquo;re a smart person who wants to get things done efficiently. It&amp;rsquo;s a refreshing contrast to systems that assume you might break everything if given too much flexibility.&lt;/p&gt;

&lt;h2&gt;Different Tools for Different Problems&lt;/h2&gt;

&lt;p&gt;This isn&amp;rsquo;t a criticism of Amazon&amp;rsquo;s approach - quite the opposite. When you&amp;rsquo;re building infrastructure that needs to work reliably for millions of customers across dozens of regions, the constraints are different. The tooling reflects those constraints, and it should.&lt;/p&gt;

&lt;p&gt;But working on personal projects reminds me why I fell in love with Ruby and its ecosystem in the first place. There&amp;rsquo;s a joy in discovering a gem that solves exactly the problem you&amp;rsquo;re facing. There&amp;rsquo;s satisfaction in contributing back to projects that have made your life easier. There&amp;rsquo;s learning that happens when you&amp;rsquo;re forced to understand the full stack of your dependencies.&lt;/p&gt;

&lt;h2&gt;The Value of Context Switching&lt;/h2&gt;

&lt;p&gt;Having worked in both worlds - the highly controlled internal ecosystem and the more chaotic but creative open source one - I&amp;rsquo;m grateful for the perspective it provides. Each approach has strengths that the other lacks.&lt;/p&gt;

&lt;p&gt;Amazon&amp;rsquo;s tooling taught me the value of consistency, reliability, and operational excellence at scale. The gem ecosystem reminds me of the power of community, the importance of developer experience, and the beauty of solving problems with elegant code.&lt;/p&gt;

&lt;h2&gt;Moving Forward&lt;/h2&gt;

&lt;p&gt;As I continue to work on side projects and contribute back to the open source community, I&amp;rsquo;m trying to bring the best of both worlds together. The operational rigor I learned at Amazon, combined with the creative problem-solving and community spirit of the Ruby ecosystem.&lt;/p&gt;

&lt;p&gt;It really is like riding a bicycle. The balance might feel shaky at first, but once you&amp;rsquo;re moving, it all comes back. And sometimes, the ride is even better than you remembered.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;Have you experienced similar transitions between different tooling ecosystems? I&amp;rsquo;d love to hear about your experiences in the comments or &lt;a href="/contact"&gt;reach out directly&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I'm Back!</title>
    <link rel="alternate" href="/i-m-back/"/>
    <id>/i-m-back/</id>
    <published>2025-04-13T19:49:00-06:00</published>
    <updated>2025-04-13T19:49:00-06:00</updated>
    <author>
      <name>Frederic Jean</name>
    </author>
    <content type="html">&lt;p&gt;A whole lot has happened since I last wrote here. I&amp;rsquo;ve been busy with work, family, hobbies,and personal projects. I&amp;rsquo;ve also dealt with some personal issues and challenges that have shaped my perspective and priorities. I&amp;rsquo;ve learned a lot about myself and the world around me, and I&amp;rsquo;m excited to share my experiences and insights with you.&lt;/p&gt;

&lt;p&gt;One big change is that I joined Amazon Web Services (AWS) nearly 8 years ago. It has been a journey of growth, learning, highs and lows. I&amp;rsquo;m still there, working on projects that ensure that your serverless applications and LLM applications have plenty of compute, storage, and inference resources. I can&amp;rsquo;t really go into details about my work, but I can say that it&amp;rsquo;s been impactful.&lt;/p&gt;

&lt;p&gt;Look for new content as I share my experiences and insights with you.&lt;/p&gt;
</content>
  </entry>
</feed>
