Table of Contents
- Why Coding Standards Matter
- Style Guides: The Foundation
- Naming Conventions
- Indentation & Whitespace
- Syntax Best Practices
- Error Handling
- Code Organization
- Comments & Documentation
- Testing Standards
- Enforcing Standards with Tooling
- Conclusion
- References
Why Coding Standards Matter
Before diving into specifics, let’s clarify why coding standards are non-negotiable:
- Consistency: A team with shared standards writes code that looks like it was written by one person, even if 10 people contributed. This reduces friction when debugging or refactoring.
- Readability: Standards like clear naming and indentation make code easier to parse at a glance. You shouldn’t have to decode variable names or hunt for logic in a messy block.
- Maintainability: Clean code is easier to update, extend, and fix. Standards prevent “code rot” by discouraging shortcuts that lead to technical debt.
- Collaboration: New team members can jump into a project faster if they don’t have to learn idiosyncratic style choices.
Style Guides: The Foundation
Ruby has no single “official” style guide, but the Ruby Style Guide (maintained by Bozhidar Batsov and the Ruby community) is the de facto standard. It’s widely adopted and enforced by tools like RuboCop. You can find it here: Ruby Style Guide.
Other notable guides include:
- GitHub Ruby Style Guide: Tailored for GitHub’s internal projects (focused on simplicity).
- Airbnb Ruby Style Guide: Airbnb’s stricter take on Ruby (great for large teams).
For most projects, starting with the community Ruby Style Guide and adjusting for team preferences is a safe bet.
Naming Conventions
Names are the “vocabulary” of your code—they should be descriptive, consistent, and follow Ruby’s cultural norms. Here’s how to name things in Ruby:
Variables & Methods: snake_case
- Use lowercase letters with underscores to separate words.
- Variables: Name should reflect the data they hold (e.g.,
user_count, notuc). - Methods: Use verbs for actions (e.g.,
calculate_total,format_name); avoid vague names likeprocess_data.
Bad:
userName = "Alice" # camelCase (not Ruby-like)
def processData(data) # camelCase method, vague name
# ...
end
Good:
user_name = "Alice" # snake_case
def format_user_name(name) # snake_case, descriptive verb
name.split.map(&:capitalize).join(" ")
end
Classes & Modules: CamelCase
- Start with an uppercase letter, no underscores. Use nouns (since classes/modules represent entities).
Bad:
class user_profile # lowercase start
# ...
end
module data_processor # lowercase start
# ...
end
Good:
class UserProfile # CamelCase, noun
# ...
end
module DataProcessor # CamelCase, noun
# ...
end
Constants: UPPER_SNAKE_CASE
- Use uppercase letters with underscores. Constants are for values that don’t change (e.g., configuration, magic numbers).
Bad:
max_users = 100 # snake_case (not a constant)
Good:
MAX_USERS = 100 # UPPER_SNAKE_CASE
API_BASE_URL = "https://api.example.com"
Booleans: predicate? Methods
- Methods that return
true/falseshould end with?(e.g.,active?,valid?).
Bad:
def is_active(user) # "is_" is redundant; no ?
user.status == "active"
end
Good:
def active?(user) # predicate method with ?
user.status == "active"
end
Indentation & Whitespace
Whitespace is invisible but critical for readability. Ruby has strong opinions here:
Indentation: 2 Spaces, No Tabs
- Use 2 spaces per indent level (not tabs). This is non-negotiable in Ruby culture.
- Nested code (conditionals, loops, blocks) should be indented.
Bad:
def greet(user)
if user.admin?
puts "Hello, admin!" # 4-space indent (too much)
else
puts "Hello, user!"
end
end
Good:
def greet(user)
if user.admin?
puts "Hello, admin!" # 2-space indent
else
puts "Hello, user!"
end
end
Line Length: ~80-100 Characters
- Keep lines under 80-100 characters (varies by team). Long lines force horizontal scrolling, which hurts readability.
- Wrap lines by breaking at logical points (e.g., after commas, operators).
Bad:
def send_welcome_email(user)
UserMailer.with(user: user).welcome_email.deliver_now # Too long!
end
Good:
def send_welcome_email(user)
UserMailer
.with(user: user)
.welcome_email
.deliver_now # Wrapped for readability
end
Trailing Whitespace: Banished!
- No spaces at the end of lines (editors like VS Code can auto-trim this).
Syntax Best Practices
Ruby’s syntax is flexible, but consistency is key. Here are the rules to follow:
Parentheses: Omit When Possible (But Be Consistent)
- Omit parentheses for method calls with no arguments or simple arguments (e.g.,
puts "hello"). - Include parentheses when:
- The method call is nested (e.g.,
format_name(user.first_name, user.last_name)). - It improves clarity (e.g.,
calculate_total(price, tax: 0.08)).
- The method call is nested (e.g.,
Bad:
puts("Hello") # Unnecessary parentheses
result = add(1, multiply(2, 3)) # Parentheses help here, but inconsistent
Good:
puts "Hello" # No parentheses (cleaner)
result = add(1, multiply(2, 3)) # Parentheses for nested calls (clearer)
Semicolons: Avoid for Line Separation
- Use newlines, not semicolons, to separate statements. Semicolons are only acceptable for short, related one-liners (rarely).
Bad:
name = "Alice"; age = 30; # Semicolons (unRuby-like)
Good:
name = "Alice"
age = 30 # Newlines (cleaner)
def Keyword: No Extra Spaces
- Use
def method_name(no space betweendefand the method name). - For methods with arguments:
def greet(user)(no space afterdefor before().
Bad:
def greet(user) # Extra space after def
# ...
end
def calculate_total (price, tax) # Extra space before (
# ...
end
Good:
def greet(user) # Clean spacing
# ...
end
def calculate_total(price, tax) # No space before (
# ...
end
Error Handling
Ruby’s exception handling is powerful, but misusing it leads to silent failures. Follow these rules:
Rescue Specific Exceptions (Never Bare rescue)
- Always rescue a specific exception class (e.g.,
StandardError,ArgumentError), not a barerescue(which rescuesException, including critical errors likeSystemExit).
Bad:
begin
risky_operation
rescue # Bare rescue (catches *all* exceptions—dangerous!)
puts "Something went wrong"
end
Good:
begin
risky_operation
rescue StandardError => e # Rescue specific exception
puts "Error: #{e.message}" # Log the error message
end
Raise Meaningful Exceptions
- When raising errors, include a descriptive message so developers know why it failed.
Bad:
raise # No message (useless for debugging)
Good:
raise ArgumentError, "User ID must be a positive integer" # Clear message
Code Organization
Ruby code should be “self-documenting”—its structure should reveal intent. Here’s how to organize it:
Methods: Single Responsibility Principle (SRP)
- A method should do one thing and do it well. Aim for methods under 10-15 lines. If a method is longer, split it into smaller methods.
Bad:
def process_order(order)
# 1. Validate order
return unless order.valid?
# 2. Calculate total
total = order.items.sum(&:price) * (1 + order.tax_rate)
# 3. Charge customer
payment = Stripe::Charge.create(amount: total, customer: order.user.stripe_id)
# 4. Send confirmation email
OrderMailer.confirmation(order).deliver_now
end
Good (split into single-responsibility methods):
def process_order(order)
return unless valid_order?(order)
total = calculate_order_total(order)
charge_customer(order, total)
send_confirmation_email(order)
end
private
def valid_order?(order)
order.valid?
end
def calculate_order_total(order)
order.items.sum(&:price) * (1 + order.tax_rate)
end
def charge_customer(order, total)
Stripe::Charge.create(amount: total, customer: order.user.stripe_id)
end
def send_confirmation_email(order)
OrderMailer.confirmation(order).deliver_now
end
Classes: Single Responsibility Principle (SRP)
- A class should have one reason to change. If a class handles both “user authentication” and “email sending,” split it into
UserAuthenticatorandEmailSender.
Comments & Documentation
Comments should explain why, not what. Ruby code is readable enough that the “what” is often obvious.
Avoid Redundant Comments
- Don’t comment on code that’s self-explanatory (e.g.,
x += 1 # Increment x).
Bad:
# Increment the user count by 1
user_count += 1
Good:
user_count += 1 # No comment needed (obvious)
Use Comments for “Why” or Complex Logic
- Comment to explain why a decision was made (e.g., business rules, workarounds for bugs).
Good:
# Use .to_f here because Stripe requires amounts in cents (e.g., $10.00 → 1000 cents)
amount_in_cents = (total * 100).to_f
Document with YARD
For public APIs (e.g., gems, libraries), use YARD to document methods, parameters, and return values. YARD is Ruby’s standard documentation tool.
Example:
# Formats a user's full name.
# @param first_name [String] The user's first name (e.g., "Alice").
# @param last_name [String] The user's last name (e.g., "Smith").
# @return [String] The formatted full name (e.g., "Alice Smith").
def format_name(first_name, last_name)
"#{first_name} #{last_name}"
end
Testing Standards
Tests are code too—they deserve the same care as production code. Follow these rules for Ruby tests (using RSpec as an example):
Descriptive Test Names
- Test names should read like sentences (e.g.,
it "returns true when user is an admin").
Bad:
it "works" # Vague
Good:
it "returns true when user has admin role" # Descriptive
Group Tests with describe and context
- Use
describefor classes/methods,contextfor scenarios (e.g.,context "when user is logged in").
Example:
describe User do
describe "#admin?" do
context "when user has admin role" do
it "returns true" do
user = User.new(role: "admin")
expect(user.admin?).to be true
end
end
context "when user has regular role" do
it "returns false" do
user = User.new(role: "user")
expect(user.admin?).to be false
end
end
end
end
Enforcing Standards with Tooling
Manually checking standards is error-prone. Use these tools to automate enforcement:
RuboCop
The gold standard for Ruby linting. RuboCop enforces the Ruby Style Guide and can auto-correct many issues.
Setup:
- Add to
Gemfile:gem "rubocop", require: false - Run:
bundle install - Generate config:
rubocop --auto-gen-config(creates.rubocop.ymlfor custom rules). - Run checks:
rubocop - Auto-correct:
rubocop -a(fixes most formatting issues).
Editor Plugins
- VS Code: Install the “Ruby” and “RuboCop” extensions to see linting errors in real time.
- Sublime Text: Use “SublimeLinter-rubocop”.
CI/CD Integration
Add RuboCop to your CI pipeline (e.g., GitHub Actions, GitLab CI) to block PRs with style violations. Example GitHub Actions config:
name: Lint
on: [pull_request]
jobs:
rubocop:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- run: bundle exec rubocop
Conclusion
Ruby coding standards aren’t about being pedantic—they’re about writing code that’s a joy to read, write, and maintain. By following naming conventions, formatting rules, and organizational principles, you’ll reduce bugs, speed up collaboration, and make your codebase resilient to change.
Start small: adopt the community Ruby Style Guide, install RuboCop, and iterate with your team. Over time, these habits will become second nature, and you’ll wonder how you ever wrote code without them.
References
- Ruby Style Guide (Community standard)
- RuboCop Documentation (Linting tool)
- YARD Documentation (Ruby documentation tool)
- Practical Object-Oriented Design in Ruby (Book by Sandi Metz—essential for code organization)
- GitHub Ruby Style Guide
- Airbnb Ruby Style Guide