Back to Scaling Ruby Applications guides

Reek: Ruby Code Smell Detection Made Simple

Stanley Ulili
Updated on September 24, 2025

As Ruby projects grow, subtle design issues can creep in and quietly erode code quality. Reek helps you catch these problems early by detecting code smells—patterns that hint at deeper structural flaws.

It scans your code for anti-patterns like long methods, feature envy, and data clumps, surfacing opportunities for refactoring before they turn into maintenance headaches. Unlike formatters that only polish style, Reek focuses on the overall health and design of your codebase.

This guide walks through installing, configuring, and integrating Reek to keep your Ruby projects clean and maintainable.

Prerequisites

To work through this guide, you'll need Ruby 2.7 or later installed:

 
ruby --version
Output
ruby 3.4.5

This guide assumes familiarity with Ruby programming concepts including classes, methods, and basic object-oriented design principles. Understanding common refactoring patterns will help you interpret and act on Reek's findings.

Understanding code smells and quality issues

Code smells are symptoms of deeper design problems that make code harder to understand, modify, and maintain. These issues often develop incrementally as features are added without careful attention to overall design quality.

Consider this example that demonstrates several common code quality issues:

problem_code.rb
class UserManager
  def process_user_data(name, email, age, role, department, salary, manager_id, start_date)
    # Long parameter list - data clump smell

    if role == "admin"
      if age > 18
        if email.include?("@")
          if salary > 50000
            # Nested conditionals - complexity smell
            user = create_user_hash(name, email, age, role, department, salary, manager_id, start_date)
            @admin_users << user
            send_welcome_email(user)
            setup_admin_permissions(user)
            return "Admin user created successfully"
          else
            return "Insufficient salary for admin role"
          end
        end
      end
    elsif role == "guest"
      # Duplicated logic - duplication smell
      if age > 16 && email.include?("@")
        user = create_user_hash(name, email, age, role, department, 0, nil, start_date)
        @guest_users << user
        send_welcome_email(user)
        return "Guest user created successfully"
      end
    end

    return "Unknown role type"
  end

  def send_welcome_email(user)
    # Feature envy - accessing too much data from user
    puts "Welcome #{user[:name]} to #{user[:department]} as #{user[:role]}"
  end
end

This code exhibits multiple quality issues: excessively long methods, too many parameters, deep nesting, duplicated logic, and methods that access too much external data. These problems make the code difficult to test, modify, and understand.

Manual code review might miss some of these issues, especially in larger codebases where patterns emerge across multiple files. Reek automates this analysis, consistently identifying quality problems regardless of code review attention.

Create a project directory to explore Reek's capabilities:

 
mkdir reek-analysis-demo && cd reek-analysis-demo

Installing and basic usage

Reek installs as a Ruby gem and works immediately with sensible defaults for detecting common code quality issues. The tool provides both command-line analysis and programmatic integration options.

Create a Gemfile for your project:

 
bundle init

Add Reek to your project's Gemfile:

Gemfile
source 'https://rubygems.org'

gem 'reek', '~> 6.5'

Install the dependencies:

 
bundle install
Output
Fetching gem metadata from https://rubygems.org/...
Resolving dependencies...
Fetching reek 6.5.0
Installing reek 6.5.0
Bundle complete! 1 Gemfile dependency, 18 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

Create the problematic code example from above:

user_manager.rb
class UserManager
  def process_user_data(name, email, age, role, department, salary, manager_id, start_date)
    if role == "admin"
      if age > 18
        if email.include?("@")
          if salary > 50000
            user = create_user_hash(name, email, age, role, department, salary, manager_id, start_date)
            @admin_users << user
            send_welcome_email(user)
            setup_admin_permissions(user)
            return "Admin user created successfully"
          else
            return "Insufficient salary for admin role"
          end
        end
      end
    elsif role == "guest"
      if age > 16 && email.include?("@")
        user = create_user_hash(name, email, age, role, department, 0, nil, start_date)
        @guest_users << user
        send_welcome_email(user)
        return "Guest user created successfully"
      end
    end

    return "Unknown role type"
  end

  def send_welcome_email(user)
    puts "Welcome #{user[:name]} to #{user[:department]} as #{user[:role]}"
  end

  def setup_admin_permissions(user)
    puts "Setting up admin permissions for #{user[:name]} in #{user[:department]}"
  end
