<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Guilherme Andrade: writing</title>
    <link>https://guilherme-andrade.com/writing/</link>
    <atom:link href="https://guilherme-andrade.com/writing/rss.xml" rel="self" type="application/rss+xml"/>
    <description>Essays and tutorials on AI-driven development, Ruby on Rails and architecture.</description>
    <language>en-gb</language>
    <lastBuildDate>Tue, 03 Nov 2026 12:00:00 GMT</lastBuildDate>
    <item>
      <title>Guardrails first: how I make AI do the right job, fast</title>
      <link>https://guilherme-andrade.com/writing/guardrails-first/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/guardrails-first/</guid>
      <pubDate>Tue, 03 Nov 2026 12:00:00 GMT</pubDate>
      <category>Essay</category>
      <description>From Claude config files to OpenSpec to custom lint rules and dependency checks: how I moved the rules for AI agents from prose the model reads to code a machine enforces.</description>
      <content:encoded><![CDATA[<p>Since August 2025 I haven&#39;t written much code by hand. Claude Code writes almost all of it, and my job has moved from typing to deciding what gets built and building the guardrails that keep the agents honest.</p>
<p>I didn&#39;t get there in one step. I started where most people start, by writing rules for the agent in its config files. When those stopped working I moved to written specs, and when specs weren&#39;t enough I moved the rules into code: custom lint rules, dependency checks and other static analysis. This is that story, using the rewrite of RemoteLock&#39;s web app as the example.</p>
<blockquote><p><strong>Figure: Each stage moved the rules from read to checked.</strong> Stage 1, config files: a request the model reads. Followed some of the time, whatever the level of detail. Stage 2, OpenSpec: a contract a person reviews. It fixes what to build, not how the code looks. Stage 3, static analysis: a check a machine runs. Yes or no, every time, and it names the line. A scale under the stages runs from &quot;the model interprets&quot; to &quot;the machine enforces&quot;.</p></blockquote>



<h2>The example: rewriting RemoteLock&#39;s web app</h2>
<p>At RemoteLock we are rebuilding the customer web app as a new React single-page app, connect-web-v2. It is a good stress test for AI-driven development for three reasons:</p>
<ul>
<li><strong>It ships next to the old app.</strong> Both apps answer the same URLs, and a route manifest decides, path by path, which one serves a customer. Nothing can break the parts that are not moved yet.</li>
<li><strong>It is big and long-lived.</strong> Hundreds of pull requests since mid-2026, many of them written by agents, and a codebase other engineers will maintain for years.</li>
<li><strong>The old code is a trap.</strong> The legacy app works, but copying its patterns would copy its problems. The rule is that legacy is reference only: behaviour is re-specified from scratch, never ported.</li>
</ul>
<p>That combination punishes an agent that guesses. So the repo is built to stop guessing.</p>
<h2>Stage 1: rules in Claude config files</h2>
<p>I started with <code>CLAUDE.md</code>: a file of conventions the agent reads at the start of every session. Use the component library. Keep modules apart. Test this way. Name things like that. It felt like onboarding a new engineer, and at first it worked.</p>
<p>Then I noticed the output wasn&#39;t consistent. The same rule held in one session and was ignored in the next. So I tried the obvious fixes, in both directions:</p>
<ul>
<li><strong>More detail.</strong> Longer explanations, examples, the reasoning behind each rule. The file grew and the agent followed it no more reliably. Rules near the top competed with rules near the bottom.</li>
<li><strong>Less detail.</strong> Short, sharp lines. Easier to scan, but loose enough to be read several ways, and the agent picked whichever reading suited the task in front of it.</li>
<li><strong>Finer granularity.</strong> Rules split per folder and per kind of task. That helped locally, but which rules applied to a given change became its own guessing game.</li>
</ul>
<p>Some changes made things worse. An example written to illustrate one rule got copied as a pattern where it didn&#39;t belong. A rule meant for one area leaked into others. And every line spent context that the actual task needed.</p>
<p>The lesson took a while to land: a config file is a request, not a guarantee. The model reads it the way a person reads a long wiki page, mostly right and never exactly the same way twice. Config files are still the right place for orientation, meaning where things live, why the code is shaped this way, and which docs to read. They are the wrong place to rely on for anything that must always be true.</p>
<h2>Stage 2: specs with OpenSpec</h2>
<p>The next problem was scope, not style. Asked to build a feature, the agent filled every gap with its own assumptions, and on a rewrite next to a legacy app those assumptions were often the legacy app&#39;s habits.</p>
<p><a href="https://github.com/Fission-AI/OpenSpec">OpenSpec</a> fixed that part. Every change starts as a written proposal: the behaviour as requirements and scenarios, and a task list. One spec change per pull request. The agent loads that change and the current spec for its area before it writes code, so it builds against a contract instead of a guess.</p>
<p>What it helped with:</p>
<ul>
<li><strong>Less guessing.</strong> The agent no longer decides what a feature does. The spec does.</li>
<li><strong>Faster review where it counts.</strong> I read a page of behaviour before anything is built. A wrong spec is cheap to fix, and a wrong diff isn&#39;t.</li>
<li><strong>A fresh start from legacy.</strong> Behaviour is re-specified from scratch, so the old app stays a reference and never becomes a template.</li>
<li><strong>Small pull requests.</strong> One change per PR keeps each one reviewable in minutes.</li>
</ul>
<p>What it didn&#39;t fix: a spec says what to build, not how the code should look. Two agents could implement the same spec correctly and still break the architecture in two different ways. The &quot;how&quot; was still living in a config file, so it was still a request.</p>
<h2>Stage 3: rules as code</h2>
<p>The change that made the output consistent was moving rules out of prose and into static analysis. If a rule matters, a machine checks it, and the check answers yes or no. The agent doesn&#39;t have to remember the rule, because it can&#39;t get past it.</p>
<p>In connect-web-v2 that means:</p>
<ul>
<li><strong>Custom lint rules for our conventions.</strong> No raw HTML elements, <code>className</code> or inline styles outside the UI library. Components are typed arrow constants. Packages are imported by name. Tests find elements only by test id. Each one started as a line in a config file that agents kept missing, and became a lint error.</li>
<li><strong>No escape hatch.</strong> Disabling a lint rule is itself forbidden, so an agent under pressure can&#39;t silence a check to get green.</li>
<li><strong>Dependency rules for the architecture.</strong> <a href="https://github.com/sverweij/dependency-cruiser">dependency-cruiser</a> enforces module boundaries: a module is imported only through its public entry file. The list of top-level modules is closed, and adding one needs a person&#39;s approval in the same PR.</li>
<li><strong>Presence checks.</strong> Every visual component must ship with a story and a test, or be explicitly tagged as non-visual. Every page must name itself in the browser tab.</li>
<li><strong>Dead code and drift.</strong> <a href="https://knip.dev">knip</a> fails on unused files and exports. The API client is generated from the backend&#39;s OpenAPI schema, and CI fails if the two drift apart. Specs are validated too.</li>
<li><strong>Budgets and gates.</strong> An 80% coverage floor on logic, accessibility checks, bundle-size budgets, a changelog entry on every user-facing change, a phone screenshot on every UI change.</li>
<li><strong>Grandfather lists that only shrink.</strong> Old code that doesn&#39;t meet a new rule is listed by name, and the list can only get shorter. A new rule never waits for a big cleanup.</li>
</ul>
<p>The dependency rules matter for another reason: they make the codebase a set of <strong>vertical slices</strong>. Each module owns everything for its feature in one folder: its API calls, schemas, hooks, components, permissions and tests, with sub-areas as nested modules of the same shape. A task almost always lives inside one slice. So the agent only needs that folder and the public entry files of the few modules it uses, a small context where everything is related, instead of a horizontal layer that cuts across the whole app. Smaller, related context is a big part of why the output got consistent: there is less to misread and less to leak into.</p>
<p>The effect on the agents was immediate. A red check is specific: it names the file, the line and the rule. The agent reads it and fixes it, usually on the first retry, without me in the loop. The config file changed role too. Its rules are still there, but each one now has a check behind it, so the file explains the rule and the check makes it true.</p>
<h2>Stage 4: a review that can be argued with</h2>
<p>Static analysis catches what can be stated as a rule. What&#39;s left, like whether the code actually does what the spec says, goes to an automated review that runs on every pull request against that PR&#39;s own spec. It is built so the model only notices and code decides:</p>
<ul>
<li>Several review passes read the diff and write candidate findings to files. They post nothing.</li>
<li>A reconcile step matches them against a per-PR ledger of findings, and it is the only thing that comments.</li>
<li>The verdict is a pure function of that ledger. Open critical or major findings block the merge, and nothing else does.</li>
<li>Later rounds check whether the open findings were fixed instead of re-reviewing from scratch, so a review converges instead of finding new nitpicks forever.</li>
</ul>
<p>When a finding is wrong, anyone can reply <code>/review dispute</code> with the reason. A fresh session, with none of the first reviewer&#39;s reasoning, re-derives the evidence and either withdraws or upholds the finding. A finding is a claim about the code, so it falls to evidence, not authority. Visual changes get the same treatment: a visual-regression diff on demand, approved per commit.</p>
<p>Put together, a change only reaches a person after every machine has said yes:</p>
<blockquote><p><strong>Figure: Only a change that passes every gate reaches a person.</strong> Left to right: spec change (written first, read by a person), agent builds (rules and skills), CI checks (yes or no), AI review (the ledger decides), merge (after spec and proof, read by a person). A red check at CI sends the change back to the agent, which retries. An open finding at AI review sends it back to the agent, which fixes it. Below AI review, a dispute step started with /review dispute has a fresh session weigh the evidence. The two places a person reads are the spec change and the merge.</p></blockquote>



<p>A red check or an open review finding sends the change back to the agent. I read only the spec at the start and the evidence at the end.</p>
<h2>Why it&#39;s fast</h2>
<p>Guardrails sound like friction. In practice they are what makes speed safe, because they move judgement out of my head and into places an agent can read and a machine can check.</p>
<ul>
<li><strong>Small units of work.</strong> One spec change per PR keeps each change small enough to review in minutes and to revert in one click.</li>
<li><strong>Cheap rejection.</strong> A red check costs the agent a retry, not me a conversation. Most problems are caught and fixed before I ever look.</li>
<li><strong>Parallel work without collisions.</strong> Module boundaries and a closed module list mean several agents can work in different areas at once without stepping on each other.</li>
<li><strong>Review that converges.</strong> The ledger turns review into a checklist that empties, not an argument that grows. Disputes settle on evidence in minutes.</li>
<li><strong>Rules that compound.</strong> Every time an agent gets something wrong in a new way, the fix is a lint rule or a check, not another line in a config file. The next agent can&#39;t repeat the mistake.</li>
</ul>
<h2>The downside</h2>
<p>This works so well that it creates its own problem. When every convention is a lint rule and every boundary is a check, writing code becomes almost deterministic. That&#39;s exactly what you want from an agent, and it&#39;s not great for the people working in the codebase.</p>
<ul>
<li><strong>Less room to improve.</strong> A better pattern now has to beat a rule, a check and a grandfather list before anyone can try it. Experiments that would have been a small PR become a debate about changing the rules.</li>
<li><strong>Gaps get hidden, not found.</strong> The checks prove the code follows the architecture. They say nothing about whether the architecture is right. When everything is green, nobody is prompted to notice that a boundary is in the wrong place or that two modules really want to be one.</li>
<li><strong>Less learning by doing.</strong> Engineers who mostly read specs and green checks spend less time inside the code, which is where people usually spot that something doesn&#39;t fit.</li>
</ul>
<p>I don&#39;t have a full answer yet. What helps so far: treating the rules themselves as code that gets reviewed and changed, keeping architecture decisions with people, and setting aside time to question the structure instead of only building inside it.</p>
<h2>What still needs me</h2>
<p>The agents write the code. Four things stay with me:</p>
<ul>
<li><strong>Deciding what to build.</strong> The spec is the product decision, and it is the part I read most carefully.</li>
<li><strong>The shape of the system.</strong> Architecture decisions, new top-level modules and the rules themselves are reviewed by people.</li>
<li><strong>Taste.</strong> Whether a screen feels right, whether copy reads well, whether a flow makes sense to a property manager at 7am. I judge that from the screenshots and recordings each PR carries.</li>
<li><strong>Building the guardrails.</strong> When something slips through, I don&#39;t fix the code. I fix the rule, check or skill that let it through.</li>
</ul>
<p>That last point is the whole method. The fastest way to make AI do the right job is not a better prompt. It is a repository where the wrong job can&#39;t pass.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Home automation got cheap: Home Assistant on a Pi with Claude</title>
      <link>https://guilherme-andrade.com/writing/home-automation-got-cheap/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/home-automation-got-cheap/</guid>
      <pubDate>Tue, 03 Nov 2026 12:00:00 GMT</pubDate>
      <category>Essay</category>
      <description>Why home automation now costs a fraction of what it used to, how to keep a Home Assistant setup on a Raspberry Pi secure, and what you can build from parts that cost tens of euros.</description>
      <content:encoded><![CDATA[<p>None of this is new. Home Assistant has been around for years, ESP32 boards have cost about ten euros for a long time, and people were watering gardens with relays long before AI. What changed for me is how little time and money it now takes to go from &quot;I wish the house did this&quot; to a working, reliable setup.</p>
<p>I run Home Assistant on a Raspberry Pi at home, and I didn&#39;t write most of its configuration by hand. Claude Code did. My job was to describe what I wanted, check the result, and keep it safe.</p>
<p>This is what that looks like, what it costs, and what I&#39;d tell anyone starting.</p>
<h2>Why it got cheap</h2>
<p>The parts were never the expensive bit. The expensive bit was getting them to work.</p>
<p>A few years ago a project like an automatic watering valve went roughly like this. You read forum threads to guess which board, relay and power supply would work together. You bought them, sometimes the wrong ones, sometimes pricier ones because you didn&#39;t trust the cheap option. You wired it up and occasionally fried something with the wrong voltage. Then you copied code you didn&#39;t fully understand, flashed it, watched it fail, and changed things until it worked, without always knowing why it finally did. Each failed attempt cost a part, an evening or both, and plenty of projects died somewhere in that loop.</p>
<p>AI removes the most error-prone steps of that loop:</p>
<ul>
<li><strong>Choosing parts.</strong> It checks compatibility, voltages and pinouts before you buy, and compares shops. In my case it priced the parts live and even caught its own mistake: it had compared a bare ESP32 module with a full dev board, which made one shop look 40% cheaper than it really was.</li>
<li><strong>Wiring.</strong> It explains which pin goes where and why, and flags the step that would destroy a board, like feeding 12 V to a 5 V input.</li>
<li><strong>Code you can read.</strong> The configuration it writes is plain YAML that it can explain line by line, instead of a sketch pasted from a forum.</li>
<li><strong>Debugging.</strong> It reads the logs and narrows a failure down to a cause, so a fix takes one attempt instead of ten.</li>
</ul>
<p>The hardware costs what it always did, tens of euros. What dropped is the number of attempts, the broken parts and the evenings, and that is most of what a project used to cost.</p>
<h2>The setup: Home Assistant as code</h2>
<p>Home Assistant runs well on a Raspberry Pi with HA OS. The one habit that makes working with an AI agent safe is keeping your configuration as code: YAML files in a git repository on your laptop, copied to the Pi with a small deploy script. Every change is a diff you can read, and every mistake is one revert away.</p>
<p>A few things make that setup easy to live with:</p>
<ul>
<li><strong>One file per area.</strong> Watering in one file, heating in another, notifications in a third. Changes stay small and easy to review.</li>
<li><strong>Validate before reloading.</strong> Home Assistant can check its own configuration. Make the deploy script run that check first, so a broken config never goes live.</li>
<li><strong>Write down the clicks.</strong> Some steps only exist in the UI, like pairing a device or signing in to a vendor account. Keep them as a checklist in the README instead of pretending they&#39;re code.</li>
</ul>
<h2>Keeping it secure</h2>
<p>A home system has cameras, door and gate controls, and your Wi-Fi password in it. The rules I follow are simple, and none of them need special skills:</p>
<ol>
<li><strong>Don&#39;t open ports to the internet.</strong> You don&#39;t need them. Remote access goes through <a href="https://tailscale.com">Tailscale</a>: the Pi makes an outbound connection to a private network, and your phone reaches Home Assistant through that network from anywhere. Nothing in your home listens to the public internet.</li>
<li><strong>Keep secrets out of the repository.</strong> Passwords, tokens and Wi-Fi keys live in a <code>secrets.yaml</code> that git ignores. The repo carries a <code>secrets.yaml.example</code> with the same shape and fake values, so the config is readable without exposing anything.</li>
<li><strong>Give every token the least it needs.</strong> If another service needs your sensor data, give it a token for a dedicated read-only user. If that token leaks, someone can read sensor values and nothing else.</li>
<li><strong>Prefer local over cloud.</strong> When you can, pick devices Home Assistant can talk to on your own network, and keep camera recordings on storage you control. Some devices only work through a cloud account. Accept that per device, knowingly, and write it down.</li>
<li><strong>Validate before you deploy.</strong> Home Assistant checks its own config before anything reloads. A bad change is rejected instead of half-applied.</li>
<li><strong>Decide what the AI may touch.</strong> Claude edits files in the repo and runs the deploy script. The secrets it relies on sit in files outside the repo, so they never end up in a diff or a chat. It doesn&#39;t log in to vendor accounts or pair devices. Those steps stay with me, in the UI.</li>
</ol>
<p>None of this is exotic. It&#39;s the same discipline you&#39;d use for a small web app, applied to a house.</p>
<h2>Cheap devices and circuits</h2>
<p>The part that surprised me most is how little the hardware costs. These are real prices for the parts of a typical small project, read from Portuguese and Spanish shops in July 2026:</p>
<table>
<thead>
<tr>
<th>Part</th>
<th>Price</th>
<th>What it does</th>
</tr>
</thead>
<tbody><tr>
<td>ESP32 dev board (NodeMCU)</td>
<td>€10.18</td>
<td>The brain of every small device: Wi-Fi, Bluetooth, GPIO pins</td>
</tr>
<tr>
<td>ESP32-S3 camera board with PIR sensor</td>
<td>€30.98</td>
<td>A camera that wakes on motion</td>
</tr>
<tr>
<td>12 V 3 A power supply</td>
<td>~€10</td>
<td>Powers a whole small project from mains</td>
</tr>
<tr>
<td>LM2596 buck converter</td>
<td>check the shop</td>
<td>Steps 12 V down to 5 V for the board</td>
</tr>
<tr>
<td>12 V solenoid valve, float switch, flow meter</td>
<td>€9–20 each</td>
<td>Open water, know when a tank is full, measure litres</td>
</tr>
<tr>
<td>Misting nozzles (15) and 25 m of drip tube</td>
<td>€9.74 and €8.33</td>
<td>Cooling and watering</td>
</tr>
<tr>
<td>Wi-Fi powerline kit</td>
<td>€81.32</td>
<td>The most expensive part: a reliable network at the far end of the property</td>
</tr>
</tbody></table>
<p>The pattern is always the same: an ESP32 running <a href="https://esphome.io">ESPHome</a>, a sensor or a relay, a power supply, and a waterproof box. Prices move, so check before you order, but the order of magnitude is tens of euros per device, not hundreds.</p>
<h2>What you can build with them</h2>
<p>None of these are new ideas. The point is that each is now an afternoon instead of a month.</p>
<p><strong>Irrigation is the best place to start.</strong> A valve per zone and an ESP32, or a Bluetooth tap timer, and Home Assistant does the thinking: it skips a run when the forecast says rain, waters longer after hot, dry days, and logs how much water each run used. Compare each run with the last few and you get a leak alert almost for free. Add your water company&#39;s prices and it can estimate the bill. It&#39;s useful from the first week, it saves water, and nothing bad happens if a run goes wrong.</p>
<p>More ideas on the same budget:</p>
<ul>
<li><strong>Control an old air conditioner or TV.</strong> An infrared blaster learns the remote and Home Assistant replays it, so a ten-year-old unit gets a schedule and a thermostat.</li>
<li><strong>Know when a tank is full or the water is running.</strong> A float switch and a flow meter cost about ten euros each.</li>
<li><strong>A camera that wakes on motion.</strong> An ESP32 camera board with a motion sensor, around thirty euros, sends a snapshot to your phone.</li>
<li><strong>Use Bluetooth gadgets without their apps.</strong> An ESP32 can act as a Bluetooth proxy, so devices out of the Pi&#39;s range still show up in Home Assistant.</li>
<li><strong>Get told when something opens.</strong> A door or gate sensor plus a notification is one of the simplest and most useful automations there is.</li>
<li><strong>Look after animals.</strong> Automatic water, feed and a camera for a chicken coop come from the same parts as everything above.</li>
</ul>
<h2>How Claude fits in, and where to stay careful</h2>
<p>The way I work is the same for every device:</p>
<ol>
<li>Describe the outcome in plain words: &quot;water zone 2 for longer when it&#39;s been hot and dry, and tell me if it uses more water than usual.&quot;</li>
<li>Claude reads the existing packages, writes or changes the YAML, and explains what it did.</li>
<li>The deploy script validates the config on the Pi and reloads it.</li>
<li>I check the result on the dashboard or the device, and Claude reads the logs when something is off.</li>
</ol>
<p>What it does well: reading datasheets and integration docs, writing configuration, working out protocols, keeping notes in the README so the next change starts from what was learned, and pricing parts.</p>
<p>Where I stay careful:</p>
<ul>
<li><strong>Anything with mains power.</strong> AI can explain the wiring, but a 230 V circuit gets checked by me, and by an electrician when it&#39;s more than plugging in a supply.</li>
<li><strong>Anything that opens or locks.</strong> Gates and doors deserve a manual override and a notification on every change, so an automation bug never locks anyone in or out.</li>
<li><strong>Accounts and pairing.</strong> Logging in to vendor clouds and pairing devices stay manual steps.</li>
<li><strong>Prices and stock.</strong> They change weekly. The AI reads them live, and I still look before ordering.</li>
</ul>
<p>The result isn&#39;t a smart home that impresses visitors. It&#39;s a house that waters the garden properly, warns me about a leak, and lets me check the cameras from anywhere, built mostly from parts that cost tens of euros each, with a lot less frustration than it used to take.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Building 3D models in SketchUp with Claude Code</title>
      <link>https://guilherme-andrade.com/writing/sketchup-with-claude-code/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/sketchup-with-claude-code/</guid>
      <pubDate>Tue, 03 Nov 2026 12:00:00 GMT</pubDate>
      <category>Essay</category>
      <description>How I modelled a house renovation in SketchUp without knowing SketchUp: a parametric Ruby model driven by Claude Code, about 34 versions in six evenings, and what worked and what didn&apos;t.</description>
      <content:encoded><![CDATA[<p>We&#39;re turning an old one-room village school in Portugal into a house. Before spending anything on builders I wanted to see the options: where the kitchen goes, whether a bed fits on a mezzanine, how a stair can reach it without blocking a door, and where a deck and a small pool could sit between trees that can&#39;t be cut down.</p>
<p>I&#39;m not an architect and I don&#39;t use SketchUp. So on a Friday night in September 2026 I typed one line into Claude Code: &quot;Can you make 3d models in sketchup files based on images of places?&quot;</p>
<h2>What I wanted, and what I started with</h2>
<p>The goals grew over the week:</p>
<ol>
<li><strong>Decide the layout.</strong> Kitchen, stair, sleeping mezzanine, bathroom, deck, pool, garden, parking.</li>
<li><strong>Compare options side by side.</strong> &quot;You should make all the different suggestions in different models&quot;, so each idea got its own file.</li>
<li><strong>Respect the real constraints.</strong> The cork oaks stay, the existing doors and windows stay, and the mezzanine has to make sense under the building rules.</li>
<li><strong>Make it look real.</strong> Plain SketchUp &quot;doesn&#39;t look realistic and is full of mistakes&quot;. I wanted renders I could show people.</li>
<li><strong>Walk through it.</strong> An aerial loop and then a walk through the rooms, like a visitor would.</li>
</ol>
<p>The starting point was thin: a map pin, &quot;the building is 8 m by 6 m&quot;, the wall thickness and a guess at the roof height. The first model came from that and one old street-view image, and the early versions looked like this:</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/02-early-rough-model.jpg" alt="An early version of the model, from the first day"></p>
<p>It got accurate once better inputs arrived: photos of the architect&#39;s drawings, which gave a scale, and the topographic survey, a CAD file that Claude converted into a JSON file with the exact outline, levels, trees and plot boundary. From then on the model of the existing building matched the real one:</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/03-existing-building.jpg" alt="The existing building, modelled from the survey and the drawings"></p>
<h2>The setup: the model is code</h2>
<p>There is no SketchUp plugin or MCP server in the middle. Claude Code drives SketchUp 2026 from the terminal: it opens SketchUp with a Ruby script passed at startup, the script builds the whole building, saves the <code>.skp</code> file, renders preview images from a set of named cameras, and quits.</p>
<p>The building itself is a parametric Ruby program, about 2,900 lines plus 1,100 for materials and decoration. Wall thickness, roof pitch, where the stair starts and which wall the kitchen sits on are constants at the top. Changing the design means changing a number, not dragging faces around.</p>
<p>Around that:</p>
<ul>
<li><strong>Real furniture and trees</strong> come from SketchUp&#39;s public 3D Warehouse as GLB files, imported at real scale.</li>
<li><strong>Textures</strong> are partly generated with Python, partly scanned PBR materials from Poly Haven.</li>
<li><strong>The survey</strong> is a CAD drawing converted to JSON with open-source tools, so the plot, levels and trees come from measurements.</li>
<li><strong>Blender</strong> rebuilt the house in Python for photoreal renders with Cycles.</li>
<li><strong>Small helpers</strong> draw plan sketches before a big change and make contact sheets of the previews.</li>
</ul>
<h2>The loop</h2>
<p>Every change went round the same loop:</p>
<ol>
<li><strong>Describe it in one line.</strong> Often from my phone while looking at the last renders: &quot;the stairs are blocking the doors to the bedroom&quot;, &quot;the bed is almost touching the roof beam&quot;.</li>
<li><strong>Sketch before building.</strong> For anything that moved the layout, Claude first drew a simple plan in the terminal so I could confirm it understood. That one habit saved more rebuilds than anything else.</li>
<li><strong>Build a new version.</strong> Each build went into a new file with its own version name, never the one I had open, so SketchUp never got stuck on a file conflict and old options stayed around to compare.</li>
<li><strong>Review the previews.</strong> Every build rendered 30-odd images from fixed cameras: the four corners outside, each room, and &quot;door views&quot; showing what you see when you walk in through each door. Claude looked at them first, I looked after.</li>
</ol>
<p>Options got their own versions too: kitchen on the north, east or west wall, a low or high mezzanine, and about a dozen stair layouts. The one I kept is version 34.</p>
<h2>Results</h2>
<p>The same aerial camera across versions shows the design settling:</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/g1-evolution-exterior.gif" alt="The exterior across versions, from the same camera"></p>
<p>And the living room, version by version:</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/g2-evolution-living-room.gif" alt="The living room across versions"></p>
<p>The chosen design, version 34: a low sleeping mezzanine over the kitchen, a stair along the north wall, a deck with a small pool, the cork oaks kept.</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/04-proposed-v34-deck-pool.jpg" alt="Version 34: the deck and pool side"></p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/05-proposed-v34-kitchen.jpg" alt="Version 34: the kitchen under the mezzanine"></p>
<p>For realism, Claude rebuilt an earlier version of the house in Blender with Python and rendered it with Cycles. Fifteen images took about a minute and a half each:</p>
<p><img src="https://guilherme-andrade.com/writing/sketchup-with-claude-code/06-blender-render-aerial.jpg" alt="A Blender render of an earlier design"></p>
<h2>What worked, what didn&#39;t</h2>
<p><strong>What worked:</strong></p>
<ul>
<li><strong>The model as code.</strong> Every option is a version, every change is a diff, and nothing depends on my SketchUp skills, which are close to zero.</li>
<li><strong>Real inputs beat clever guessing.</strong> The model was vague until the survey and the drawings arrived, and exact after.</li>
<li><strong>Sketch first.</strong> Asking for a quick plan before each big change caught misunderstandings before they cost a build.</li>
<li><strong>Fixed cameras.</strong> The same views every build made changes easy to compare, for Claude and for me.</li>
</ul>
<p><strong>What didn&#39;t:</strong></p>
<ul>
<li><strong>Walkways.</strong> The agent kept forgetting that people need room to walk past a bed, a counter or a stair. I had to say it again and again.</li>
<li><strong>Headless SketchUp is fragile.</strong> A welcome window, an open file or a locked screen can stall a build silently. The scripts write their own error log because SketchUp shows nothing.</li>
<li><strong>3D Warehouse is uneven.</strong> Some models are kilometres wide, some trees are flat photos.</li>
<li><strong>SketchUp to Blender was too slow.</strong> Exporting the full model produced 11 million triangles and a 1.2 GB file, so the photoreal renders stayed on the earlier Blender rebuild.</li>
<li><strong>The walkthrough video.</strong> Rendering it frame by frame would have taken hours, so the tour plays live inside SketchUp and I record the screen.</li>
</ul>
<p>Six evenings and about 34 versions later, I had a layout I&#39;d call the best we&#39;d done, and a clear picture of the options we turned down.</p>
]]></content:encoded>
    </item>
    <item>
      <title>tailwindcss-rb alpha released</title>
      <link>https://guilherme-andrade.com/writing/tailwindcss-rb-alpha-released/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/tailwindcss-rb-alpha-released/</guid>
      <pubDate>Sat, 02 Nov 2024 12:00:00 GMT</pubDate>
      <category>News</category>
      <description>Tailwindcss-rb is as a (sort of) simple Ruby gem that aims to bring Tailwind CSS writing into a more Ruby-friendly environment.</description>
      <content:encoded><![CDATA[<p>Disclaimer: This is a pet project built for open source that is in no way affiliated with Tailwind Labs Inc, the creator of tailwind.</p>
<p>I&#39;m happy to announce that I&#39;ve just released tailwindcss-rb!</p>
<p>Tailwindcss-rb is as a (sort of) simple Ruby gem that aims to bring Tailwind CSS writing into a more Ruby-friendly environment.</p>
<p>With it, you can style your html with Tailwind in a Ruby-like syntax without losing the power of it&#39;s compiler. It&#39;s still unclear to me where it&#39;s value lies exactly, but it&#39;s something I&#39;ve used as a core component of my other WIP library (view-component-ui), a mantine-like ui component framework for ruby on rails.</p>
<p>Here’s what Tailwindcss-rb offers:</p>
<ul>
<li>Easy Setup: Just add <code>gem &#39;tailwindcss-rb&#39;</code> to your Gemfile, and you’re ready to go.</li>
<li>Ruby-like Tailwind Classes: The <code>Tailwindcss::Style</code> class and <code>tailwind</code> helper make it simple to build classes in a Ruby way.</li>
<li>Flexible Configuration: Tweak everything from output paths to breakpoints to match your project’s needs.</li>
<li>Real-Time Compilation: Compile on the fly during development, or pre-compile your styles for production effortlessly.</li>
</ul>
<p>I can’t wait to see how Tailwindcss-rb helps simplify and speed up your styling in Ruby projects. 🚀</p>
<p>👉 <a href="https://github.com/guilherme-andrade/tailwindcss-rb">Explore tailwindcss-rb on GitHub</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>What the Rails documentation doesn&apos;t tell you: three developer challenges</title>
      <link>https://guilherme-andrade.com/writing/what-rails-documentation-doesnt-tell-you/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/what-rails-documentation-doesnt-tell-you/</guid>
      <pubDate>Sat, 02 Nov 2024 12:00:00 GMT</pubDate>
      <category>Tutorial</category>
      <description>As a Rails app grows, the documentation stops having answers.</description>
      <content:encoded><![CDATA[<p>Rails, as a web framework, is great for getting a web app off the ground quickly. Whether it&#39;s a personal project or the early stages of a startup, you’re almost guaranteed to find everything you need in its core libraries to ship something fast. But as your app grows and the domain complexity starts to pile on, you might notice something: the Rails documentation doesn&#39;t always have the answers for the kinds of problems you&#39;re now dealing with.</p>
<blockquote>
<p>the Rails documentation doesn&#39;t always have the answers for the kinds of problems you&#39;re now dealing with.</p>
</blockquote>
<p>As your project matures, the straightforward guidance that Rails offers starts to fade, and you’re left with questions that don’t have clear answers in the docs. That’s when friction starts to creep in. You’ll find yourself writing code that doesn’t quite fit into the standard Rails patterns, or relying on libraries that feel like they&#39;re just bolted on. Worse yet, you might end up with code that&#39;s difficult to maintain, riddled with performance issues, or just plain buggy. And suddenly, that &quot;magic&quot; that made Rails so appealing starts to feel like a burden.</p>
<p>At this stage, the issues you’ll run into usually fall into one or more of these three categories:</p>
<ul>
<li>Code that requires more than the core Rails libraries: As your app grows, you often need features that the framework doesn’t provide out of the box, leading you to patchwork external solutions.</li>
<li>Code that becomes too complex for the simple MVC architecture: The default Rails patterns start to break down as you introduce more complex business logic, making your codebase harder to maintain.</li>
<li>Code that fails due to the use of Rails&#39; own patterns: Using certain Rails conventions can lead to performance bottlenecks, bugs, or maintenance nightmares, and sometimes the framework’s magic becomes the problem instead of the solution.</li>
</ul>
<p>In this article, I’m not here to talk about the quick-fix Rails solutions for hobby projects. I’m talking to the developers who’ve spent months (maybe years) working on growing Rails apps—developers who have hit the same roadblocks I have, and who have searched the docs for answers that aren’t there. If you’ve been struggling with finding a path through some of Rails&#39; hidden complexities, stick with me. I’m going to walk you through three common challenges that the documentation just doesn’t cover, and what you can do to navigate them without tearing your hair out.</p>
<p>But before we dive into the specifics, let’s start with some foundational principles that will help you reduce the friction in these situations.</p>
<h2>The Base Principles.</h2>
<p>These don&#39;t apply to the development of Rails apps alone, but are particularly relevant in Rails in my opinion, because of the problems we mentioned earlier.</p>
<p>For that reason, keep these in mind:</p>
<h3>1. Do keep it stupid simple (KISS)</h3>
<p>One of the biggest downfalls of a developer is abstracting too much too early, foreseeing problems that may never be relevant for the future of the company. I have been too many times guilty of doing this myself, and worked long enough to see how damaging it could be in the long run.</p>
<h3>2. Remember that Simplicity is an antonym of Complexity, but is not synonyms with Easy.</h3>
<p>When an organisation strives to “keep things simple”, too often are arguments construed in favour justifying a particular solution by calling it “simple”, when the author of the argument actually means “easy”. By this I mean that, in order for you to consider something as the “Simplest solution”, your considerations should not revolve around the time it takes to develop it, but around the total time and maintenance costs of the feature. Not to say that a solution can’t be easy and simple, on the contrary, that’s the ideal scenario, and by taking simple solutions you’ll guarantee than in the future you’ll have an easier time find the simple solution.</p>
<h3>3. Remember that Consistency (almost) always trumps correctness.</h3>
<p>Don’t go against existing patterns if you believe you’ve found a better one, unless you can entirely replace the existing pattern, otherwise you’ll end up with 2 patterns, and where there’s room for 2 patterns that do the same thing, there’s likely room for a third, and so on.</p>
<p>Always remember that following patterns will make your code better and easier to maintain than introducing a new pattern that others will need to learn.</p>
<p><em>To be continued.</em></p>
]]></content:encoded>
    </item>
    <item>
      <title>Mastering data mapping in Rails with dry-transformer</title>
      <link>https://guilherme-andrade.com/writing/mastering-data-mapping-in-ruby-on-rails-with-dry-transformer/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/mastering-data-mapping-in-ruby-on-rails-with-dry-transformer/</guid>
      <pubDate>Thu, 25 Apr 2024 12:00:00 GMT</pubDate>
      <category>Tutorial</category>
      <description>Data mapping is a crucial aspect of Ruby on Rails development, allowing developers to transform and manipulate data seamlessly across different layers of an application.</description>
      <content:encoded><![CDATA[<h2>Understanding Dry-Transformer</h2>
<p>dry-transformer offers a versatile toolkit for defining and applying data transformations in Ruby on Rails applications. By leveraging composable functions known as transformers, developers can easily define complex mappings between different data structures. With a declarative syntax and modular approach, dry-transformer enables clean and efficient data manipulation, making it an invaluable tool for optimizing data mapping tasks.</p>
<h2>Usage Examples</h2>
<h3>Example 1: Renaming Keys and Nesting Data</h3>
<pre><code>require 'dry/transformer'

class DataMapper
  extend Dry::Transformer::Registry
  import Dry::Transformer::HashTransformations

  # Define transformations
  map_keys rename_keys: { user_name: :name, user_age: :age }
  rename_keys user_email: :email
  nest :address, [:street, :city, :zip_code]
end</code></pre>
<p>Usage: Let&#39;s say we have input data like this:</p>
<pre><code>input_data = {
  user_name: 'John',
  user_age: 30,
  user_email: 'john@example.com',
  street: '123 Main St',
  city: 'New York',
  zip_code: '10001'
}</code></pre>
<p>When we call DataMapper.new.call(input_data), it transforms the data as follows:</p>
<pre><code>{
  name: 'John',
  age: 30,
  email: 'john@example.com',
  address: {
    street: '123 Main St',
    city: 'New York',
    zip_code: '10001'
  }
}</code></pre>
<h3>Example 2: Multiplying Values</h3>
<pre><code>require 'dry/transformer'

class DataMapper
  extend Dry::Transformer::Registry

  # Define custom transformation
  map_value price: -&gt;(value) { value * 10 }
end</code></pre>
<p>Usage: Suppose we have an input value of { price: 20 }. When we call DataMapper.new.call(input_data), it transforms the data to { price: 200 }.</p>
<h3>Example 3: Composing Transformers</h3>
<pre><code>require 'dry/transformer'

module CustomTransformers
  extend Dry::Transformer::Registry
  import Dry::Transformer::HashTransformations

  # Define custom transformations
  map_keys rename_keys: { first_name: :name, user_age: :age }
  rename_keys user_email: :email
end

class DataMapper
  extend Dry::Transformer::Pipe
  import CustomTransformers
end</code></pre>
<p>Usage: Let&#39;s say we have input data like { first_name: &#39;John&#39;, user_age: 30, user_email: &#39;<a href="mailto:john@example.com">john@example.com</a>&#39; }. When we call DataMapper.new.call(input_data), it transforms the data as follows:</p>
<pre><code>{
  name: 'John',
  age: 30,
  email: 'john@example.com'
}</code></pre>
<h2>Conclusion</h2>
<p>By leveraging <code>dry-transformer</code>, Ruby on Rails developers can achieve clean, efficient, and modular data mapping in their applications. Whether you need to rename keys, nest data, apply custom transformations, or compose multiple transformers, <code>dry-transformer</code> offers a flexible and powerful toolkit to meet your data mapping needs. Incorporate <code>dry-transformer</code> into your development workflow to streamline data manipulation and unlock new possibilities for data transformation in Ruby on Rails applications.</p>
<p>Happy mapping!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Better data validation in Rails with custom types and dry-validation</title>
      <link>https://guilherme-andrade.com/writing/enhancing-data-validation-in-ruby-on-rails-with-custom-types-and-dry-validation/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/enhancing-data-validation-in-ruby-on-rails-with-custom-types-and-dry-validation/</guid>
      <pubDate>Thu, 25 Apr 2024 12:00:00 GMT</pubDate>
      <category>Tutorial</category>
      <description>In the realm of Ruby on Rails development, data validation plays a critical role in ensuring the integrity and reliability of applications.</description>
      <content:encoded><![CDATA[<h2>The Need for Custom Types</h2>
<p>In many applications, certain attributes have specific validation requirements beyond simple presence or format checks. For example, consider a scenario where you need to validate the gender attribute of a user record, ensuring that it contains one of the values &#39;male&#39;, &#39;female&#39;, or &#39;other&#39;. While Rails provides mechanisms for basic validation, handling such custom requirements can be challenging.</p>
<h2>Introducing dry-types</h2>
<p>dry-types is a powerful gem that provides a flexible toolkit for defining and working with types in Ruby applications. One of its key features is the ability to define custom types tailored to your application&#39;s domain. Let&#39;s start by defining a custom type for the gender attribute:</p>
<pre><code>require 'dry-types'

module Types
  include Dry::Types.module
  
  # Define custom type for gender attribute
  Gender = Strict::String.enum('male', 'female', 'other')
end</code></pre>
<p>In this example, we define a custom type Gender using dry-types, restricting the values to &#39;male&#39;, &#39;female&#39;, or &#39;other&#39;. With our custom type defined, let&#39;s integrate it into the validation process using dry-validation.</p>
<h2>Validating Data with dry-validation</h2>
<p>dry-validation is a validation library that integrates seamlessly with dry-types, allowing you to define validation contracts with support for custom types. Let&#39;s create a validation contract for a user entity that includes our custom type:</p>
<pre><code>require 'dry-validation'

class UserValidator &lt; Dry::Validation::Contract
  params do
    required(:name).filled(:string)
    required(:age).filled(:integer)
    required(:gender).filled(Types::Gender)
  end
end</code></pre>
<p>In this validation contract, we specify that the :gender attribute must be filled and must adhere to the Types::Gender custom type we defined earlier. Now, let&#39;s see how we can use this validation contract in practice.</p>
<h2>Putting it into Practice</h2>
<pre><code># Usage example
input = { name: 'John', age: 25, gender: 'male' }

result = UserValidator.new.call(input)

if result.success?
  puts 'Validation passed!'
else
  puts 'Validation failed:'
  puts result.errors.to_h
end</code></pre>
<p>In this example, we create a UserValidator instance and call it with input data containing attributes for name, age, and gender. The validation process checks that all required attributes are present and that the gender attribute conforms to our custom type. If validation fails, we print out the validation errors for further inspection.</p>
<h2>Conclusion</h2>
<p>By leveraging custom types defined with dry-types alongside dry-validation, you can enhance data validation in your Ruby on Rails applications with ease. Whether you need to enforce specific constraints on attributes or validate complex data structures, this approach provides a flexible and powerful solution. Incorporate custom types into your validation process to ensure data integrity and reliability, empowering you to build robust and maintainable Rails applications.</p>
<p>Happy coding!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Decimal precision issues in PostgreSQL with ActiveRecord</title>
      <link>https://guilherme-andrade.com/writing/precision-issues-in-postgres-activerecord/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/precision-issues-in-postgres-activerecord/</guid>
      <pubDate>Thu, 25 Apr 2024 12:00:00 GMT</pubDate>
      <category>Essay</category>
      <description>When dealing with financial data or any numeric values requiring precise calculations, developers often encounter challenges related to decimal precision.</description>
      <content:encoded><![CDATA[<h2>The Problem with PostgreSQL Decimal Precision</h2>
<p>PostgreSQL supports the <code>decimal</code> data type for precise numeric storage. This data type allows users to specify both the precision (total number of digits) and scale (number of digits to the right of the decimal point). However, when interacting with PostgreSQL through ActiveRecord, developers may notice unexpected behavior due to differences in how decimal values are handled.</p>
<h3>Example of Precision Loss</h3>
<p>Consider the following scenario:</p>
<pre><code># Migration file
create_table :transactions do |t|
  t.decimal :amount, precision: 10, scale: 2
end

# Model class
class Transaction &lt; ApplicationRecord
end

# Creating a new transaction
Transaction.create(amount: 10.555)</code></pre>
<p>In this example, we&#39;re creating a <code>transactions</code> table with an <code>amount</code> column defined as a decimal with a precision of 10 and a scale of 2. However, when we attempt to save a transaction with an amount of <code>10.555</code>, ActiveRecord will truncate the value to <code>10.55</code> before storing it in the database.</p>
<h2>Why Precision Loss is Problematic</h2>
<p>Precision loss can lead to inaccurate financial calculations, potentially causing discrepancies in balance sheets, transaction totals, and other critical metrics. Furthermore, rounding errors can compound over time, resulting in significant discrepancies in financial reporting. For applications handling sensitive financial data, such inaccuracies are unacceptable and can undermine trust and reliability.</p>
<h2>Solutions to Precision Issues</h2>
<p>To address precision issues in PostgreSQL with ActiveRecord, developers can consider the following solutions:</p>
<h3>Solution 1: Adjust PostgreSQL Column Scale</h3>
<pre><code># Migration file
change_column :transactions, :amount, :decimal, precision: 15, scale: 5</code></pre>
<p>By increasing the scale of the <code>amount</code> column, more decimal places can be stored, mitigating precision loss for values with fractional components.</p>
<h3>Solution 2: Handle Precision in Application Logic</h3>
<pre><code># Model class
class Transaction &lt; ApplicationRecord
  before_save :adjust_amount_precision

  private

  def adjust_amount_precision
    self.amount = amount.ceil(2)
  end
end</code></pre>
<p>In this solution, we use <code>ceil(2)</code> to round the <code>amount</code> attribute up to two decimal places before saving it to the database. By rounding up, we ensure that precision is maintained and that any fractional components are accounted for.</p>
<h2>Conclusion</h2>
<p>Decimal precision issues in PostgreSQL with ActiveRecord can pose significant challenges for developers working with financial data or other numeric values requiring precise calculations. By understanding the limitations of PostgreSQL&#39;s decimal data type and adopting appropriate strategies for handling precision, developers can ensure accurate and reliable data storage and calculations in their Ruby on Rails applications. Whether through adjusting PostgreSQL column scale, handling precision in application logic, or a combination of both, addressing precision issues is essential for maintaining data integrity and trustworthiness in financial applications and beyond.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The problem with MVC frameworks</title>
      <link>https://guilherme-andrade.com/writing/the-problem-with-mvc-frameworks/</link>
      <guid isPermaLink="true">https://guilherme-andrade.com/writing/the-problem-with-mvc-frameworks/</guid>
      <pubDate>Wed, 15 Nov 2023 12:00:00 GMT</pubDate>
      <category>Essay</category>
      <description>Join me as I dive into the hidden complexities of Ruby on Rails, where its celebrated simplicity meets challenging realities as our projects grow and evolve.</description>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Ruby on Rails, with its Model-View-Controller (MVC) framework, has long been a hallmark of simplicity and efficiency in web application development. Initially, this framework offers a clear and structured approach, but as applications grow in complexity, these once beneficial characteristics can turn into limitations. Drawing from personal experiences and a broader understanding of Rails, this article explores how the framework&#39;s early advantages may evolve into challenges and emphasizes the importance of a dynamic architectural approach in Rails, which offers much more than just MVC.</p>
<h2>The Broader Appeal of Rails</h2>
<p>Rails is often lauded for its MVC framework, but its allure extends far beyond this aspect. Its appeal lies in the simplicity it brings across the board – from setting up web servers and managing databases to fostering a robust and supportive community. The true beauty of Rails lies in this comprehensive simplicity, underscoring the fact that Rails is more than its MVC framework. It&#39;s a holistic toolkit that simplifies numerous facets of web development.</p>
<h2>The Initial Appeal of Simplicity</h2>
<p>The MVC framework in Rails, more than a mere structural guideline, embodies a philosophy of straightforwardness crucial in the early development stages. While it excels in managing basic functionalities and standard features, we must acknowledge that this is only a part of what Rails has to offer. As projects scale, this simplicity can start to conflict with the complexities of advanced features, revealing the limitations of a static architectural mindset.</p>
<h2>Rising Complexity and Architectural Evolution</h2>
<p>As projects grow, adding features and building intricate interdependencies, the simplicity of Rails&#39; MVC starts to falter. This increase in &#39;domain complexity&#39; isn&#39;t just about more code; it&#39;s about the complex interaction of expanding features. Here lies a critical point where initial architectural choices may no longer be sufficient. It becomes evident that architecture in Rails should not be static but rather dynamic, evolving to meet the application’s growing needs.</p>
<h2>Misconceptions of the &#39;Rails Way&#39;</h2>
<p>A prevalent misconception in the Rails community is the notion of a &#39;Rails way&#39; – a rigid adherence to MVC with little room for deviation. This idea can be misleading, suggesting that if MVC isn&#39;t a perfect fit, the solution might be to switch frameworks or languages. However, such a view overlooks Rails&#39; inherent flexibility and richness. Rails offers a robust foundation that extends well beyond MVC, capable of adapting to various complexities and requirements.</p>
<h2>Community Influence and Discerning Solution Adoption</h2>
<p>The Rails community is a vibrant ecosystem that continuously generates a multitude of solutions and patterns. However, the popularity of these solutions, often gauged by metrics like GitHub stars, can sometimes overshadow their actual suitability for specific problems. While community-driven innovations are invaluable, they should be approached critically, ensuring they align with the project&#39;s unique requirements rather than being adopted based on trendiness alone.</p>
<h2>Embracing Architectural Flexibility</h2>
<p>Confronting the challenges of growing complexity necessitates exploring beyond conventional MVC. Integrating service objects, presenters, decorators, and embracing domain-driven design (DDD) represents a move towards more flexible and scalable architectural patterns. This approach is in harmony with the philosophy of Rails, advocating for architectural practices that are dynamic, adaptable, and responsive to an application&#39;s evolving requirements.</p>
<h2>Conclusion</h2>
<p>Rails, often equated with its MVC framework, is in fact a multifaceted tool that simplifies a wide range of web development aspects. As applications evolve, it&#39;s crucial to embrace the flexibility inherent in Rails, venturing beyond MVC to discover architectural solutions tailored to specific project needs. Recognizing and leveraging the full spectrum of capabilities offered by Rails allows for the development of sophisticated, well-structured applications that can gracefully scale with growing complexity.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
