<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Yuri Sidorov]]></title><description><![CDATA[Yuri Sidorov]]></description><link>https://blog.yurisidorov.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 18:31:32 GMT</lastBuildDate><atom:link href="https://blog.yurisidorov.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Big "Why Ruby?" Update]]></title><description><![CDATA[A few weeks ago, the official Ruby website added a "Why Ruby?" section right on its home page. I looked at it and thought: do I even need to keep my site? And if I do, how should it look now?
Since the launch, the site has collected some nice article...]]></description><link>https://blog.yurisidorov.com/the-big-why-ruby-update</link><guid isPermaLink="true">https://blog.yurisidorov.com/the-big-why-ruby-update</guid><category><![CDATA[Ruby Community]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[why ruby]]></category><dc:creator><![CDATA[Yuri Sidorov]]></dc:creator><pubDate>Tue, 10 Feb 2026 15:52:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770738396552/ab65e18b-aa96-4dea-85b8-142ab7705c97.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few weeks ago, the official Ruby website added a <a target="_blank" href="https://www.ruby-lang.org/en/#:~:text=Why%20Ruby">"Why Ruby?"</a> section right on its home page. I looked at it and thought: do I even need to keep my site? And if I do, how should it look now?</p>
<p>Since the launch, the site has collected some nice articles and is now #1 in Google for "why ruby" — so I guess it's doing its job. But I loved the quotes idea from the official site. They immediately answer the main question. <a target="_blank" href="https://twitter.com/palkan_tula">Vladimir Dementyev</a> suggested letting everyone share why they love Ruby. So I stole the whole idea and put it right on the first screen 🤷‍♂️</p>
<p>Now, on your profile, you can write a couple of sentences, and with a little help of AI it becomes a beautiful testimonial on the home page. <a target="_blank" href="https://rubycommunity.org">Go try it!</a></p>
<p>Along the way, I fixed a bunch of bugs and added features some people asked for, like hiding repositories or the "Open to Work" badge. The design got a refresh too.</p>
<h2 id="heading-the-community-section-got-popular">The community section got popular</h2>
<p>Many of us have great open source projects, and the community page has become a nice place to see what each of us is working on and to support each other by voting on GitHub. People liked the ratings, the ability to discover contributions, to see what we give back to the community.</p>
<p>This part of the site started to feel like it needed its own space. A site centered on Ruby developers. A place to showcase your work.</p>
<p>Now it has a new home: <a target="_blank" href="http://rubycommunity.org"><strong>rubycommunity.org</strong></a>.</p>
<p><a target="_blank" href="https://rubycommunity.org"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770738342927/83ff7b51-0674-4607-8997-bea7ec6873b9.png" alt class="image--center mx-auto" /></a></p>
<p>Same app, same database. Sign in on one site and you're signed in on the other. But now there's a clear separation: <a target="_blank" href="http://whyruby.info">whyruby.info</a> for advocacy content and testimonials, <a target="_blank" href="http://rubycommunity.org">rubycommunity.org</a> for the community itself.</p>
<p>It now features an interactive map of Ruby developers around the world, and daily star trends showing which projects are popular right now.</p>
<p>More than 70 developers have already joined. I could have just scraped GitHub and added everyone myself, but that felt wrong. People should decide if they want to appear on the site. So please share this in your networks and invite your Ruby friends.</p>
<h2 id="heading-ideas-for-the-future">Ideas for the future</h2>
<p>Conference talk stats, dedicated project pages with collected blog posts about them, linking users to their companies' contributions, and so on. The project is <a target="_blank" href="https://github.com/newstler/why_ruby">open source</a> and built for the community to own. PRs and ideas are welcome.</p>
<h2 id="heading-a-personal-note">A personal note</h2>
<p>I've spent almost 20 years writing Ruby. Built all kinds of products and this past year went deep into practical AI integration.</p>
<p><a target="_blank" href="https://rubycommunity.org/newstler"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770653718958/a0cf372a-d466-4f7b-944f-1ba69d7045bf.png" alt class="image--center mx-auto" /></a></p>
<p>I'm looking for work. If you're hiring or know someone who is, I'd love to <a target="_blank" href="https://cal.com/yurisidorov">chat</a>.</p>
<p>Thanks for reading!<br /><a target="_blank" href="http://yurisidorov.com">yurisidorov.com</a> | <a target="_blank" href="http://WhyRuby.info">WhyRuby.info</a> | <a target="_blank" href="http://RubyCommunity.org">RubyCommunity.org</a></p>
]]></content:encoded></item><item><title><![CDATA[How I Think About Building Rails Apps in 2026]]></title><description><![CDATA[I recently overhauled my Rails starter template. Not because anything was broken — the foundation was fine. But the landscape shifted, and some assumptions I'd been making needed revisiting.
This is how I think about it now. Opinions, not rules.
What...]]></description><link>https://blog.yurisidorov.com/how-i-think-about-building-rails-apps-in-2026</link><guid isPermaLink="true">https://blog.yurisidorov.com/how-i-think-about-building-rails-apps-in-2026</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[AI-native]]></category><category><![CDATA[AI]]></category><category><![CDATA[SQLite]]></category><category><![CDATA[mcp]]></category><category><![CDATA[Rails 8]]></category><category><![CDATA[ruby_llm]]></category><category><![CDATA[TDD (Test-driven development)]]></category><category><![CDATA[hotwire]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[kamal ]]></category><category><![CDATA[claude-code]]></category><category><![CDATA[magic links]]></category><category><![CDATA[uuidv7]]></category><category><![CDATA[37signals]]></category><dc:creator><![CDATA[Yuri Sidorov]]></dc:creator><pubDate>Thu, 29 Jan 2026 01:43:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769646721779/53c989e7-97ba-4a27-b596-3cdf24394fbf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently overhauled my <a target="_blank" href="https://github.com/newstler/template/tree/feature/upgrade-philosophy">Rails starter template</a>. Not because anything was broken — the foundation was fine. But the landscape shifted, and some assumptions I'd been making needed revisiting.</p>
<p>This is how I think about it now. Opinions, not rules.</p>
<h2 id="heading-what-i-started-with">What I Started With</h2>
<p>I needed a template for my personal projects. I considered <a target="_blank" href="https://bullettrain.co/">Bullet Train</a>, especially given I was a contributor there, but it was too heavy for my use case. I usually run 3-5 apps on the same 2GB server. Other templates are either not free or don't match how I like to build things. So I made my own.</p>
<p>The baseline: edge Rails from main branch — upgrades are atomic and automated with Dependabot, which helps avoid painful version migrations. SQLite for everything — database plus the <a target="_blank" href="https://rubyonrails.org/2024/11/7/rails-8-no-paas-required">Solid Trifecta</a> (Cache, Queue, Cable). <a target="_blank" href="https://fractaledmind.com/2024/04/15/sqlite-on-rails-the-how-and-why-of-optimal-performance/">Faster than Postgres</a>, <a target="_blank" href="https://x.com/dhh/status/1705271515997143168">production-ready</a>, no Redis. Devise for authentication. ULID primary keys. Avo for admin. Hotwire instead of React or Vue. Tailwind for styling.</p>
<p>This foundation was solid. But 2025 changed some assumptions.</p>
<h2 id="heading-ai-native-by-default">AI-Native by Default</h2>
<p>The last six months brought massive progress in AI-assisted development. That progress pushed me to finally upgrade the template.</p>
<h3 id="heading-agents-are-users-now">Agents are users now</h3>
<p>Simple rule: if a human can do it through UI, an agent should be able to do it through an API.</p>
<p>This isn't hypothetical anymore. Internal automation scripts need programmatic access. AI assistants need to interact with your app. Integration tools expect standard protocols.</p>
<p>My implementation uses <a target="_blank" href="https://modelcontextprotocol.io/">MCP (Model Context Protocol)</a> as the transport. Every feature gets a model, a controller, and an MCP tool. The development rule: "Every new feature MUST have MCP parity."</p>
<p>Your app becomes automatable from day one. Retrofitting this later is painful.</p>
<h3 id="heading-rubyllm-integration">RubyLLM integration</h3>
<p>I built in <a target="_blank" href="https://rubyllm.com/">RubyLLM</a> with OpenAI and Anthropic support. Chat interface with message history. Cost tracking per conversation.</p>
<p>AI isn't an add-on anymore. If your app will eventually need AI features — and most will — build with that assumption from the start.</p>
<p>The chat system is central to any AI-enabled app. You need it for internal use: auto-generating summaries, processing content, running background AI tasks. The user-facing ChatGPT-style UI is a bonus that can be disabled if you don't need it.</p>
<h3 id="heading-llm-settings">LLM settings</h3>
<p>The template includes configuration for Claude Code to work well with the codebase. Style guides for Ruby, testing, migrations, views, Stimulus, Tailwind, i18n — they load automatically and keep the AI aligned with project conventions. Specialized agents for Rails-specific tasks: code-reviewer, debugger, ui-designer. Slash commands like <code>/review-code</code>, <code>/commit-push-pr</code>, <code>/favicon</code> for quick access to common workflows.</p>
<p>This structure makes AI assistance consistent. The AI reads the same conventions every time, follows the same patterns, catches the same issues.</p>
<h3 id="heading-tdd-matters-more-now">TDD matters more now</h3>
<p>Tests first, implementation second. Minitest + fixtures. No RSpec, no FactoryBot.</p>
<p>This matters more than ever with AI-assisted development. TDD gives the AI structure. Tests define what "correct" means before the AI writes anything. Without that constraint, LLMs produce plausible-looking code that drifts from what you actually need. With tests, the AI has a target to hit and immediate feedback when it misses.</p>
<p>Justin Searls <a target="_blank" href="https://justin.searls.co/posts/tdd-is-more-important-than-ever/">puts it well</a> — there's an odd paradox in the industry right now: developers experienced in TDD are both the most skeptical of AI code generation AND the most successful at building software with coding agents. The skepticism comes from caring about quality. The success comes from having techniques that let agents verify their own work. Tests give the AI a target and immediate feedback. Without them, you're just hoping the output is correct.</p>
<p>Obie Fernandez <a target="_blank" href="https://obie.medium.com/ruby-was-ready-from-the-start-4b089b17babb">makes a related point</a>: the process defines the quality of the output; the tool just accelerates whatever process you already follow. If your process is sloppy, AI makes you sloppy faster. If your process includes tests, the AI has guardrails.</p>
<h2 id="heading-vanilla-rails">Vanilla Rails</h2>
<p>37signals open-sourcing <a target="_blank" href="https://github.com/basecamp/fizzy">Fizzy</a> was a good example of this approach in production — a real SaaS built without extra layers. For the first time, developers can study actual 37signals production code, not just read blog posts about their philosophy.</p>
<p>The approach: fat models, thin controllers. Concerns named as adjectives (<code>Closeable</code>, <code>Publishable</code>) instead of service objects. State as records, not booleans — <code>card.closure</code> instead of <code>card.closed</code>. Database constraints over model validations where possible.</p>
<p>I explicitly avoid service objects, query objects, form objects, Devise, Pundit, Sidekiq, Redis, ViewComponent, GraphQL, React/Vue/npm/yarn.</p>
<p>Fewer patterns means less cognitive load. Rails already provides enough. And there's another reason now: simpler stacks are easier for AI to work with. Martin Alderson's <a target="_blank" href="https://martinalderson.com/posts/which-programming-languages-are-most-token-efficient/">recent research</a> shows Ruby ranks #3 in token efficiency across 19 languages — right after Clojure and Julia. Less boilerplate, fewer tokens, longer context windows, lower costs.</p>
<h2 id="heading-magic-links-instead-of-passwords">Magic Links Instead of Passwords</h2>
<p>The old version used Devise. I removed it.</p>
<p>Passwords have become obsolete for most apps. Users forget them constantly. The recovery flow sends an email anyway. So the password step can be skipped entirely — just send <a target="_blank" href="https://avohq.io/blog/magic-link-authentication-with-rails">magic links</a> through email.</p>
<p>One less thing for users to manage. One less attack surface. Simpler code.</p>
<p>Worth considering 2FA later for apps that need it, but for my current projects it's not necessary.</p>
<h2 id="heading-database-decisions">Database Decisions</h2>
<h3 id="heading-uuidv7-replaces-ulid">UUIDv7 replaces ULID</h3>
<p>I moved from ULID to native <a target="_blank" href="https://www.honeybadger.io/blog/uuids-and-ulids/">UUIDv7</a>. UUIDv7 is the industry standard now — time-ordered, globally unique, and the database generates them directly. No model callbacks needed.</p>
<pre><code class="lang-ruby"><span class="hljs-symbol">id:</span> { <span class="hljs-symbol">type:</span> <span class="hljs-symbol">:string</span>, <span class="hljs-symbol">default:</span> -&gt; { <span class="hljs-string">"uuid7()"</span> } }
</code></pre>
<p>ULID was a good idea before UUIDv7 existed. Now there's no reason to use it.</p>
<h3 id="heading-litestream-for-replication">Litestream for replication</h3>
<p><a target="_blank" href="https://litestream.io/">Litestream</a> handles automatic SQLite backups to cloud storage. Zero configuration in application code. Backup and replication used to be a real concern with SQLite — Litestream solves that completely.</p>
<h2 id="heading-frontend-decisions">Frontend Decisions</h2>
<h3 id="heading-hotwire-stays">Hotwire stays</h3>
<p>Server-rendered HTML first. JavaScript as sprinkles, not foundation. Progressive enhancement — works without JS.</p>
<h3 id="heading-tailwind-css-v4">Tailwind CSS v4</h3>
<p><a target="_blank" href="https://tailwindcss.com/blog/tailwindcss-v4">Tailwind v4</a> brings CSS-first configuration now. No JavaScript config file. And a strict rule: OKLCH colors only. Modern color space, better perception.</p>
<p>Server-centric rendering also has an unexpected benefit: agents don't need to parse JavaScript to understand your app structure. Server-rendered HTML is readable.</p>
<h2 id="heading-developer-experience">Developer Experience</h2>
<h3 id="heading-quality-gates">Quality gates</h3>
<p><code>bin/ci</code> runs Rubocop + tests + Brakeman + i18n checks. Pre-commit hooks enforce this automatically. No exceptions — must pass before every commit.</p>
<p>Automation beats hoping for discipline.</p>
<h3 id="heading-documentation">Documentation</h3>
<p>Comprehensive <a target="_blank" href="http://AGENTS.md">AGENTS.md</a> that works for humans and AI assistants alike. Moved the template closer to Rails conventions where sensible.</p>
<h3 id="heading-madmin-over-avo">Madmin over Avo</h3>
<p>Switched from Avo to <a target="_blank" href="https://github.com/excid3/madmin">Madmin</a>. I love Adrian, but some features I consider basic (sorting, dashboard graphs) require a premium subscription. For my personal projects that barely break even, Madmin fits better. It's lighter, closer to vanilla Rails, and does what I need without extra complexity.</p>
<h2 id="heading-what-im-working-on-next">What I'm Working On Next</h2>
<p>Currently adding to the template: Stripe for subscriptions and payments, <a target="_blank" href="https://launchkit.evilmartians.io/">Evil Martians' LaunchKit</a> — a well-researched landing page template designed for developer tools based on their analysis of 100+ devtool sites — and user settings for preferences and notifications.</p>
<p>Also upgrading my existing projects with these changes. First <a target="_blank" href="http://ListenWith.Me">ListenWith.Me</a> — it doesn't have production data to worry about, so it's a good testing ground. Then <a target="_blank" href="http://WhyRuby.info">WhyRuby.info</a>, which will require some tricks: moving from DigitalOcean to Hetzner (5x cheaper) and switching IDs from ULID to UUIDv7 in the same migration.</p>
<hr />
<p>A modern Rails template should be AI-native. Not "AI-compatible" as an afterthought — native from the start. MCP tools alongside controllers. <a target="_blank" href="http://AGENTS.md">AGENTS.md</a> alongside README. Tests that work for humans and agents alike.</p>
<p>The rest is vanilla Rails and simplicity. Every choice either removes complexity or adds genuine value.</p>
<p>Curious if this would work for you — or what you'd do differently.</p>
]]></content:encoded></item></channel></rss>