end

Run Reek to analyze the code quality:

 
bundle exec reek user_manager.rb
Output
Inspecting 1 file(s):
S

user_manager.rb -- 9 warnings:
  [5, 18]:DuplicateMethodCall: UserManager#process_user_data calls 'email.include?("@")' 2 times
  [9, 21]:DuplicateMethodCall: UserManager#process_user_data calls 'send_welcome_email(user)' 2 times
  [30, 30, 30]:FeatureEnvy: UserManager#send_welcome_email refers to 'user' more than self
  [34, 34]:FeatureEnvy: UserManager#setup_admin_permissions refers to 'user' more than self
  [1]:InstanceVariableAssumption: UserManager assumes too much for instance variable '@admin_users'
  [1]:InstanceVariableAssumption: UserManager assumes too much for instance variable '@guest_users'
  [1]:IrresponsibleModule: UserManager has no descriptive comment
  [2]:LongParameterList: UserManager#process_user_data has 8 parameters
  [2]:TooManyStatements: UserManager#process_user_data has approx 11 statements

Reek identified multiple code quality issues with specific line numbers and helpful descriptions. Each warning includes the smell type and actionable suggestions, such as moving methods to other classes or reducing parameter counts.

The analysis reveals issues like duplicate method calls, feature envy (methods accessing too much external data), missing documentation, and overly complex methods. These findings provide concrete starting points for refactoring efforts.

Understanding Reek's code smell detection

Reek categorizes code quality issues into distinct smell types, each representing a different aspect of design problems. Understanding these categories helps prioritize refactoring efforts and build better code structure habits.

Method-level smells

Method-level smells indicate problems with individual method design:

Long Parameter List: Methods with too many parameters suggest the method is doing too much or that related data should be grouped into objects.

Too Many Statements: Methods with many lines often violate the single responsibility principle and become difficult to test and understand.

Nested Iterators: Deep nesting creates complex control flow that's hard to follow and prone to bugs.

Create an example demonstrating method-level issues:

method_smells.rb
class ReportGenerator
  # Long Parameter List and Too Many Statements
  def generate_user_report(user_id, start_date, end_date, format, include_stats, include_graphs, email_recipient, department_filter)
    user = find_user(user_id)
    activities = fetch_activities(user_id, start_date, end_date)

    activities = activities.select { |a| a.department == department_filter } if department_filter

    report_data = {}
    report_data[:total_activities] = activities.count if include_stats
    report_data[:avg_duration] = calculate_average_duration(activities) if include_stats

    if include_graphs
      # Nested iteration complexity
      activities.each do |activity|
        activity.tasks.each do |task|
          task.subtasks.each { |subtask| process_subtask(subtask, report_data) }
        end
      end
    end

    formatted_report = format_report(report_data, format)
    send_report_email(formatted_report, email_recipient) if email_recipient
    save_and_log_report(formatted_report, user_id)

    return formatted_report
  end
end

Class-level smells

Class-level smells reveal problems with class design and responsibility distribution:

Feature Envy: Methods that use more data from other classes than from their own class suggest misplaced behavior.

Data Clump: Groups of variables that consistently appear together indicate missing abstractions.

Utility Function: Methods that don't use instance state might belong elsewhere or suggest a class with unclear purpose.

Duplication smells

Duplication smells identify repeated code patterns that should be extracted into reusable components:

Duplicate Method Call: The same method called repeatedly with identical parameters.

Repeated Conditional: The same conditional logic appearing in multiple places.

Analyze the method smells example:

 
bundle exec reek method_smells.rb
Output
Inspecting 1 file(s):
S

method_smells.rb -- 7 warnings:
  [13]:ControlParameter: ReportGenerator#generate_user_report is controlled by argument 'include_graphs'
  [10, 11]:ControlParameter: ReportGenerator#generate_user_report is controlled by argument 'include_stats'
  [1]:IrresponsibleModule: ReportGenerator has no descriptive comment
  [3]:LongParameterList: ReportGenerator#generate_user_report has 8 parameters
  [17]:NestedIterators: ReportGenerator#generate_user_report contains iterators nested 3 deep
  [3]:TooManyStatements: ReportGenerator#generate_user_report has approx 15 statements
  [7]:UncommunicativeVariableName: ReportGenerator#generate_user_report has the variable name 'a'

