<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged code-refactoring</title>
<link>https://coderlegion.com/tag/code-refactoring</link>
<description>Powered by Question2Answer</description>
<item>
<title>From Writing Code to Orchestrating AI: The Delegate-Review-Own Model Every Engineering Lead Needs</title>
<link>https://coderlegion.com/14216/from-writing-code-orchestrating-the-delegate-review-model-every-engineering-lead-needs</link>
<description>&lt;p&gt;There is a paradox sitting at the center of engineering in 2026.&lt;/p&gt;
&lt;p&gt;80% of developers are now using AI coding agents in their daily workflows. Productivity gains of 35 to 45% have been documented across organizations that have leaned in. AI-powered testing frameworks are catching 68% of bugs before they even reach production. By every metric, adoption is a runaway success.&lt;/p&gt;
&lt;p&gt;And yet trust in AI accuracy has dropped from 40% to 29% year-over-year.&lt;/p&gt;
&lt;p&gt;That is not a contradiction. That is the market maturing.&lt;/p&gt;
&lt;p&gt;The developers who experienced initial euphoria, shipped AI-generated code without enough scrutiny, and then watched subtle bugs slip through into production: they are the ones driving that trust number down. I have been there. And working through that experience forced me to completely rethink how I structure my relationship with AI coding tools.&lt;/p&gt;
&lt;p&gt;What I landed on is something teams are converging on across the industry. The Delegate-Review-Own model.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=8765472423551287469&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-agentic-actually-means-now&quot;&gt;What &quot;Agentic&quot; Actually Means Now&lt;/h3&gt;
&lt;p&gt;Twelve months ago, &quot;AI-assisted development&quot; mostly meant smart autocomplete. A tool that finished your function signature, suggested a variable name, maybe drafted a docstring.&lt;/p&gt;
&lt;p&gt;That era is over.&lt;/p&gt;
&lt;p&gt;In 2026, the leading AI coding tools operate as genuine agents. They do not respond to a single prompt and stop. They run through execution loops: breaking down a task, scaffolding a solution, writing tests, running those tests, reading the failure output, revising the implementation, and iterating until the criteria are met. Tools like Claude Code, Cursor with background agents, and JetBrains Central (launched in March 2026 as an &quot;open system for agentic software development&quot;) can now handle hours of work autonomously before ever surfacing a result for your review.&lt;/p&gt;
&lt;p&gt;Gartner projects that 40% of enterprise applications will embed AI agents by the end of 2026. That number is not about chatbots in a sidebar. That is agents taking actions inside production systems, writing code, running queries, submitting pull requests.&lt;/p&gt;
&lt;p&gt;The question for every engineering lead is no longer &quot;should we use AI tools?&quot; It is &quot;how do we operate in a world where agents are doing significant chunks of the work?&quot;&lt;/p&gt;
&lt;h3 id=&quot;the-delegate-review-own-model&quot;&gt;The Delegate-Review-Own Model&lt;/h3&gt;
&lt;p&gt;The teams getting this right in 2026 have stopped thinking about AI tools as productivity boosters and started thinking about them as a new tier of the engineering team. Here is the model I have settled on:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                   DELEGATE - REVIEW - OWN                   │
├───────────────┬─────────────────────────┬───────────────────┤
│   DELEGATE    │        REVIEW           │       OWN         │
│               │                         │                   │
│ Agent handles │  Engineer validates     │ Human accountable │
│ first-pass    │  correctness, risk,     │ for architecture, │
│ execution:    │  alignment, edge cases  │ trade-offs,       │
│               │                         │ outcomes          │
│ - Scaffolding │  Ask: &quot;Would I have     │                   │
│ - Tests       │  written it this way?&quot;  │ Non-delegatable:  │
│ - Boilerplate │  &quot;What did the agent    │ - System design   │
│ - Docs        │  not consider?&quot;         │ - Risk calls      │
│ - First impl  │  &quot;Is there hidden debt  │ - Team judgment   │
│               │  here?&quot;                 │ - Stakeholder     │
│               │                         │  communication    │
└───────────────┴─────────────────────────┴───────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Delegate&lt;/strong&gt; means being intentional about what you hand off. Good candidates: first-draft implementations of well-scoped tickets, test case generation, documentation, boilerplate for new services, refactoring passes for isolated modules. Bad candidates: anything touching security-critical paths without a tight spec, cross-system integration design, or anything where requirements are genuinely ambiguous.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt; is where the model breaks down for most teams. Engineers trained to &quot;code fast and trust the AI&quot; skip review or treat it like a rubber stamp. That is how the 29% trust number gets generated. Effective review in an agentic workflow is different from reviewing a colleague's PR. You are not just checking &quot;does this work?&quot; You are asking: &quot;What assumptions did the agent make that I never specified?&quot; and &quot;What failure modes exist that the agent was not asked to consider?&quot; This requires reading agent output with more skepticism, not less, precisely because the code often looks clean and confident.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Own&lt;/strong&gt; means the engineer, not the agent, is accountable for what ships. This sounds obvious, but the cultural pressure to externalize blame onto &quot;the AI wrote it&quot; is real on some teams. The role shift from creator to orchestrator does not change who carries responsibility. If anything, that responsibility sharpens: you are now accountable for the quality of your instructions, the rigor of your review, and the integrity of your final approval.&lt;/p&gt;
&lt;h3 id=&quot;what-this-means-for-how-you-lead-your-team&quot;&gt;What This Means for How You Lead Your Team&lt;/h3&gt;
&lt;p&gt;I have made three concrete changes to how I run my team since we adopted this model:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Redefine &quot;done&quot; in your definition of ready.&lt;/strong&gt;&lt;br&gt;
Before any agent-assisted ticket ships, the engineer on point must be able to explain why specific design choices were made, not just that the tests pass. We now explicitly ask this in code review. It surfaces quickly who is reviewing versus rubber-stamping.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Separate agent velocity from engineer throughput.&lt;/strong&gt;&lt;br&gt;
Your sprint velocity will look wildly different when agents are doing first-pass work. That is not a reflection of team performance. I stopped using raw output volume as a signal of individual contribution and shifted to measuring decision quality, architecture coherence, and review depth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Build agent guardrails into your workflow, not just your tools.&lt;/strong&gt;&lt;br&gt;
We define clear &quot;agent lanes&quot; per project. The agent can operate freely inside those lanes. Outside them, it surfaces a proposal and waits for human decision. This is not slowing the agent down. It is structuring the agent's autonomy so review effort is concentrated where risk is highest.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=14208859716610815768&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-skill-that-actually-matters-now&quot;&gt;The Skill That Actually Matters Now&lt;/h3&gt;
&lt;p&gt;Everyone is talking about &quot;prompt engineering&quot; as the new developer skill. I think that framing is already outdated.&lt;/p&gt;
&lt;p&gt;The skill that matters in 2026 is orchestration: how you design the interaction protocols between specialized agents, how you specify constraints and guardrails upfront, how you sequence multi-agent workflows, and how you build review checkpoints that catch what the agent missed without creating so much friction that the productivity gains evaporate.&lt;/p&gt;
&lt;p&gt;That is an engineering judgment skill. It requires deep domain knowledge, system intuition, and the ability to anticipate second-order failures. Junior engineers struggle with it not because they lack technical ability but because they do not yet have the accumulated context to know what questions to ask.&lt;/p&gt;
&lt;p&gt;This, more than anything, is what makes experienced engineering leads more valuable in 2026 than they were in 2023, not less.&lt;/p&gt;
&lt;p&gt;The agents are not replacing judgment. They are raising the floor on execution speed, which means the ceiling for leverage now belongs to the people who bring the clearest thinking to what gets built and why.&lt;/p&gt;
&lt;p&gt;The engineers who are thriving right now are the ones who treated the first wave of AI tools as an opportunity to sharpen their review instincts, design cleaner specs, and think harder about system architecture. The ones struggling are the ones who tried to compete with the agents at their own game: raw output speed.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14216/from-writing-code-orchestrating-the-delegate-review-model-every-engineering-lead-needs</guid>
<pubDate>Wed, 08 Apr 2026 07:19:10 +0000</pubDate>
</item>
<item>
<title>SOLID for Rails Developers, real-life tour (with code)</title>
<link>https://coderlegion.com/6507/solid-for-rails-developers-real-life-tour-with-code</link>
<description>&lt;p&gt;You’ve heard “keep controllers skinny, models thin”  but &lt;strong&gt;how&lt;/strong&gt;? The SOLID principles are a compact set of habits that keep Rails apps change-friendly as they grow. Here’s a practical, with bite-size Rails examples you can use today.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-solid-&quot;&gt;What is SOLID?&lt;/h3&gt;
&lt;p&gt;Before we jump into code, let’s meet the SOLID squad  five principles that save your codebase from chaos, confusion, and late-night debugging sessions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;S&lt;/strong&gt; ingle Responsibility Principle (SRP): Every class should have one job. Not two. Not three. Just one.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O&lt;/strong&gt; pen/Closed Principle (OCP): Your code should be open for extension, but closed for modification.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;L&lt;/strong&gt; iskov Substitution Principle (LSP): If your code says it’s a duck, it should quack like a duck.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I&lt;/strong&gt; nterface Segregation Principle (ISP): Don’t force your classes to implement methods they don’t need.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;D&lt;/strong&gt; ependency Inversion Principle (DIP): Depend on abstractions, not concrete things.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ready to &lt;strong&gt;SOLIDify&lt;/strong&gt; your Rails code? Let’s go!&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-running-scenario&quot;&gt;A running scenario&lt;/h3&gt;
&lt;p&gt;Imagine a small trading API for “Tomato” prices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We fetch intraday &lt;code&gt;PriceTick&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;We compute the best daily gain (buy low, sell high once).&lt;/li&gt;
&lt;li&gt;We expose endpoints for analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll use this scenario to illustrate each principle.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;s-single-responsibility-principle-srp-&quot;&gt;S  Single Responsibility Principle (SRP)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A class should have one reason to change.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;bad-a-god-controller-&quot;&gt;Bad (a God Controller)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class AnalyticsController &amp;lt; ApplicationController
  def show
    date = Date.iso8601(params[:date])
    ticks = PriceTick.where(time: date.all_day).order(:time)
    # validation, parsing, domain logic, formatting… all here 
    min = ticks.first.value_cents
    best = 0
    ticks.drop(1).each do |t|
      best = [best, t.value_cents - min].max
      min = [min, t.value_cents].min
    end
    render json: { date: date, best_gain_cents: best * 100 }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;good-split-responsibilities-&quot;&gt;Good (split responsibilities)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Query&lt;/strong&gt; loads just what’s needed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt; computes the gain&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt; orchestrates and renders&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;app/services/best_gain_calculator.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class BestGainCalculator
  def self.call(ticks, quantity: 100)
    enum = ticks.each
    first = enum.next rescue (return 0)
    min   = first.value_cents
    best  = 0
    enum.each do |t|
      diff = t.value_cents - min
      best = diff if diff &amp;gt; best
      min  = t.value_cents if t.value_cents &amp;lt; min
    end
    best * quantity
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/queries/price_ticks_on_day.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class PriceTicksOnDay
  def self.call(date)
    PriceTick.where(time: date.all_day).select(:time, :value_cents).order(:time)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/controllers/api/v1/best_gains_controller.rb&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class Api::V1::BestGainsController &amp;lt; ApplicationController
  def show
    ticks = PriceTicksOnDay.call(date)
    render json: { best_gain_cents: BestGainCalculator.call(ticks) }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Win:&lt;/strong&gt; Each class changes for exactly one reason.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;o-open-closed-principle-ocp-&quot;&gt;O  Open/Closed Principle (OCP)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Open for extension, closed for modification.&lt;/strong&gt; Add behaviors without rewriting stable code.&lt;/p&gt;
&lt;h4 id=&quot;real-life-new-gain-strategies-without-editing-the-controller&quot;&gt;Real life: new gain strategies without editing the controller&lt;/h4&gt;
&lt;p&gt;app/services/gain_strategies/base.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module GainStrategies
  class Base
    def call(ticks) = raise NotImplementedError
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/services/gain_strategies/single_trade.rb&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module GainStrategies
  class SingleTrade &amp;lt; Base
    def call(ticks) = BestGainCalculator.call(ticks)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/services/gain_strategies/multi_trade.rb&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;module GainStrategies
  class MultiTrade &amp;lt; Base
    def call(ticks)
      # example: sum of all positive deltas
      prev = nil
      profit = 0
      ticks.each do |t|
        if prev
          delta = t.value_cents - prev
          profit += delta if delta.positive?
        end
        prev = t.value_cents
      end
      profit * 100 # quantity stub
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app/controllers/api/v1/best_gains_controller.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def show
  ticks = PriceTicksOnDay.call(date)

  strategy = params[:mode] == &quot;multi&quot; ? GainStrategies::MultiTrade.new : GainStrategies::SingleTrade.new
  render json: { best_gain_cents: strategy.call(ticks) }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Win:&lt;/strong&gt; Adding &lt;code&gt;WeekOverWeek&lt;/code&gt; or &lt;code&gt;TrailingStop&lt;/code&gt; strategies doesn’t touch controller code.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;l-liskov-substitution-principle-lsp-&quot;&gt;L  Liskov Substitution Principle (LSP)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Subtypes must be usable wherever their base type is expected.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;real-life-sti-pitfalls-vs-composition&quot;&gt;Real life: STI pitfalls vs composition&lt;/h4&gt;
