# Reek: Ruby Code Smell Detection Made Simple

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:

```command
ruby --version
```

```text
[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:

```ruby
[label 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:

```command
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:

```command
bundle init
```

Add Reek to your project's Gemfile:

```ruby
[label Gemfile]
source 'https://rubygems.org'

[highlight]
gem 'reek', '~> 6.5'
[/highlight]
```

Install the dependencies:

```command
bundle install
```

```text
[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:

```ruby
[label 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:

```command
bundle exec reek user_manager.rb
```

```text
[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:

```ruby
[label 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:

```command
bundle exec reek method_smells.rb
```

```text
[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:

```yaml
[label .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:

```ruby
[label 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:

```command
bundle exec reek configured_example.rb
```

```text
[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):

```command
bundle exec reek user_manager.rb
```

JSON format for programmatic processing:

```command
bundle exec reek --format json user_manager.rb
```

HTML format for detailed reporting:

```command
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:

```command
bundle exec reek --format json user_manager.rb
```

```json
{
  "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](https://github.com/troessner/reek) for advanced configuration options and integration patterns.