The analysis reveals several additional smell types beyond the basic ones we discussed:

Control Parameter: Methods that change behavior based on boolean or flag parameters, suggesting the method might be doing too much.

Uncommunicative Variable Name: Variables with unclear names like single letters that don't convey meaning.

Irresponsible Module: Classes or modules lacking documentation comments.

These findings demonstrate how Reek catches subtle design issues that might be missed during manual code review, providing specific guidance for improving code clarity and maintainability.

Configuring Reek for your project

Reek provides configuration options that let you customize detection rules for your project's specific requirements and coding standards. Configuration helps reduce noise from acceptable design decisions while maintaining focus on genuine quality issues.

Create a Reek configuration file:

.reek.yml
# Disable specific smells globally
detectors:
  TooManyStatements:
    max_statements: 20
  LongParameterList:
    max_params: 5
  FeatureEnvy:
    enabled: false
  UtilityFunction:
    enabled: false

# Configure per-directory rules  
directories:
  "lib/":
    TooManyStatements:
      max_statements: 15
  "spec/":
    TooManyStatements:
      max_statements: 30
    LongParameterList:
      max_params: 8

# Exclude specific files
exclude_paths:
  - db/migrate
  - vendor
  - tmp

This configuration demonstrates several customization approaches:

  • Adjusting thresholds for specific smells based on project needs
  • Disabling smells that don't align with your design philosophy
  • Setting different rules for different directories (stricter for lib, more relaxed for tests)
  • Excluding generated or third-party code from analysis

Per-file smell suppression

You can also suppress specific smells using inline comments:

configured_example.rb
class DataProcessor
  # :reek:LongParameterList
  def process_data(id, name, email, department, role, salary, start_date, manager)
    # Method intentionally accepts many parameters for batch processing
    create_user_record(id, name, email, department, role, salary, start_date, manager)
  end

  # :reek:TooManyStatements  
  def complex_calculation
    # This method performs a multi-step calculation that's clearer as one unit
    step_one = initial_processing
    step_two = intermediate_processing(step_one)
    step_three = advanced_processing(step_two)
    step_four = final_processing(step_three)

    validate_result(step_four)
    log_calculation_result(step_four)

    return step_four
  end
end

Test the configuration by running Reek with your updated settings:

 
bundle exec reek configured_example.rb
Output
Inspecting 1 file(s):
S

configured_example.rb -- 1 warning:
  [1]:IrresponsibleModule: DataProcessor has no descriptive comment

The inline suppressions eliminated the Long Parameter List and Too Many Statements warnings for methods where the design decisions are intentional and well-justified. The remaining warning about missing documentation can be addressed by adding a class comment or suppressed if documentation isn't required for this example.

Interpreting and acting on Reek reports

Understanding how to interpret Reek's output and prioritize refactoring efforts helps maximize the value of code quality analysis. Not all smells require immediate action, and some indicate architectural decisions rather than problems.

Output formats and analysis

Reek supports multiple output formats for different use cases:

Human-readable format (default):

 
bundle exec reek user_manager.rb

JSON format for programmatic processing:

 
bundle exec reek --format json user_manager.rb

HTML format for detailed reporting:

 
bundle exec reek --format html user_manager.rb > quality_report.html

The JSON format proves useful for integration with other tools or custom analysis scripts:

 
bundle exec reek --format json user_manager.rb
 
{
  "user_manager.rb": [
    {
      "context": "UserManager#process_user_data",
      "lines": [4],
      "message": "has too many parameters (8)",
      "smell_type": "LongParameterList",
      "source": "user_manager.rb"
    }
  ]
}

Final thoughts

Reek transforms subjective code quality discussions into objective analysis based on established design principles. Start with default configuration, then customize detection rules to match your project's specific needs.

Focus on high-impact smells that affect maintainability and readability. Use Reek's findings as starting points for design discussions rather than absolute requirements - some smells may be acceptable trade-offs for specific architectural needs.

Regular analysis builds awareness of code quality patterns and helps develop intuition for better design decisions. The tool works best as part of normal development workflows rather than occasional cleanup sessions.

Explore the Reek documentation for advanced configuration options and integration patterns.

Got an article suggestion? Let us know
Next article
How to Profile Ruby Code
Learn how to profile Ruby code with ruby-prof and stackprof to find bottlenecks, analyze performance, and optimize your applications effectively.
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.