&lt;p&gt;If you have &lt;code&gt;PriceTick&lt;/code&gt; and you try STI for &lt;code&gt;FxPriceTick &amp;lt; PriceTick&lt;/code&gt; but change &lt;code&gt;value_cents&lt;/code&gt; semantics (e.g., store pips), substituting &lt;code&gt;FxPriceTick&lt;/code&gt; where &lt;code&gt;PriceTick&lt;/code&gt; is expected will break calculations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; keep interface and units consistent, or &lt;strong&gt;compose&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class PriceTick &amp;lt; ApplicationRecord
  # always expose value in cents
  def value_cents
    super # guaranteed integer cents
  end
end

class FxPriceValue
  def initialize(pips:, pip_value_cents:)
    @pips = pips
    @pip_value_cents = pip_value_cents
  end

  def to_cents = @pips * @pip_value_cents
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Win:&lt;/strong&gt; Anything expecting &lt;code&gt;value_cents&lt;/code&gt; continues to work.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;i-interface-segregation-principle-isp-&quot;&gt;I  Interface Segregation Principle (ISP)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Prefer small, focused interfaces over fat ones.&lt;/strong&gt; Consumers shouldn’t depend on what they don’t use.&lt;/p&gt;
&lt;h4 id=&quot;real-life-split-service-interfaces&quot;&gt;Real life: split service interfaces&lt;/h4&gt;
&lt;p&gt;Bad:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class ReportService
  def generate_csv_for_day(date); end
  def generate_pdf_for_week(date); end
  def email_pdf_to(user); end
  def email_csv_to(user); end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Good:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class CsvReport
  def call(date); end
end

class PdfReport
  def call(week); end
end

class ReportMailer
  def send_pdf(user, pdf); end
  def send_csv(user, csv); end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Win:&lt;/strong&gt; Each client depends on only what it needs; easier to test and swap.&lt;/p&gt;
&lt;p&gt;In Rails, ISP often means &lt;strong&gt;small POROs&lt;/strong&gt; instead of piling methods into one “service class.”&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;d-dependency-inversion-principle-dip-&quot;&gt;D  Dependency Inversion Principle (DIP)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Depend on abstractions, not concrete classes.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;real-life-inject-gateways-http-cache-payments-&quot;&gt;Real life: inject gateways (HTTP, cache, payments)&lt;/h4&gt;
&lt;p&gt;app/services/price_sync.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class PriceSync
  def initialize(client: External::PricesClient.new, cache: Rails.cache)
    @client = client
    @cache  = cache
  end

  def call(date)
    @cache.fetch(&quot;prices:#{date}&quot;, expires_in: 10.minutes) do
      @client.fetch_for(date) # abstraction: responds to `fetch_for`
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;In tests&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;fake = Class.new { def fetch_for(date) = [{ time: Time.now, value_cents: 10000 }] }.new
result = PriceSync.new(client: fake, cache: ActiveSupport::Cache::MemoryStore.new).call(Date.today)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Win:&lt;/strong&gt; Swap implementations without changing business logic. Fewer brittle tests.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;pulling-it-together-a-tiny-solid-checklist&quot;&gt;Pulling it together: a tiny SOLID checklist&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SRP:&lt;/strong&gt; Does this class change for exactly one reason?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCP:&lt;/strong&gt; Can I add a variation without editing existing classes?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LSP:&lt;/strong&gt; Will any subtype respect the expected inputs/outputs/units?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISP:&lt;/strong&gt; Is this interface minimal for its consumer?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DIP:&lt;/strong&gt; Are external details injected (e.g., clients, storage, time)?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-realistic-solid-endpoint-end-to-end-&quot;&gt;A realistic, SOLID endpoint (end-to-end)&lt;/h3&gt;
&lt;p&gt; app/controllers/api/v1/best_gains_controller.rb&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class Api::V1::BestGainsController &amp;lt; ApplicationController
  def show
    ticks = PriceTicksOnDay.call(date)
    strategy = strategy_for(params[:mode])
    best = strategy.call(ticks)
    return render json: { error: &quot;no valid trades&quot; }, status: :unprocessable_entity if best &amp;lt;= 0
    render json: { date: date, best_gain_cents: best }
  end

  private

  def strategy_for(mode)
    mode == &quot;multi&quot; ? GainStrategies::MultiTrade.new : GainStrategies::SingleTrade.new
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything above respects SOLID:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The controller just orchestrates.&lt;/li&gt;
&lt;li&gt;Strategies extend behavior (OCP).&lt;/li&gt;
&lt;li&gt;Calculators keep contracts consistent (LSP).&lt;/li&gt;
&lt;li&gt;Tiny interfaces (ISP).&lt;/li&gt;
&lt;li&gt;Dependencies injected (DIP).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thought&quot;&gt;Final thought&lt;/h3&gt;
&lt;p&gt;Rails gives you speed; SOLID gives you &lt;strong&gt;sustainable speed&lt;/strong&gt;. Start small: extract one PORO today (calculator or query), inject one dependency, and keep your interfaces tiny. Your future self  and your teammates  will thank you.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;bonus-if-solid-were-a-superhero-team-&quot;&gt;Bonus: If SOLID were a superhero team...&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SRP&lt;/strong&gt;: Captain Focus  only fights one villain at a time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OCP&lt;/strong&gt;: The Extender  always ready for new powers, never rewrites their origin story.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LSP&lt;/strong&gt;: Duckman  if it walks like a duck and quacks like a duck, it’s Duckman!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISP&lt;/strong&gt;: The Minimalist  only carries what’s needed for the mission.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DIP&lt;/strong&gt;: The Abstractionist  never depends on sidekicks, only on the idea of sidekicks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now go forth and SOLIDify your Rails app  and remember, with great principles comes great maintainability!&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/6507/solid-for-rails-developers-real-life-tour-with-code</guid>
<pubDate>Thu, 16 Oct 2025 09:47:21 +0000</pubDate>
</item>
<item>
<title>What’s Missing With AI-Generated Code? Refactoring</title>
<link>https://coderlegion.com/5485/whats-missing-with-ai-generated-code-refactoring</link>
<description>&lt;p&gt;A GitClear study found AI-generated code rife with duplication, indicating productivity gains could disappear amid the growing use of coding assistants.&lt;/p&gt;
&lt;p&gt;Last month, GitClear published an analysis of 211 million lines of code in its &lt;a rel=&quot;nofollow&quot; href=&quot;https://gitclear-public.s3.us-west-2.amazonaws.com/AI-Copilot-Code-Quality-2025.pdf&quot;&gt;AI Copilot Code Quality report&lt;/a&gt;. One of the key findings is that &lt;a rel=&quot;nofollow&quot; href=&quot;https://thenewstack.io/is-this-the-end-of-data-refactoring/&quot;&gt;refactoring signals&lt;/a&gt; are crashing while code duplication and churn is increasing. In fact, 2024 is the first year when the introduction of repeated code is greater than refactoring activity.&lt;/p&gt;
&lt;p&gt;The trend is attributed to the rise in AI coding assistants, and if it continues, we could be heading toward a software crisis.&lt;/p&gt;
&lt;h3 id=&quot;the-race-to-adopt-ai&quot;&gt;The Race To Adopt AI&lt;/h3&gt;
&lt;p&gt;If you work in software development, someone has told you that “AI won’t replace developers; developers using AI will replace developers who don’t.” The message is clear: either use AI or you’re heading for a career change. More positive messages suggest we could remove toil work — the tasks that require high repetition and little thought.&lt;/p&gt;
&lt;p&gt;The recent &lt;a rel=&quot;nofollow&quot; href=&quot;https://survey.stackoverflow.co/2024/ai&quot;&gt;Stack Overflow State of Development survey&lt;/a&gt; found that more than 60% of developers are now using AI as part of their work, and more are planning to do so. The primary motivation for AI adoption is increased productivity. As the GitClear report shows, the dramatic downside of wanting to increase productivity is that you may wind up removing your bicycle chain in order to peddle faster.&lt;/p&gt;
&lt;p&gt;In the case of software development, we are now rapidly accelerating the rate of change in our codebases. In 2025, the rate of change is predicted to be almost double the pre-AI (2021) number.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=4229260829449691236&quot; alt=&quot;Lines of code change increasing dramatically with the adoption of AI&quot;&gt;&lt;/p&gt;
&lt;p&gt;This leap in productivity is likely seen as great news by many, particularly those selling AI. However, we should remember the wisdom of our predecessors. &lt;a rel=&quot;nofollow&quot; href=&quot;https://thenewstack.io/poorly-designed-rewards-crush-improvement-efforts/&quot;&gt;Productivity provides a poor view of knowledge work&lt;/a&gt; and has been permanently elusive in its measurement.&lt;/p&gt;
&lt;p&gt;“There is surely nothing quite so useless as doing with great efficiency what should not be done at all.” — Peter Drucker, 1963.&lt;/p&gt;
&lt;h3 id=&quot;throwing-out-good-practice&quot;&gt;Throwing Out Good Practice&lt;/h3&gt;
&lt;p&gt;Before we became productivity-obsessed, there were some foundational practices that the software industry found to be highly valuable. One of these is refactoring. You build more reliable systems when you continuously revisit your code to keep components loosely coupled and to make sure you define concepts just once. You would keep things together if they changed for the same reason and tease them apart if they had different drivers for change.&lt;/p&gt;
&lt;p&gt;My bookshelf creaks beneath the weight of software design literature by Kent Beck, Emily Bache, Martin Fowler, Robert C. Martin, Michael Feathers, Rebecca Parsons, Steve McConnell and more. These books contain lasting techniques and practices that are vital to successful software over the long haul. Coding assistants don’t change the fundamentals of software development.&lt;/p&gt;
&lt;p&gt;If we accelerate the rate of change, we must match this by keeping pace with the software’s internal structure. In other words, for this to result in a successful long-term software development strategy, we must be able to refactor at the same pace we change the code.&lt;/p&gt;
&lt;p&gt;But the report highlights that this is not currently the case.&lt;/p&gt;
&lt;p&gt;Refactoring activity is tracked using a category of change called “moved code.” This is where the fundamental logic remains the same but has been shuffled to improve the code’s design. This includes classic refactoring patterns like “extract method” or “rename variable,” which are typically automated by developer tools to guarantee they are safe refactorings (not to mention the practice of test-driven development should mean your tests would catch any accidental behavioral changes).&lt;/p&gt;
&lt;p&gt;Since 2021, the proportion of refactoring changes has plummeted from 24% to below 10%. At the same time, the number of copy/pasted lines of code, or duplication, has increased from below 10% to almost 15%.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=13410835227873280831&quot; alt=&quot;Refactoring plummets while duplication increases&quot;&gt;&lt;/p&gt;
&lt;p&gt;The prediction for 2025 is that we will reach a point where refactoring is dead, representing little more than 3% of code changes. Our software will continue for some time before the effects of this become clear.&lt;/p&gt;
&lt;h3 id=&quot;the-lesson-comes-too-late&quot;&gt;The Lesson Comes Too Late&lt;/h3&gt;
&lt;p&gt;I’m reminded of an organization where I successfully replaced a chaotic, fragile process with continuous delivery. The key practices installed were test automation, deployment automation, and a solid monitoring and alerting system. The combination of these tools dramatically improved reliability, and elevated the levels of trust between developers and business stakeholders.&lt;/p&gt;
&lt;p&gt;After I left, the team decided that managing test data was an undesirable task. They deleted the database script that ran on test environments to reset data to a known state. For many months, the integration tests still worked, and would have continued to work if nobody had manually changed the test data for the test record configured for integration testing.&lt;/p&gt;
&lt;p&gt;Once the test data was spoiled, the team faced a tough choice. They could recreate the test data management script, updating it so it worked with all the database changes they had made. Alternatively, they could delete the failing tests. Under pressure to deliver features (and remain “productive”), the team deleted the tests.&lt;/p&gt;
&lt;p&gt;Deleting tests has no immediate impact. The feature continued to work for some time, but errors were eventually introduced, and then became a recurring issue.&lt;/p&gt;
&lt;p&gt;This is the problem that arises when you choose productivity over long-term sustainability. It takes a long time to realize there’s damage. When the impact of past decisions is apparent, it can often be too late to mitigate it.&lt;/p&gt;
&lt;h3 id=&quot;flying-vs-falling&quot;&gt;Flying vs. Falling&lt;/h3&gt;
&lt;p&gt;AI code assistants provide the perfect conditions for parabolic software velocity. Just like the zero-gravity plane flights, which use a parabolic curve to provide a feeling of weightlessness, code assistants make us believe we’re flying when we’re actually following a ballistic trajectory in free fall.&lt;/p&gt;
&lt;p&gt;For AI to sustainably increase your productivity, you can’t let it dictate your code quality.&lt;/p&gt;
</description>
<category>IDEs &amp; Code Editors</category>
<guid isPermaLink="true">https://coderlegion.com/5485/whats-missing-with-ai-generated-code-refactoring</guid>
<pubDate>Tue, 23 Sep 2025 07:37:30 +0000</pubDate>
</item>
<item>
<title>JuggleBee’s Great Leap – Data Migration, ActiveStorage, and Production Readiness (Part 2)</title>
<link>https://coderlegion.com/4934/jugglebees-great-leap-data-migration-activestorage-and-production-readiness-part-2</link>
<description>&lt;p&gt;Now that we had a deployable app, I set up a staging server using my new favourite provider, &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.hetzner.com/&quot;&gt;Hetzner&lt;/a&gt; (&lt;em&gt;not a sponsor, lol&lt;/em&gt;), spun it up, and witnessed a “fully functional” skeleton of JuggleBee. Stage 1 of the migration plan was complete.&lt;/p&gt;
&lt;p&gt;Now came the real meat and potatoes of the project — actually hydrating the new app with all of its production data. We’re talking over 50,000 images, countless database records, and security credentials… the works. This is the part where a missed step could mean broken listings, missing files, or downtime. No pressure.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In case you missed &lt;strong&gt;Part 1&lt;/strong&gt;, we covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why I started fresh on &lt;strong&gt;Rails 8&lt;/strong&gt; instead of doing incremental upgrades.&lt;/li&gt;
&lt;li&gt;Migrating core &lt;strong&gt;models/controllers/services&lt;/strong&gt; to modern Rails conventions.&lt;/li&gt;
&lt;li&gt;Swapping Sprockets for &lt;strong&gt;importmaps&lt;/strong&gt; and modernizing the JavaScript setup.&lt;/li&gt;
&lt;li&gt;Replacing &lt;strong&gt;Sidekiq + Redis + whenever&lt;/strong&gt; with &lt;strong&gt;ActiveJob + SolidQueue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Moving deployments to &lt;strong&gt;Kamal 2&lt;/strong&gt; with Traefik and Let’s Encrypt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Catch up on it here:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.brazenbraden.com/posts/jugglebee_rails_upgrade_part1/&quot;&gt;JuggleBee’s Great Leap – Rebuilding a Rails 4 App in Rails 8 (Part 1)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now—back to the post.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-daunting-database-migration&quot;&gt;The Daunting Database Migration&lt;/h3&gt;
&lt;p&gt;Legacy JuggleBee had been coasting along happily on Postgres 9.6 — which, back in 2016, was the latest and greatest. Fast forward to today and it’s long past its sell-by date, with official support ending in November 2021. Upgrading wasn’t just about keeping up with the times; Postgres 17.5 brings some serious perks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native JSON field type support.&lt;/li&gt;
&lt;li&gt;Incremental backups with &lt;code&gt;pg_basebackup --incremental&lt;/code&gt;, slashing backup time and storage usage.&lt;/li&gt;
&lt;li&gt;Noticeable performance gains from better memory management, indexing, and partitioning.&lt;/li&gt;
&lt;li&gt;Improved observability via enhanced &lt;code&gt;EXPLAIN&lt;/code&gt; options and richer stats views.&lt;/li&gt;
&lt;li&gt;…and more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was a no-brainer to upgrade, but the version gap meant one wrong move could corrupt thousands of user, auction, and invoice records. That made reliable backups non-negotiable before touching a single byte. Luckily, I already had a manual backup process baked into my deploy routine. Here’s the script (&lt;em&gt;feel free to steal any of the scripts in my posts&lt;/em&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

DB_CONTAINER=($(sudo docker ps | grep postgres | awk '{print $NF}'))
BACKUP_NAME=dump_`date +%d-%m-%Y&quot;_&quot;%H_%M_%S`.sql
BACKUP_FOLDER=db_backups
KEEP=10

# Dump the database into a backup sql file
echo &quot;Creating the database dump...&quot;
docker exec -t $DB_CONTAINER pg_dumpall -c -U postgres &amp;gt; $BACKUP_NAME
echo &quot;Database dump created.&quot;

echo &quot;Moving database backup to backup folder...&quot;
mkdir -p $BACKUP_FOLDER
mv $BACKUP_NAME $BACKUP_FOLDER
echo &quot;Backup moved to backup folder.&quot;

echo &quot;Deleting old releases...&quot;
(cd $BACKUP_FOLDER &amp;amp;&amp;amp; (ls -t | head -n $KEEP; ls) | sort | uniq -u | xargs rm -rf)
echo &quot;Backup stored.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One catch: &lt;code&gt;pg_dumpall&lt;/code&gt; (used above) tries to dump &lt;em&gt;everything&lt;/em&gt; — including Postgres cluster-wide settings — which can be version-specific and cause headaches on import. For a major version jump, you want &lt;code&gt;pg_dump&lt;/code&gt;, which targets a single database and avoids the version mismatch landmines.&lt;/p&gt;
&lt;p&gt;For the migration, I only needed to change the &lt;code&gt;docker&lt;/code&gt; command we executed - with the added ENV vars, that is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;DB_USER=db_user
DB_PASSWORD=db_password
DATABASE_NAME=database_name

# ...

docker exec -e PGPASSWORD=$DB_PASSWORD -t $DB_CONTAINER \
    pg_dump -U $DB_USER $DATABASE_NAME &amp;gt; $BACKUP_NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the new backup in hand, importing into Postgres 17.5 went off without a hitch — no edits, no drama. Honestly, I was braced for a fight given the version gap, but the data was simple enough (and avoided fancy Postgres features) that it just… worked. A rare and pleasant surprise in a project full of moving parts.&lt;/p&gt;
&lt;h3 id=&quot;listing-image-migration&quot;&gt;Listing Image Migration&lt;/h3&gt;
&lt;p&gt;Unlike the data migration before it, migrating all the listing images (just shy of 50,000!) came with its own set of headaches. The legacy setup used CarrierWave with a custom uploader and fixed S3 paths, which worked fine at the time but wasn’t exactly future-proof. Since I was already upgrading to Rails 8, it made sense to tackle this technical debt head-on and move to ActiveStorage — effectively retiring these gems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;carrierwave&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fog-aws&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mini_magick&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;… and replacing them with &lt;code&gt;image_processing&lt;/code&gt; for post-processing.&lt;/p&gt;
&lt;p&gt;In the old days, uploads required creating an “Uploader” class and mounting it on a model. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# app/models/image.rb
class Image &amp;lt; ActiveRecord::Base
  mount_uploader :aws, ImageUploader
end

# app/uploaders/image_uploader.rb
class ImageUploader &amp;lt; CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  storage :fog

  process resize_to_fill: [850, 850]

  version :thumb do
    process resize_to_fill: [280, 280]
  end

  def store_dir
    &quot;listings/#{model.listing_id}/#{model.id}&quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With ActiveStorage, uploaders and hard-coded S3 paths are gone. You simply declare the attachment in your model (after setting up &lt;code&gt;config/storage.yml&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class Image &amp;lt; ApplicationRecord
  has_one_attached :file do |attachable|
    attachable.variant :thumb, resize_to_limit: THUMB_DIMENSIONS, preprocessed: true
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That takes care of &lt;em&gt;future&lt;/em&gt; uploads — but what about migrating the 50,000+ legacy images stored in the old bucket? The &lt;code&gt;image.aws&lt;/code&gt; field plus CarrierWave’s &lt;code&gt;store_dir&lt;/code&gt; gave me the exact file path to each image. I then wrote a script to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download each image from the legacy bucket.&lt;/li&gt;
&lt;li&gt;Re-upload it through ActiveStorage so it generates its own hashed storage path.&lt;/li&gt;
&lt;li&gt;Skip already-migrated images to allow safe re-runs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s the script in all its glory (run synchronously to avoid AWS rate limits — which meant a cool 4 hours of migration time):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;#!/usr/bin/env ruby

require_relative '../config/environment'
require 'aws-sdk-s3'
require 'stringio'

OLD_S3_BUCKET = Rails.application.credentials.dig(:old_aws, :bucket)
OLD_S3_REGION = Rails.application.credentials.dig(:old_aws, :region)
OLD_S3_ACCESS_KEY_ID = Rails.application.credentials.dig(:old_aws, :s3_key)
OLD_S3_SECRET_ACCESS_KEY = Rails.application.credentials.dig(:old_aws, :s3_secret)

# Optional: skip already migrated images
SKIP_EXISTING = true

s3 = Aws::S3::Client.new(
  region: OLD_S3_REGION,
  access_key_id: OLD_S3_ACCESS_KEY_ID,
  secret_access_key: OLD_S3_SECRET_ACCESS_KEY
)

puts &quot;Starting image migration...&quot;

Image.find_each do |image|
  begin
    if SKIP_EXISTING &amp;amp;&amp;amp; image.file.attached?
      puts &quot;Skipping Image #{image.id} (already attached)&quot;
      next
    end

    # Construct old S3 key from uploader logic - your path here
    key = &quot;listings/#{image.listing_id}/#{image.id}/#{File.basename(image[:aws].to_s)}&quot;

    obj = s3.get_object(bucket: OLD_S3_BUCKET, key: key)

    image.file.attach(
      io: StringIO.new(obj.body.read),
      filename: File.basename(key),
      content_type: obj.content_type || 'image/jpeg'
    )

    puts &quot;Migrated Image #{image.id} (Listing #{image.listing_id})&quot;
  rescue Aws::S3::Errors::NoSuchKey =&amp;gt; e
    warn &quot;Image #{image.id} missing in old bucket: #{key}&quot;
  rescue =&amp;gt; e
    warn &quot;Failed to migrate Image #{image.id}: #{e.class} - #{e.message}&quot;
  end
end

puts &quot;Migration script finished&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four hours later, we were in business — all images were now managed by ActiveStorage.&lt;br&gt;
Future uploads are handled automatically, thumbnails are generated on demand, and the whole setup is cleaner and easier to maintain.&lt;/p&gt;
&lt;h3 id=&quot;credentials-amp-security&quot;&gt;Credentials &amp;amp; Security&lt;/h3&gt;
&lt;p&gt;You might have noticed the use of &lt;code&gt;Rails.application.credentials&lt;/code&gt; in the previous script. That’s new territory — Rails encrypted credentials didn’t exist back in 4.2.&lt;/p&gt;
&lt;p&gt;Back then we had &lt;code&gt;secrets.yml&lt;/code&gt;, which stored everything in plain text and was meant to be excluded from Git. In theory, you’d inject it during deploy with whatever tooling you used. In practice… I was lazy. My deploys were manual, the repo was private, and I just checked them straight in. &lt;strong&gt;Big no-no.&lt;/strong&gt; Thankfully, Bitbucket never got hacked — but let’s just say this setup wouldn’t pass any kind of security audit.&lt;/p&gt;
&lt;p&gt;Rails 5.2 introduced encrypted credentials — finally, a way to store secrets in plain text &lt;em&gt;locally&lt;/em&gt; while Rails encrypts them with a master key. That master key stays out of Git and gets injected during deploy. Much better.&lt;/p&gt;
&lt;p&gt;Fast forward to today, and Kamal (my de facto deployment tool) takes it a step further with &lt;a rel=&quot;nofollow&quot; href=&quot;https://kamal-deploy.org/docs/commands/secrets/&quot;&gt;built-in support for pulling secrets&lt;/a&gt; straight from password managers like Bitwarden, 1Password, or LastPass. That means my Rails master key, database credentials, and other environment variables can live safely in Bitwarden, and Kamal just grabs them during deploy. No manual copying, no “where did I put that key?” moments, and no plain-text secrets hanging around in the repo.&lt;/p&gt;
&lt;p&gt;Here’s an example using Bitwarden via the CLI. This snippet fetches all secrets and assigns them to variables in &lt;code&gt;.kamal/secrets&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SECRETS=$(kamal secrets fetch --adapter bitwarden-sm all)

KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD $SECRETS)
RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY $SECRETS)
POSTGRES_USER=$(kamal secrets extract POSTGRES_USER $SECRETS)
POSTGRES_PASSWORD=$(kamal secrets extract POSTGRES_PASSWORD $SECRETS)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only catch: you’ll need to have the Bitwarden CLI installed and authenticated on every machine you deploy from. It’s a one-time setup, but totally worth it for the peace of mind of never having to worry about leaked secrets again.&lt;/p&gt;
&lt;h3 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h3&gt;
&lt;p&gt;Looking back, a few big takeaways stood out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scripts are your best friend.&lt;/strong&gt; Whether it’s a database dump, image migration, or credentials setup, having a repeatable script means you can run it, tweak it, and run it again without reinventing the wheel. It also removes a ton of mental overhead when you’re juggling multiple moving parts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test migrations in staging — thoroughly.&lt;/strong&gt; Moving to PostgreSQL 17.5 could have been a disaster if I’d gone straight into production. Running the full migration end-to-end in a safe environment gave me confidence and caught subtle issues before they ever touched live data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expect the cleanup phase.&lt;/strong&gt; Even after the “big ticket” migrations were done, staging revealed a laundry list of smaller fixes — broken image links, JavaScript load order issues, outdated gem calls, and other gremlins. None of these were major individually, but together they took nearly two weeks to iron out. Build that buffer into your timeline.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Take the opportunity to ditch technical debt.&lt;/strong&gt; CarrierWave, fog-aws, Sidekiq, Redis… all of these had served me well for years, but replacing them with ActiveStorage and SolidQueue means fewer dependencies to maintain, fewer services to monitor, and a cleaner architecture.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security deserves equal billing with features.&lt;/strong&gt; Rails encrypted credentials plus Bitwarden CLI integration finally dragged my secrets management into the modern age. No more plain-text secrets in Git. Enough said.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modern Rails is worth the leap.&lt;/strong&gt; From importmaps to Kamal, the tooling around Rails 8 makes deployment, scaling, and maintenance dramatically simpler than what I was doing in 2015.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h3&gt;
&lt;p&gt;And with that, JuggleBee officially joined the modern Rails era.&lt;/p&gt;
&lt;p&gt;This wasn’t just a version bump — it was a full-stack rejuvenation.&lt;br&gt;
The app runs faster, the infrastructure is leaner, and I finally have a deployment pipeline I can trust at 2 a.m. without crossing my fingers.&lt;/p&gt;
&lt;p&gt;Was it worth skipping incremental upgrades? Absolutely. Starting fresh on Rails 8 gave me a clean slate to rebuild only what mattered, using tools that will keep JuggleBee humming for years to come.&lt;/p&gt;
&lt;p&gt;If you’ve been sitting on a legacy Rails app, staring down the upgrade path and wondering if it’s worth the effort — it is. Just plan your migrations, test them in staging, and embrace the opportunity to shed some old weight while you’re at it.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.jugglebee.com&quot;&gt;JuggleBee’s&lt;/a&gt; now live on &lt;strong&gt;Rails 8 / Ruby 3.4.3 / PostgreSQL 17.5&lt;/strong&gt;, with ActiveStorage handling thousands of images, Bitwarden keeping our secrets safe, and Kamal making deployments a one-command affair.&lt;/p&gt;
&lt;p&gt;Now it’s time to step away from the terminal, grab a cold beer, and actually enjoy the thing I’ve been rebuilding over the last month — until the next big upgrade comes along.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/4934/jugglebees-great-leap-data-migration-activestorage-and-production-readiness-part-2</guid>
<pubDate>Sun, 24 Aug 2025 10:52:32 +0000</pubDate>
</item>
<item>
<title>JuggleBee’s Great Leap - Rebuilding a Rails 4 App in Rails 8 (Part 1)</title>
<link>https://coderlegion.com/4894/jugglebees-great-leap-rebuilding-a-rails-4-app-in-rails-8-part-1</link>
<description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;http://www.jugglebee.com&quot;&gt;JuggleBee&lt;/a&gt; was born in 2015. It was Namibia's first online auction platform and is still one of the biggest today. I built it with Ruby on Rails 4.2 on Ruby 2.2. It sat there, rock-solid and stubbornly stable, only needing the occasional dust-off and minor tweak over the years. At various points in time, I thought about upgrading the various versions; however, I was stuck between a rock and a hard place — in order to upgrade Ruby, I had to upgrade Rails, and vice versa. The idea of incremental upgrades felt like a nightmare — two battlefronts to fight on, Ruby on one side and Rails on the other.&lt;/p&gt;
&lt;p&gt;Fast forward to 2025. With the arrival of my daughter, I acquired a smattering of free time interspersed with sleepless nights. The perfect time to finally bite the bullet, bring JuggleBee into the 21st century (you know what I mean), and get these upgrades done. After much pondering and planning, only one realistic option remained... incremental upgrades would take months with constant patching between every version bump; I would have to take the leap from Rails 4.2 straight to Rails 8, with Ruby hopping from 2.2 to 3.4.3. It was quite the journey, and what follows is a breakdown of the challenges and learnings I made along the way.&lt;/p&gt;
&lt;h3 id=&quot;starting-fresh&quot;&gt;Starting Fresh&lt;/h3&gt;
&lt;p&gt;Not to blow my own horn or anything, but I was in a pretty good place with this migration plan. The codebase of JuggleBee was intentionally built with self-contained business logic components, defining a clear separation of concerns. The models and controllers were not overly bloated, with liberal usage of &quot;service objects&quot; performing the more complicated logic, and an added separation of logic between my controllers and views using the &quot;view decorator&quot; pattern. This architecture made the copy-pasta approach almost… dare I say… fun. But let’s not kid ourselves — a jump from Rails 4.2 to 8 is no walk in the park.&lt;/p&gt;
&lt;p&gt;As part of the &lt;code&gt;rails new&lt;/code&gt; process (after installing the latest Ruby and necessary Rails gems), and before the true code migration could begin, I just needed an empty, runnable project with the necessary gems installed. I appended my old &lt;code&gt;Gemfile&lt;/code&gt; with the auto-generated one, removing all locked versions to ensure the latest compatible versions were installed. I also identified irrelevant and dead gems, removing those and replacing them with alternatives where necessary (more detail on this later).&lt;/p&gt;
&lt;p&gt;Reading into each of the default gems specified by the &lt;code&gt;rails new&lt;/code&gt; generator gave me a good understanding of what the current Rails stack looks like. I didn’t need all of it, so some were commented out, but I did take some of the new suggestions into account. &lt;code&gt;Puma&lt;/code&gt;, for example, replaced &lt;code&gt;Unicorn&lt;/code&gt;, which I was previously using. I could also get rid of &lt;code&gt;God&lt;/code&gt;, in the non-divine sense, as I no longer needed to monitor my server state manually. All in all, this whole process didn’t take more than an hour or so.&lt;/p&gt;
&lt;h3 id=&quot;models-controllers-services-amp-views-in-that-order-&quot;&gt;Models, Controllers, Services &amp;amp; Views (in that order)&lt;/h3&gt;
&lt;p&gt;These being purely Ruby code made it the easiest place to start. Even though we jumped up from Ruby 2.2 to 3.4.3, not all that much in the core language changed. Twas Rails that was the most behind. For example, JuggleBee was developed before the abstract &lt;code&gt;ApplicationRecord&lt;/code&gt; class made its way into the Rails architecture!&lt;/p&gt;
&lt;h4 id=&quot;models&quot;&gt;Models&lt;/h4&gt;
&lt;p&gt;The models were the easiest to migrate over, as they already had a smattering of unit tests behind them. First, though, we had to get the database up and running. Spoiler alert: I was also updating our Postgres version from &lt;strong&gt;9.6&lt;/strong&gt; to &lt;strong&gt;17.5&lt;/strong&gt; as part of this big update. The old migration files were fossils — brittle, outdated, and utterly unfit for a modern Rails 8 app. The simplest solution was to drop a &lt;code&gt;pg_dump&lt;/code&gt; of the current database (just on my local copy of the now legacy JuggleBee) and import it, generating the &lt;code&gt;schema.rb&lt;/code&gt;. I could now copy across my models and test them out in the &lt;code&gt;rails console&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Some of the updates required to get things up and running were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;belongs_to&lt;/code&gt; is now a required atribute. I have a home-grown version of polymorphism which allows a &lt;code&gt;Listing&lt;/code&gt; to be either a &lt;code&gt;Product&lt;/code&gt; or &lt;code&gt;Auction&lt;/code&gt; and the &lt;code&gt;belongs_to&lt;/code&gt; on these associations are optional, so I had to update these associations accordingly (*&lt;strong&gt;side note&lt;/strong&gt;: a refactor waiting to happen*). So,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;belongs_to :auction
belongs_to :product
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;belongs_to :auction, optional: true
belongs_to :product, optional: true
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I had a couple of instances of &lt;code&gt;update_attributes&lt;/code&gt; (very selective. Given they bypass validations, they were used with extreme caution) which is now deprecated and had to be changed to &lt;code&gt;update&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deprecated validation methods such as &lt;code&gt;validates_presence_of :name&lt;/code&gt; needed updating to &lt;code&gt;validates :name, presence: true&lt;/code&gt; sort of changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for the views, the gems I used (&lt;code&gt;haml-rails&lt;/code&gt;, &lt;code&gt;redcarpet&lt;/code&gt;, &lt;code&gt;simple_form&lt;/code&gt;, &lt;code&gt;cocoon&lt;/code&gt;, etc) are all still actively maintained and required no changes at all — a very pleasant surprise.&lt;/p&gt;
&lt;h4 id=&quot;controllers&quot;&gt;Controllers&lt;/h4&gt;
&lt;p&gt;Next up were the controllers. Thanks to my use of service objects for the bulk of complex logic, migrating controllers was mostly painless. Rails 8 is stricter, and that’s where most of my changes were required. While bringing over controllers, I also began migrating the service objects they called upon, which are POROs and required almost no changes.&lt;/p&gt;
&lt;p&gt;The main updates included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Params passed to background jobs now must be valid JSON. This was especially relevant for controllers triggering email or background tasks.&lt;/li&gt;
&lt;li&gt;Controller &lt;code&gt;filter&lt;/code&gt;s were renamed to &lt;code&gt;action&lt;/code&gt;s (&lt;code&gt;before_filter&lt;/code&gt; → &lt;code&gt;before_action&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Controller hooks like &lt;code&gt;before_action&lt;/code&gt; should come after the method they reference, not at the top of the file (a style guideline enforced in modern Rails apps).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redirect_to :back&lt;/code&gt; was replaced with &lt;code&gt;redirect_back fallback_location: root_path&lt;/code&gt; (or an appropriate fallback path).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;responders&lt;/code&gt; gem is no longer included in Rails, so &lt;code&gt;respond_with&lt;/code&gt; calls were rewritten using &lt;code&gt;respond_to&lt;/code&gt; blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, the MVC migration was more about cleaning things up and embracing modern Rails conventions rather than fighting major incompatibilities.&lt;/p&gt;
&lt;h3 id=&quot;javascript-modernization&quot;&gt;JavaScript Modernization&lt;/h3&gt;
&lt;p&gt;This is where things started to get spicy — the kind of spicy where you wonder if you just bit off more than you can chew. So much has changed in the front-end assets side of things. JuggleBee leverages &lt;strong&gt;jQuery&lt;/strong&gt; (thankfully I dodged the &lt;em&gt;CoffeeScript&lt;/em&gt; bullet) with Sprockets as the asset pipeline. Modern Rails favours &lt;code&gt;importmaps&lt;/code&gt; as the default asset manager and pipeline, and keeping with the spirit of rejuvenating JuggleBee and bringing it up to speed, I signed up to it too. This allowed me to replace a bunch of gems which added various front-end features, such as &lt;code&gt;chartkick&lt;/code&gt;, &lt;code&gt;masonry&lt;/code&gt; and &lt;code&gt;bootstrap&lt;/code&gt; with the importmaps &lt;code&gt;pin&lt;/code&gt; alternative. Some libraries had to remain as CDN imports in my layout file, due to the order at which these JavaScripts got initialized and loaded by the DOM.&lt;/p&gt;
&lt;p&gt;My suite of JavaScript classes also needed a bit of love and attention. The Sprockets&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;//= require
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;statements were replaced with&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and my classes now had to &lt;code&gt;export&lt;/code&gt; themselves so that they could be loaded as ES modules. All the files had to be relocated from &lt;code&gt;app/assets/javascripts/&lt;/code&gt; to &lt;code&gt;app/javascript/&lt;/code&gt;. The way we add our JavaScript base file into our application view layout also had to change slightly, going from&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;%= javascript_include_tag &quot;application&quot; %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;%= javascript_importmap_tags %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even though &lt;code&gt;jQuery&lt;/code&gt; is considered a bit long in the tooth, given the plethora of really solid UI frameworks like Vue and React, I opted to keep my reliance on it for the time being. It still works, is actively maintained, and trying to replace it now would be a whole new kettle of fish. An adventure for another day.&lt;/p&gt;
&lt;h3 id=&quot;background-jobs-amp-scheduling&quot;&gt;Background Jobs &amp;amp; Scheduling&lt;/h3&gt;
&lt;p&gt;This area was one of the biggest wins in the entire migration. JuggleBee had the “classic” background processing setup: &lt;strong&gt;Sidekiq + Redis + whenever&lt;/strong&gt; (for cron). It worked fine for years, but it always felt a little… heavy, like lugging around a toolbox just to tighten a single screw. Sidekiq required its own container, Redis was a hungry beast that always felt like it was asking for more memory, and &lt;code&gt;whenever&lt;/code&gt; meant fiddling with cron jobs and ensuring everything stayed in sync across deploys. It worked, but it was yet another moving part in an already aging stack.&lt;/p&gt;
&lt;p&gt;Enter &lt;strong&gt;SolidQueue&lt;/strong&gt; — a gem that ships with Rails 8, built to replace Sidekiq-like setups with something that is both simpler and more tightly integrated with ActiveJob. The real beauty? &lt;strong&gt;No Redis.&lt;/strong&gt; SolidQueue uses the same database you already have (Postgres in our case) to manage job queues, which meant I could drop an entire service and reclaim a chunk of server memory.&lt;/p&gt;
&lt;p&gt;Here’s what this meant for JuggleBee:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No more Sidekiq configuration, container management, or Redis headaches.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;whenever&lt;/code&gt; gem (used for cron scheduling) could be thrown out too, thanks to SolidQueue’s built-in &lt;code&gt;recurring.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Background jobs now feel like a natural part of Rails — no extra glue required.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To put it in perspective, my stack went from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Rails App + Sidekiq + Redis + whenever + cron
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;to&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Rails App + SolidQueue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. Beautiful, minimal, and a lot less to maintain.&lt;/p&gt;
&lt;p&gt;Another &lt;em&gt;chef’s kiss&lt;/em&gt; moment was how little code I had to change. Most jobs migrated over with minimal tweaks — the biggest adjustment being that job arguments &lt;strong&gt;must be JSON-serializable&lt;/strong&gt;. This meant replacing keyword arguments with hashes like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;EmailJob.perform(&quot;MyEmailClass&quot;, {&quot;from&quot; =&amp;gt; current_user.name, &quot;subject&quot; =&amp;gt; &quot;Hello there&quot;})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;EmailJob.perform(&quot;MyEmailClass&quot;, from: current_user.name, subject: &quot;Hello there&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was one of those rare upgrades where less really is more. Dropping Redis and cron alone made this whole migration feel worth it.&lt;/p&gt;
&lt;h3 id=&quot;infrastructure-amp-deployment&quot;&gt;Infrastructure &amp;amp; Deployment&lt;/h3&gt;
&lt;p&gt;For years, deployment was powered by a custom shell script I wrote. It wasn’t flashy, but it was reliable and got the job done. It handled atomic releases, cleaned up old deployments, built Docker images, restarted containers, and even maintained a cache for faster updates. For a single-developer project like JuggleBee, it was the perfect balance of simplicity and control.&lt;/p&gt;
&lt;p&gt;Here’s the core of that script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

branch=${1:-master}
cwd=/home/ubuntu
repo_url=your_repo_here
revision=master
keep=5
timestamp=$(date +%s)
cache=$cwd/.git_cache
releases=$cwd/releases
mkdir -p $releases
previous=$releases/$(ls $releases/ -t | head -n 1)
release=$releases/$timestamp

if [ ! -d $cache ] ; then
        git clone $repo_url $cache
fi

echo &quot;downloading latest source code from $branch...&quot;
mkdir -p $release
(cd $cache &amp;amp;&amp;amp; git gc --prune=now &amp;amp;&amp;amp; git remote prune origin &amp;amp;&amp;amp; git fetch origin &amp;amp;&amp;amp; git reset --hard origin/$branch &amp;amp;&amp;amp; git archive $revision | tar -x -c $release)

echo &quot;release timestamp is: $timestamp ($release)&quot;

echo 'building docker images...'
/bin/bash -c &quot;(cd $release &amp;amp;&amp;amp; docker compose -f docker-production.yml build)&quot;

if [ $? -eq 0 ]
then
        if [[ $previous != &quot;&quot; ]] ; then
                echo 'stopping previous containers...'
                /bin/bash -c &quot;(cd $previous &amp;amp;&amp;amp; docker compose -f docker-production.yml stop &amp;amp;&amp;amp; docker ps -a -q --filter='status=exited' | xargs docker rm)&quot;
        fi

        echo 'restarting application...'
        /bin/bash -c &quot;(cd $release &amp;amp;&amp;amp; docker compose -f docker-production.yml up -d)&quot;

        echo 'deleting old releases...'
        (cd $releases &amp;amp;&amp;amp; (ls -t | head -n $keep; ls) | sort | uniq -u | xargs rm -rf)

        echo 'creating symlink.'
        rm $cwd/current-release
        ln -s $release $cwd/current-release

        echo 'deploy complete.'
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Honestly, this script could have kept soldiering on for years… until &lt;strong&gt;Kamal&lt;/strong&gt; walked in like the cool new kid who makes your old tricks look ancient. It wasn’t broken — far from it — but Kamal is like having a personal DevOps engineer in your terminal. It takes all the things I cared about (Dockerized deploys, atomic releases, rollbacks) and adds extra superpowers I didn’t even realize I needed.&lt;/p&gt;
&lt;h3 id=&quot;introducing-kamal-2&quot;&gt;Introducing Kamal 2&lt;/h3&gt;
&lt;p&gt;Kamal is a server provisioning and deployment tool built specifically (but not limited to) Rails apps. It automates a ton of tasks that my script didn’t — and one of the most significant changes? &lt;strong&gt;No more Nginx.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kamal ships with a built-in Traefik proxy that handles all your routing and SSL certificates out of the box. No more tinkering with &lt;code&gt;nginx.conf&lt;/code&gt; files or restarting a separate webserver. One less dependency chewing through RAM and one less thing to break at 2 am.&lt;/p&gt;
&lt;p&gt;Here’s what Kamal brings to the table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;kamal setup&lt;/code&gt;&lt;/strong&gt;: installs Docker, Git, and all required dependencies on your server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;kamal deploy&lt;/code&gt;&lt;/strong&gt;: builds your Rails app into a Docker image, pushes it to your registry, and runs it on the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik proxy with SSL (via Let’s Encrypt)&lt;/strong&gt;: you get HTTPS without lifting a finger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessory management&lt;/strong&gt;: want Postgres or Redis? Kamal spins them up as Docker containers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scaling&lt;/strong&gt;: need more capacity? add another container in deploy.yml and Kamal will route traffic automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The impact of this was huge. I went from managing Docker builds, old release directories, and an Nginx webserver, to just running one command. There’s something almost unsettling about how smooth it is — I felt like I was missing steps at first, like forgetting my keys when leaving the house.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Wait, that’s it? Did I actually deploy? Did I forget something? Oh… it’s done already. Huh.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This wasn’t just a convenience win — it was a dependency detox. Between dropping Nginx here and killing Redis with SolidQueue earlier, my infrastructure got a lot lighter, faster, and cheaper to run. Kamal didn’t just evolve my old script — it rendered half of its logic unnecessary.&lt;/p&gt;
&lt;h3 id=&quot;half-way-there&quot;&gt;Half Way There&lt;/h3&gt;
&lt;p&gt;With the new Rails 8 foundation in place, JuggleBee has already shed a lot of its old skin. We’ve modernized the models and controllers, swapped out a creaky asset pipeline for importmaps, retired Sidekiq, Redis, and cron in favor of SolidQueue, and traded a homegrown deployment script (solid as it was) for the convenience and power of Kamal 2. The app is lighter, faster to deploy, and much easier to maintain — but we’re not done yet.&lt;/p&gt;
&lt;p&gt;Getting the Rails 8 app running and deployable was only &lt;strong&gt;half the battle&lt;/strong&gt;. Now comes the rest of the journey:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migrating data from a legacy PostgreSQL 9.6 database to a fresh PostgreSQL 17.5 instance.&lt;/li&gt;
&lt;li&gt;Replacing CarrierWave with ActiveStorage and migrating all user-uploaded files into a new S3 bucket.&lt;/li&gt;
&lt;li&gt;Locking down credentials with Rails encrypted secrets and Bitwarden CLI.&lt;/li&gt;
&lt;li&gt;Cleaning up leftover code smells, finalizing test coverage, and polishing the overall performance of the new stack.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s some of what Part 2 will cover — all the finishing touches, the unexpected hurdles, and the final steps that took JuggleBee from a Rails 4 relic to a lean, modern, and production-ready Rails 8 app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stay tuned for Part 2, where the migration story continues.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Ruby on Rails</category>
<guid isPermaLink="true">https://coderlegion.com/4894/jugglebees-great-leap-rebuilding-a-rails-4-app-in-rails-8-part-1</guid>
<pubDate>Thu, 21 Aug 2025 08:06:05 +0000</pubDate>
</item>
<item>
<title>Mastering JavaScript: The Power of forEach and Ternary Operators</title>
<link>https://coderlegion.com/4813/mastering-javascript-the-power-of-foreach-and-ternary-operators</link>
<description>&lt;h5 id=&quot;this-article-explores-how-to-effectively-use-javascript-s-foreach-method-in-combination-with-the-ternary-operator-enhancing-your-understanding-of-the-underlying-code-while-writing-it-more-efficiently-&quot;&gt;This article explores how to effectively use JavaScript's forEach method in combination with the ternary operator, enhancing your understanding of the underlying code while writing it more efficiently!&lt;/h5&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1755105031209/12a1c778-3cfd-4890-880d-0af923826cae.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h6 id=&quot;image-credit-star-wars-character-lucasfilm-ltd-amp-tm-all-rights-reserved-coca-cola-can-the-coca-cola-company-used-under-fair-use-for-educational-purposes-&quot;&gt;&lt;em&gt;Image credit: Star Wars character © Lucasfilm Ltd. &amp;amp; TM. All Rights Reserved. Coca-Cola can © The Coca-Cola Company. Used under fair use for educational purposes.&lt;/em&gt;&lt;/h6&gt;
&lt;hr&gt;
&lt;h4 id=&quot;introduction&quot;&gt;Introduction&lt;/h4&gt;
&lt;p&gt;Using JavaScript's &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach&quot;&gt;forEach&lt;/a&gt; method in conjunction with the &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator&quot;&gt;ternary&lt;/a&gt; operator can increase your coding efficiency. Learning how to integrate different methods like this will enable you to write cleaner, more efficient code, enhancing readability and functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Throughout the article, we will discuss key JavaScript concepts, including:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Objects:&lt;/strong&gt; Understanding how to structure and utilize objects to organize data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arrays:&lt;/strong&gt; Learning how arrays can store multiple values and how to manipulate them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;forEach Method:&lt;/strong&gt; Discovering how to iterate over arrays efficiently using this built-in method.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterating and Modifying Object Arrays:&lt;/strong&gt; Exploring techniques to update object properties within arrays.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ternary Operator:&lt;/strong&gt; Mastering this concise alternative to traditional if-else statements for decision-making.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;javascript-objects&quot;&gt;JavaScript Objects&lt;/h4&gt;
&lt;p&gt;An &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object&quot;&gt;object&lt;/a&gt; in JavaScript is a collection of related data and functionality, organized as key-value pairs. Objects help you organize related information, making managing and accessing data in your code easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The following code defines a JavaScript object named Anakin. This object contains several key-value pairs that describe his attributes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const Anakin = {
  name: &quot;Anakin Skywalker&quot;,
  ForcePath: &quot;light&quot;,
  affiliation: &quot;Jedi&quot;,
  homePlanet: &quot;Tatooine&quot;,
  lightsaberColor: &quot;blue&quot;,
  mentor: &quot;Obi-Wan Kenobi&quot;,
  apprentice: &quot;Ahsoka Tano&quot;,
  knownAs: &quot;The Chosen One&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;javascript-array&quot;&gt;JavaScript Array&lt;/h4&gt;
&lt;p&gt;A JavaScript &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array&quot;&gt;array&lt;/a&gt; is a special type of object used to store multiple values in a single variable. Arrays are like lists that can hold a collection of items, such as numbers, strings, or even other objects. Each item in an array has a specific position, called an index, starting from zero. This makes accessing, adding, or modifying items using their index easy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We can create two new Star Wars character objects, and then add them to an array as follows:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const characters = [Anakin, ObiWan, Dooku];
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;javascript-foreach-method&quot;&gt;JavaScript forEach Method&lt;/h4&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach&quot;&gt;forEach&lt;/a&gt; method in JavaScript is a built-in function used to execute a specific function once for each element in an array. It's a convenient way to loop through all the items in an array without having to write a traditional &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for_statement&quot;&gt;for&lt;/a&gt; loop.&lt;/p&gt;
&lt;p&gt;When you use forEach, you provide a function that will be called for each element in the array. This function can perform any operation you need, such as logging values to the console, updating elements, or performing calculations.&lt;/p&gt;
&lt;p&gt;While iterating over the array with forEach, you can access the values of an object's properties using dot notation. Dot notation allows you to easily retrieve or update the value associated with a specific key in an object.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We can iterate over the Star Wars characters array and console log each character&lt;/em&gt;’&lt;em&gt;s&lt;/em&gt; &lt;strong&gt;&lt;em&gt;name&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;ForcePath&lt;/em&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;em&gt;affiliation&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;as follows:&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;characters.forEach(character =&amp;gt; {
  console.log(`Name: ${character.name}`);
  console.log(`Force Path: ${character.ForcePath}`);
  console.log(`Affiliation: ${character.affiliation}`);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;iterating-and-modifying-object-arrays&quot;&gt;Iterating and Modifying Object Arrays&lt;/h4&gt;
&lt;p&gt;Now that we have an understanding of a JavaScript object, an array, and the forEach Method: Let’s write code to iterate and modify the object arrays’ &lt;strong&gt;affiliation&lt;/strong&gt; values based on each character's &lt;strong&gt;ForcePath&lt;/strong&gt; value.&lt;/p&gt;
&lt;p&gt;If the character has a value of “&lt;strong&gt;light&lt;/strong&gt;“ for their &lt;strong&gt;ForcePath&lt;/strong&gt;, then their &lt;strong&gt;affiliation&lt;/strong&gt; value is &lt;strong&gt;“Jedi&lt;/strong&gt;.&lt;strong&gt;“&lt;/strong&gt; If the character has a value of “&lt;strong&gt;dark&lt;/strong&gt;“ for their &lt;strong&gt;ForcePath&lt;/strong&gt;, then their &lt;strong&gt;affiliation&lt;/strong&gt; value is &lt;strong&gt;“Sith&lt;/strong&gt;.&lt;strong&gt;“&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;characters.forEach(character =&amp;gt; {
  if (character.ForcePath === &quot;dark&quot;) {
    character.affiliation = &quot;Sith&quot;;
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Now, changing Anakin’s ForcePath to dark changes his character affiliation to Sith!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;ternary-operator&quot;&gt;Ternary Operator&lt;/h4&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator&quot;&gt;ternary&lt;/a&gt; operator in JavaScript is a shorthand way of writing an &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else&quot;&gt;if-else&lt;/a&gt; statement. It allows you to make a quick decision between two values based on a condition. The ternary operator uses the &lt;code&gt;?&lt;/code&gt; and &lt;code&gt;:&lt;/code&gt; symbols and follows this basic structure:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;condition ? valueIfTrue : valueIfFalse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here's how it works: if the condition is true, the operator returns the value before the colon (&lt;code&gt;:&lt;/code&gt;); if the condition is false, it returns the value after the colon. It's a concise way to assign values or execute expressions based on a condition, making your code shorter and often easier to read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We can revise the if statement code inside the forEach loop to a ternary operator for better readability and concise code:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;characters.forEach(character =&amp;gt; character.ForcePath === &quot;dark&quot; ? character.affiliation = &quot;Sith&quot; : character.affiliation = &quot;Jedi&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;codepen-demonstration&quot;&gt;&lt;strong&gt;CodePen Demonstration&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;To see the code in action, check out the complete implementation on CodePen &lt;a rel=&quot;nofollow&quot; href=&quot;https://codepen.io/Michael_Larocca/pen/azvVzgp?editors=0112&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. Make sure to open the console log to view the results.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;my-personal-use-case&quot;&gt;My Personal Use Case&lt;/h4&gt;
&lt;p&gt;As a personal project, I am working on a JavaScript Pac-Man game based on Ania Kubów’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=q2ViNbRwr5U&quot;&gt;1-hour Pac-Man in JavaScript YouTube tutorial&lt;/a&gt;. This tutorial was featured both on Scrimba and freeCodeCamp, and it’s a really fun way to learn JavaScript!&lt;/p&gt;
&lt;h5 id=&quot;-here-is-a-link-to-my-javascript-pac-man-game-which-is-in-progress-&quot;&gt;???? Here is a &lt;a rel=&quot;nofollow&quot; href=&quot;https://codepen.io/Michael_Larocca/project/full/ZvpWdE&quot;&gt;link&lt;/a&gt; to my JavaScript Pac-Man game, which is in progress.&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1754949308618/0535686e-7868-4553-ad77-c7d4aff0d9cd.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I added levels to my game. When each level is completed, I increase the speed of Pac-Man and all the ghosts.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Following Ania’s tutorial, I created the four ghosts using a JavaScript &lt;strong&gt;Ghost&lt;/strong&gt; class stored in a &lt;strong&gt;ghosts&lt;/strong&gt; array. After completing each game level, I needed to update each ghost's &lt;strong&gt;speed&lt;/strong&gt; value to achieve the desired result.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As a quite comical glitch, as the levels progress, the ghosts' speed increases so much that the gameplay becomes unplayable; they zip by so fast that avoiding them is impossible!&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;export class Ghost {
  constructor (className, startIndex, speed, size, color, eyes) {
    this.className = className;
    this.startIndex = startIndex;
    this.speed = speed;
    this.size = size;
    this.color = color;
    this.eyes = eyes;
    this.currentIndex = startIndex;
    this.isScard = false;
    this.timerId = NaN;
  }
}

export const ghosts = [
  new Ghost ('blinky', 321, 225,`ghost-${ghostSize}`, 'ghost-red', `ghost-look-left-${eyeSize}`),
  new Ghost ('inky', 376, 275,`ghost-${ghostSize}`, 'ghost-blue', `ghost-look-up-${eyeSize}`),
  new Ghost ('pinky', 377, 250,`ghost-${ghostSize}`, 'ghost-pink', `ghost-look-down-${eyeSize}`),
  new Ghost ('clyde', 378, 300,`ghost-${ghostSize}`, 'ghost-orange', `ghost-look-right-${eyeSize}`),
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The ghosts' speeds are initially set to different values in milliseconds, which determine how quickly they move. After each level is completed, the speed of each ghost is increased by reducing the time interval by 25 milliseconds. This makes the ghosts move faster, adding to the challenge of the game as players progress through the levels.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Using all of the JavaScript concepts covered in this article, I wrote the following code to “cap“ each ghost's speed at 100 milliseconds, which solved the issue of the ghost moving at an unplayable rate.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt; ghosts.forEach(ghost =&amp;gt; ghost.speed !== 100 ? ghost.speed -= 25 : ghost.speed = ghost.speed)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;my-other-related-articles&quot;&gt;My other related articles&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2025/06-25/javascript-understanding-the-set-and-clear-interval-methods/&quot;&gt;&lt;strong&gt;JavaScript: Understanding the Set and Clear Interval Methods&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.htmlallthethings.com/blog-posts/mastering-javascript-fundamentals-unleashing-your-framework-readiness&quot;&gt;&lt;strong&gt;Mastering JavaScript Fundamentals: Unleashing Your Framework Readiness&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2022/04-22/starwarsapi-01/&quot;&gt;&lt;strong&gt;JavaScript: How to Use the Star Wars API for Beginners&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2024/02-24/developing-a-dynamic-hamburger-menu-in-react-a-step-by-step-guide/&quot;&gt;&lt;strong&gt;Developing a Dynamic Hamburger Menu in React: A Step-by-Step Guide&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2025/05-25/how-to-build-a-star-wars-language-translator-in-react/&quot;&gt;&lt;strong&gt;How to Build a Star Wars Language Translator in React&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1740168177634/1ff578a9-5d03-4800-9c0c-9092e4e60c4f.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;be-sure-to-listen-to-the-html-all-the-things-podcast-&quot;&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2025/05-25/how-to-build-a-star-wars-language-translator-in-react/&quot;&gt;&lt;strong&gt;Be sure to listen to the HTML All The Things Pod&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;cast!&lt;/strong&gt;&lt;/h4&gt;
&lt;h5 id=&quot;-i-also-write-articles-for-the-html-all-the-things-podcast-which-you-can-read-on-their-website-https-www-htmlallthethings-com-&quot;&gt;???? &lt;em&gt;I also write articles for the HTML All The Things Podcast, which you can read on their website:&lt;/em&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.htmlallthethings.com/&quot;&gt;&lt;em&gt;https://www.htmlallthethings.com/&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/h5&gt;
&lt;h5 id=&quot;be-sure-to-check-out-html-all-the-things-on-socials-&quot;&gt;&lt;strong&gt;Be sure to check out HTML All The Things on socials!&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://twitter.com/htmleverything&quot;&gt;Twitter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/company/html-all-the-things/&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.tiktok.com/@htmlallthethings&quot;&gt;TikTok&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.instagram.com/htmlallthethings/&quot;&gt;Instagram&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;affiliate-amp-discount-links-&quot;&gt;Affiliate &amp;amp; Discount Links!&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1740168473785/c85789c9-1594-4000-aa2f-43e842f9825f.jpeg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With CodeMonkey, learning can be all fun and games!&lt;/strong&gt; CodeMonkey transforms education into an engaging experience, enabling children to evolve from tech consumers to creators. Use CodeMonkey's &lt;strong&gt;FREE trial&lt;/strong&gt; to unlock the incredible potential of young tech creators!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With a structured learning path tailored for various age groups, kids progress from block coding to more advanced topics like data science and artificial intelligence, using languages such as CoffeeScript and Python. The platform includes features for parents and teachers to track progress, making integrating coding into home and classroom settings easy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Through fun games, hands-on projects, and community interaction, CodeMonkey helps young learners build teamwork skills and receive recognition for their achievements. It fosters a love for coding and prepares children for future career opportunities in an ever-evolving tech landscape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;To learn more about CodeMonkey, you can read my detailed&lt;/em&gt;&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2025/02-25/inspiring-young-coders-how-codemonkey-turns-kids-into-tech-creators/&quot;&gt;&lt;strong&gt;&lt;em&gt;review article&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Affiliate Links:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://codemonkey.sjv.io/c/5987452/919057/12259&quot;&gt;Sign Up for Parents&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://codemonkey.sjv.io/c/5987452/919060/12259&quot;&gt;Sign Up for Teachers&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1740169191630/ac8c5360-d1c5-4c85-8504-18b9c755841e.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;advance-your-career-with-a-20-discount-on-scrimba-pro-using-this-affiliate-link-&quot;&gt;Advance your career with a 20% discount on Scrimba Pro using this &lt;a rel=&quot;nofollow&quot; href=&quot;https://scrimba.com/?via=MichaelLarocca&quot;&gt;affiliate link&lt;/a&gt;!&lt;/h4&gt;
&lt;p&gt;Become a hireable developer with Scrimba Pro! Discover a world of coding knowledge with full access to all courses, hands-on projects, and a vibrant community. You can &lt;a rel=&quot;nofollow&quot; href=&quot;https://selftaughttxg.com/2021/06-21/06-07-21/&quot;&gt;read my article&lt;/a&gt; to learn more about my exceptional experiences with Scrimba and how it helps many become confident, well-prepared web developers!&lt;/p&gt;
&lt;h6 id=&quot;important-this-discount-is-for-new-accounts-only-if-a-higher-discount-is-currently-available-it-will-be-applied-automatically-&quot;&gt;&lt;strong&gt;&lt;em&gt;Important:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;This discount is for new accounts only. If a higher discount is currently available, it will be applied automatically.&lt;/em&gt;&lt;/h6&gt;
&lt;p&gt;&lt;strong&gt;How to Claim Your Discount:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Click &lt;a rel=&quot;nofollow&quot; href=&quot;https://scrimba.com/?via=MichaelLarocca&quot;&gt;the link&lt;/a&gt; to explore the new Scrimba 2.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new account.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upgrade to Pro; the 20% discount will automatically apply.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h6 id=&quot;disclosure-this-article-contains-affiliate-links-i-will-earn-a-commission-from-any-purchases-made-through-these-links-at-no-extra-cost-to-you-your-support-helps-me-continue-creating-valuable-content-thank-you-&quot;&gt;&lt;strong&gt;&lt;em&gt;Disclosure:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;This article contains affiliate links. I will earn a commission from any purchases made through these links at no extra cost to you. Your support helps me continue creating valuable content. Thank you!&lt;/em&gt;&lt;/h6&gt;
&lt;hr&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;To become a better JavaScript developer, it's important to learn and understand the underlying logic of your code. This provides you with the skill to revise it using built-in methods, resulting in cleaner and more efficient code. For example, once you understand the logic and how to write a for loop, you can alternatively use JavaScript’s forEach method.&lt;/p&gt;
&lt;p&gt;Another example of code revision is using a ternary operator instead of an if-else statement. Combining shorthand operators and built-in methods further helps you to create more concise and readable code.&lt;/p&gt;
&lt;p&gt;Most importantly, enjoy the process of coding! I created objects featuring Star Wars characters to illustrate the concepts discussed. I then used these concepts to revise the code in my JavaScript Pac-Man game! What entertainment genres do you enjoy? Do you find coding games fun as well? Customize your learning experience to make it enjoyable and become a better developer!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Let’s connect! I’m active on&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/michaeljudelarocca/&quot;&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://twitter.com/MikeJudeLarocca&quot;&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:700/0*WkkMi-AgjubeODf8.jpeg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h6 id=&quot;are-you-now-confident-in-using-javascript-s-foreach-method-and-ternary-operators-to-write-more-efficient-code-do-you-have-other-tips-for-mastering-these-javascript-concepts-please-share-the-article-and-comment-&quot;&gt;&lt;em&gt;Are you now confident in using JavaScript's forEach method and ternary operators to write more efficient code? Do you have other tips for mastering these JavaScript concepts? Please share the article and comment!&lt;/em&gt;&lt;/h6&gt;
&lt;hr&gt;
</description>
<category>JavaScript</category>
<guid isPermaLink="true">https://coderlegion.com/4813/mastering-javascript-the-power-of-foreach-and-ternary-operators</guid>
<pubDate>Mon, 18 Aug 2025 20:42:57 +0000</pubDate>
</item>
<item>
<title>Sharding &amp; Partitioning Secrets You Were Never Told</title>
<link>https://coderlegion.com/2941/sharding-partitioning-secrets-you-were-never-told</link>
<description>&lt;p&gt;Beneath every blazing-fast app, behind every seamless digital experience, lies a &lt;strong&gt;forbidden architecture&lt;/strong&gt;—one that few dare to discuss. Two ancient techniques, whispered in server rooms and scribbled in the margins of database logs, hold the key: &lt;strong&gt;Sharding&lt;/strong&gt; and &lt;strong&gt;Partitioning&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But beware—this knowledge is &lt;strong&gt;dangerous&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Partitioning: The Silent Knife in the Dark&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Your database is a living entity, growing, consuming, swelling until it chokes on its own weight. Then... the knife falls.&lt;/p&gt;
&lt;p&gt;Partitioning splits the beast—not by destroying it, but by carving it into manageable pieces. Each slice obeys a hidden rule (a date, a name, a secret key), allowing queries to move like shadows, slipping through only what they need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Good&lt;/strong&gt;: Faster. Cleaner. Contained.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bad&lt;/strong&gt;: Still one beast. Still one lair.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Truth&lt;/strong&gt;: You’ve only delayed the inevitable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⚔️ Sharding: The Fracturing of Realms&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When one world is no longer enough, you shatter it.&lt;/p&gt;
&lt;p&gt;Sharding does not cut—it replicates, spawning parallel dimensions of data, each ruling its own domain. No single point of failure. No master, only fragments of power.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Good&lt;/strong&gt;: Infinite scale. Unbreakable resilience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bad&lt;/strong&gt;: Complexity. The risk of imbalance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Truth&lt;/strong&gt;: Once you shard, there is no going back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; The Forbidden Choice&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Partitioning&lt;/strong&gt; is the &lt;strong&gt;monk’s path&lt;/strong&gt;—orderly, controlled, but limited.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sharding&lt;/strong&gt; is the &lt;strong&gt;warlock’s gambit&lt;/strong&gt;—unleashing power at a cost.&lt;/p&gt;
&lt;p&gt;Which will you choose when your data demands sacrifice?&lt;/p&gt;
&lt;p&gt; The secrets deepen… &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.link-trim.in/FSBAwJ9D&quot;&gt;Unlock the truth here&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Full-stack Dev</category>
<guid isPermaLink="true">https://coderlegion.com/2941/sharding-partitioning-secrets-you-were-never-told</guid>
<pubDate>Fri, 09 May 2025 17:16:44 +0000</pubDate>
</item>
<item>
<title>The Most Powerful Refactor You’ll Never Commit</title>
<link>https://coderlegion.com/1754/the-most-powerful-refactor-youll-never-commit</link>
<description>&lt;p&gt;Sometimes the most effective change you can make isn’t in the code at all—it’s in how you think about the code. It’s a shift in understanding, not syntax. This kind of change happens quietly: a name stays the same, no lines are added or deleted, but your mental model adjusts. You stop fighting what a variable should mean and start working with what it does mean. In doing so, you unlock momentum. You’re no longer blocked by a mismatch between intention and reality. You simply choose to interpret differently, and the problem dissolves.&lt;/p&gt;
&lt;p&gt;This comes up constantly in programming. We all value clarity and meaning in the names we choose—function names, field names, class names, all of it. When those names align with their purpose, it’s easier to reason about the system. But that alignment isn’t always perfect, and chasing it can become a trap. The code might be working just fine, doing exactly what you need, but its wording is off. That tension can tempt you to refactor—rename, restructure, redefine—when what’s really needed is a change in how you think about the thing in front of you.&lt;/p&gt;
&lt;p&gt;Letting go of that urge doesn’t mean ignoring problems or giving up on maintainability. It means recognizing that not all mismatches need to be resolved in code. Sometimes it’s more pragmatic to mentally adapt than to physically rewrite. This kind of decision can accelerate progress—helping a team build on existing systems rather than stalling out in pursuit of semantic perfection. Especially in fast-moving environments, reframing how you interpret a symbol or component can be the difference between moving forward or grinding to a halt.&lt;/p&gt;
&lt;p&gt;That said, it’s not free. This is a form of technical debt. Like all debt, it carries risk. Over time, a system full of misnamed parts can create real confusion. But in my experience, when managed intentionally, this kind of debt-taking often pays off. It lets teams prioritize function over form, momentum over polish. The key is awareness: knowing when you’re choosing to change your mind instead of the code, and making sure that choice is deliberate. It’s not a failure of discipline—it’s a technique. And sometimes, it’s the best one you’ve got.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/1754/the-most-powerful-refactor-youll-never-commit</guid>
<pubDate>Mon, 31 Mar 2025 19:52:45 +0000</pubDate>
</item>
<item>
<title>Code Refactoring - Python Best Practices and Tips</title>
<link>https://coderlegion.com/377/code-refactoring-python-best-practices-and-tips</link>
<description>&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Software &lt;strong&gt;normally fails&lt;/strong&gt; when it becomes so &lt;strong&gt;complex&lt;/strong&gt; that it can &lt;strong&gt;no longer provide the additional features&lt;/strong&gt; needed while remaining error-free. Refactoring is used to &lt;strong&gt;improve the code design&lt;/strong&gt; to make it easier to understand and extensible. If you believe that a feature may be needed and your current code will not easily accommodate it, you can refactor that code. You make it easier to add that feature now, rather than worrying about what you should change in your code to add the feature later.&lt;/p&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Importance of Refactoring for Code Maintainability and Readability&lt;/h2&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Why should you refactor? By removing duplicate code, you reduce the overall codebase, making it easier to modify and understand. Hence, you have &lt;strong&gt;less code that is easier to modify&lt;/strong&gt; and understand, which you are well aware of if you look at huge programs and try to understand how they work.&lt;/p&gt;
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;Writing understandable code will make it &lt;strong&gt;easy to modify and maintain the code&lt;/strong&gt;. By refactoring the code, you will understand the system better. If you know the system better, it would be easier to spot bugs.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;Refactoring also helps you &lt;strong&gt;write code faster&lt;/strong&gt;. If you write understandable code, you will spend all your time adding features instead of having to go back and try to understand the code. You have written repetitively to fix bugs and incorporate new features.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;Refactoring also makes the code easy to read. &lt;strong&gt;Eliminating duplication makes modification easy&lt;/strong&gt; and minimizes complex conditional logic.&lt;/li&gt; 
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=9348492370158194588&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;In this article, I will cover the importance of refactoring, its principles and designs, and how you can improve your program readability through refactoring techniques. I will also discuss the best practices for enhancing the performance of your Python code.&lt;/p&gt; 
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Identifying Code Smells and Refactoring Opportunities&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Introduction to Code Smells and Their Impact on Code Quality&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;While refactoring code, you are looking for bad smells, which indicates design problems. A &lt;strong&gt;code smell is like detecting in-depth issues&lt;/strong&gt; and concerns in the application or its logic. These issues are &lt;strong&gt;not bugs and errors&lt;/strong&gt; but deviations from the code design and its fundamentals that &lt;strong&gt;negatively impact the code quality&lt;/strong&gt;. This violation will not affect the code compilation but will make the program &lt;strong&gt;performance vulnerable to future security threats&lt;/strong&gt;. Therefore, these code smells are known as bad smells that require a thorough investigation of the program codebase to take immediate action to enhance the quality.&lt;/p&gt;  
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Common Code Smells in Python Programs&lt;/h3&gt;  
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;When the developer fails to write the code as per the defined design standard, it leads to code smell. Bad code is the result of &lt;strong&gt;hard deadlines, mismanagement, shortcuts, and inexperienced developer skills&lt;/strong&gt;, which leads developers to make mistakes during the development process. Now, in Python, various types of code smell &lt;strong&gt;may differ from project to project&lt;/strong&gt;. These are:&lt;/p&gt;
&lt;ol&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Duplicate Code:&lt;/strong&gt; One of the most common code smells is code duplication. It means that a similar block of code is used more than once in the program. Instead of copy-paste, there is also duplication in the code structure and inheritance hierarchies. Therefore, fixing it is easy by extracting the duplicate code into a separate function and then calling it whenever you need to.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Long Methods:&lt;/strong&gt; Another common code smell is long methods. This occurs when the function is too long and is responsible for many tasks. Breaking the long methods into smaller methods, where each must perform its task independently, will resolve this issue.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Improper Names:&lt;/strong&gt; Using the proper names of variables, classes, and methods will make the code understandable and clean. If you use character-based names or non-descriptive function names, it leads to code smell that makes it difficult to read and maintain. Therefore, the naming convention should be descriptive.&lt;/li&gt;
&lt;/ol&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Some other code smells that need your attention are:&lt;/p&gt; 
&lt;p&gt;&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=11171628092731303793&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Techniques for Identifying Refactoring Opportunities Using Code Reviews and Analysis Tools&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Code review is the process used to &lt;strong&gt;detect quality issues&lt;/strong&gt; in an application. The most common issue that &lt;strong&gt;impacts code quality is bad smell&lt;/strong&gt;. Code refactoring is an effective process for tracing code smell and maintaining software quality. It makes the code &lt;strong&gt;cleaner, concise, and effective&lt;/strong&gt; without modifying its core functionalities. Furthermore, code review and analysis tools will help you identify the areas that benefit from refactoring. Several techniques for identifying refactoring opportunities are as follows:&lt;/p&gt;
&lt;div class=&quot;div-blue&quot;&gt;  
&lt;span class=&quot;alert-header&quot;&gt;Note:&lt;/span&gt;  
&lt;span class=&quot;alert-body&quot;&gt;Some people think that refactoring is related to applying design patterns to your code, which is not true. However, spending a lot of time creating a better design is a simple refactoring goal.  
&lt;/span&gt; 
&lt;/div&gt;
&lt;ol&gt;
 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Duplicate Code:&lt;/strong&gt; Duplicate code is a common issue for refactoring. &lt;a rel=&quot;nofollow&quot; href=&quot;https://pypi.org/project/pylint/&quot; title=&quot;file&quot;&gt;pylint&lt;/a&gt;, and &lt;strong&gt;FindBugs&lt;/strong&gt; are effective tools for analyzing and finding duplicate pieces of code. These tools reduce the risk of inconsistencies and make maintenance easier.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Complexity Analysis:&lt;/strong&gt; &lt;strong&gt;PyCharm&lt;/strong&gt; is an IDE that provides the features of code analysis and refactoring tools and helps identify areas that would benefit from refactoring. In addition, tools like &lt;strong&gt;SonarQube and Code Climate&lt;/strong&gt; will ensure the complexity analysis of code and provide the necessary tips to make it less complex.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Code Static Analysis:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://mypy.readthedocs.io/en/stable/&quot; title=&quot;file&quot;&gt;mypy&lt;/a&gt; is a tool used to check Python code to identify potential bugs in your code. This tool ensures that your code follows a consistent structure.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Security Analysis:&lt;/strong&gt; Tools like &lt;strong&gt;Bandit&lt;/strong&gt; will help Python developers &lt;strong&gt;identify potential security threats in their code.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt; 
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Principles and Patterns of Refactoring&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Introduction to Refactoring Principles&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;To write a maintainable and clean code of high quality, there are certain &lt;strong&gt;guidelines known as refactoring principles&lt;/strong&gt;. These principles are the set of instructions proven to work over the years. These popular principles are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;DRY:&lt;/strong&gt; Known as &lt;strong&gt;&quot;Don’t Repeat Yourself.&quot;&lt;/strong&gt;. This principle draws attention to the &lt;strong&gt;duplication problem within the code&lt;/strong&gt;. When a block of code is used repeatedly, it makes the code harder to maintain and update because updating would be required at multiple locations. To implement this principle, developers must create a method containing duplicate content to ensure that logic is written in only one place and that the function can be called when needed.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;KISS:&lt;/strong&gt; Knows as &lt;strong&gt;&quot;Keep It Super Simple&quot;&lt;/strong&gt;. This principle focuses on writing the &lt;strong&gt;code as simply as possible&lt;/strong&gt; and in a way that the junior developer can easily understand. It highlights the simplicity of the code design and implementation, which makes the code more maintainable and readable. The main point is to avoid unnecessary complexity that leads to poor code quality and confusion among developers.&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;SOLID:&lt;/strong&gt; This principle is further divided into &lt;strong&gt;five principles&lt;/strong&gt; that you can follow as the code passes the prototype phase. These five principles are as follows:
&lt;ol&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;S-Single Responsibility Principle (SRP):&lt;/strong&gt; This principle emphasizes that each class in the code should have one responsibility or purpose. It ensures that the &lt;strong&gt;specific class or module is focused on one task&lt;/strong&gt;, which makes the code less complex when modification is required.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;O-Open/Closed Principle (OCP):&lt;/strong&gt; This principle emphasizes that each fundamental of code, like classes, modules, and &lt;strong&gt;functions, should be open to changes and modification&lt;/strong&gt; without the need to change their existing behavior. This makes the code more flexible and modular.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;L-Liskov Substitution Principle (LSP):&lt;/strong&gt; This principle's focus is that each derived class should be able to implement or replace the base class without any error. It means that the &lt;strong&gt;objects of the superclass are replaceable by subclasses&lt;/strong&gt; without affecting the program's behavior. It makes the code more extensible and interchangeable.&lt;/li&gt;  
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;I-Interface Segregation Principles (ISP):&lt;/strong&gt; This principle focuses on &lt;strong&gt;implementing multiple small interfaces based on client needs&lt;/strong&gt; instead of one large interface. In this way, clients can interact with a specific interface according to their needs instead of a monolithic interface.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;D-Dependency Inversion Principle (DIP):&lt;/strong&gt; These principles emphasize the use of an &lt;strong&gt;abstraction layer&lt;/strong&gt; instead of the direct interaction between high- and low-level modules. This means that the high-level modules should not directly focus on the low-level module, which makes them highly coupled and difficult to modify.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Exploring Common Refactoring Patterns and Techniques&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Let's explore common code refactoring patterns and techniques. These areas follows:&lt;/p&gt; 
&lt;ol&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Extract Method:&lt;/strong&gt; Used to break large methods into separate functions or methods to simplify complex logic and make them more manageable.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Replace Conditional with Polymorphism:&lt;/strong&gt; Replaces the complex conditional logic with a polymorphism or inheritance concept to make the code easy to understand and modify.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Extract Class:&lt;/strong&gt; Used to place all related methods and fields in one class. It makes the class more manageable when it becomes large and complex; therefore, handles some responsibilities in a separate class.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Extract Variable:&lt;/strong&gt; Used to capture all complex expressions and variables and replace their names with descriptive names.&lt;/li&gt;  
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Remove Parameters:&lt;/strong&gt; Remove all unnecessary parameters used in the method signature to improve readability.
&lt;/li&gt;
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Split Loop:&lt;/strong&gt; Divide the large loop expression into smaller loops to enhance code clarity.&lt;/li&gt; 
&lt;li style=&quot;text-align: justify; margin: 1em;&quot;&gt;&lt;strong&gt;Introduce Design Patterns:&lt;/strong&gt; Use design patterns to solve recurring problems instead of writing the code yourself.&lt;/li&gt;
&lt;/ol&gt; 
&lt;p&gt;&lt;img src=&quot;https://logiclair.org/?qa=blob&amp;amp;qa_blobid=14245653729998271027&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Understanding When and How to Apply Each Refactoring Pattern Effectively&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;Selecting the correct refactoring pattern and techniques and understanding when to use each depends on the code requirements. They require careful consideration and context upon which each is used. Let's explore the requirements of some of them:&lt;/p&gt;  
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;1. Extract Method&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;When to Apply:&lt;/strong&gt; Having duplicate and large methods that are replaced with a small separate method.&lt;br&gt; 
&lt;strong&gt;How to Apply:&lt;/strong&gt; Identify the duplicate code, extract the code into a separate method, and Call the method where needed.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;2. Replace Conditional with Polymorphism&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;When to Apply:&lt;/strong&gt; Code containing complex conditional logic with object behavior changing on the basis of different states. &lt;br&gt;
&lt;strong&gt;How to Apply:&lt;/strong&gt; Remove all conditional logic and replace them with separate classes, where each class defines a separate state. Each class has its own method and fields.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;3. Extract Class&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;When to Apply:&lt;/strong&gt; One class performs too many distinct tasks and has many responsibilities. This makes the code logic complex.&lt;br&gt; 
&lt;strong&gt;How to Apply:&lt;/strong&gt; Identify the methods and related fields that have similar tasks and group them into separate classes.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;4. Extract Variable&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;When to Apply:&lt;/strong&gt; When the same expression is used repeatedly within the method. Therefore, it is used to enhance code readability. &lt;br&gt;
&lt;strong&gt;How to Apply:&lt;/strong&gt; Identify all repeated expressions within the method. Then, assign it to a variable with a descriptive name.&lt;/p&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;5. Remove Parameters&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;&lt;strong&gt;When to Apply:&lt;/strong&gt; When the parameter used in the method signature is no longer necessary. Furthermore, removing the parameter does not affect the functionality of the method.&lt;br&gt;
&lt;strong&gt;How to Apply:&lt;/strong&gt; Identify the unnecessary parameter and check the method body if it is used within the method. Next, remove the parameter when it is unnecessary and update the caller.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#An Example for removing the unnecessary parameter of middle name 
#which is not used 
def enter_Name(f_Name, m_Name, l_Name):
    return f&quot;{f_Name} {m_Name} {l_Name}&quot;
# Usage
full_name = enter_Name(&quot;Harry&quot;, &quot;&quot;, &quot;Ford&quot;)
print(full_name)
#----------------------------------------------------------------!
#After Refactoring
def enter_Name(f_Name, l_Name):
    return f&quot;{f_Name} {l_Name}&quot;
# Usage
full_name = enter_Name(&quot;Harry&quot;, &quot;Ford&quot;)
print(full_name)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Refactoring Techniques for Improved Readability&lt;/h2&gt; 
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Breaking Down Long and Complex Functions into Smaller One&lt;/h3&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;One of the most common techniques for code refactoring is the extract method. This technique is used to &lt;strong&gt;break down complex and larger methods into smaller ones&lt;/strong&gt; that are more manageable. Here, the block of code that performs a specific task is extracted into the new function. In addition, if the method is too old and not used frequently, then replacing the function call with method code i.e. &lt;strong&gt;inline method&lt;/strong&gt; is preferable to avoid duplication and reduce complexity. Also, try to use the descriptive names of the methods that specify their task and the variable names within the method.&lt;/p&gt;
&lt;div class=&quot;div-red&quot;&gt;  
&lt;span class=&quot;alert-header&quot;&gt;Caution:&lt;/span&gt;  
&lt;span class=&quot;alert-body&quot;&gt;Always ensure that the refactored code maintains the same functionality as the original code. Also, thoroughly test to detect any unintended changes in behavior.
&lt;/span&gt; 
&lt;/div&gt;
&lt;h3 style=&quot;margin: 0.5;&quot;&gt;Improving Variable Names and Code Comments for Clarity and Understanding&lt;/h3&gt; 
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;When writing the code, use descriptive names for variables, functions, classes, and all other elements that adhere to &lt;strong&gt;industry standards and conventions&lt;/strong&gt;. The use of a naming convention will improve the readability of code because it properly &lt;strong&gt;conveys its purpose and functionality&lt;/strong&gt;, making it easier for a developer to understand the codebase and logic. In addition, the use of comments within the code will &lt;strong&gt;clarify the tasks and responsibilities of the classes and functions&lt;/strong&gt;. Therefore, to implement the code refactoring, improve the variable name and add comments to clarify the code.&lt;/p&gt;
&lt;div class=&quot;div-faq&quot; style=&quot;margin-bottom: 5px; margin-top: 2px;&quot;&gt;
  &lt;span class=&quot;faq-header&quot; style=&quot;font-weight: bold; color: #333;&quot;&gt;FAQs&lt;/span&gt;
  &lt;div class=&quot;faq-body&quot; style=&quot;margin-top: 2px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Q:&lt;/strong&gt; What is code refactoring in Python?&lt;br&gt;
    &lt;strong&gt;A:&lt;/strong&gt; In Python, it is the process of restructuring Python's existing code without changing its external behavior.
  &lt;/div&gt;
  &lt;div class=&quot;faq-body&quot; style=&quot;margin-top: 2px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Q:&lt;/strong&gt; Is it important in Python development?&lt;br&gt;
    &lt;strong&gt;A:&lt;/strong&gt; It is important in Python because it enhance readability, code quality, and maintainability and reduces bug risk.
  &lt;/div&gt;
  &lt;div class=&quot;faq-body&quot; style=&quot;margin-top: 2px; margin-bottom: 10px;&quot;&gt;
    &lt;strong&gt;Q:&lt;/strong&gt; Is there any tool available with the IDE in Python?&lt;br&gt;
    &lt;strong&gt;A:&lt;/strong&gt; Tools like PyCharm, Visual Studio Code with Python extensions, Rope, and Black are commonly used for code refactoring in Python.
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p style=&quot;text-align: justify; margin: 1;&quot;&gt;In conclusion, we discussed the importance of code refactoring in the era of programming. Whether you're developing a small application or an enterprise-level application, &lt;strong&gt;code quality matters the most&lt;/strong&gt;. Refactoring is &lt;strong&gt;not a magic button&lt;/strong&gt; that resets the entire code, but it tells you the &lt;strong&gt;effective approach for writing maintainable code&lt;/strong&gt;. It contains many strategies and techniques by which the developer can write perfect code. The perfect code requires &lt;strong&gt;fewer upgrades and enhances productivity&lt;/strong&gt;. I hope this guide is helpful for you. Thank you for reading this. Happy Coding!&lt;/p&gt; 
&lt;hr&gt;
&lt;h2 style=&quot;margin: 0.5;&quot;&gt; Reference&lt;/h2&gt;   
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.jetbrains.com/help/pycharm/refactoring-source-code.html&quot; title=&quot;file&quot;&gt;PyCharm Refactoring Documentation&lt;/a&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://peps.python.org/pep-0008/&quot; title=&quot;file&quot;&gt;PEP 8 style guide for Python code&lt;/a&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672&quot; title=&quot;file&quot;&gt;Effective Book on Refactoring&lt;/a&gt;&lt;/p&gt;
</description>
<category>Best Practices</category>
<guid isPermaLink="true">https://coderlegion.com/377/code-refactoring-python-best-practices-and-tips</guid>
<pubDate>Wed, 26 Jun 2024 14:38:16 +0000</pubDate>
</item>
</channel>
</rss>