Avoid unnecessary indirection
Spreading things across multiple functions, modules, and files is to be avoided when it detracts from clarity. Massive files and functions are to be avoided, but LLMs often overcorrect, and in the process make the logic impossible to follow.
Avoid unnecessary helper functions
Common signs that a helper function is unneeded:
- It’s very short (1-3 lines)
- It’s only used in one place
- It replicates an existing helper function or merely wraps it
- It does not break out a meaningful unit of work (it should probably have some kind of control flow)
For a rails controller, there’s often an easy heuristic for this: Is it a call to a model method?
If so, good. If not, either inline the logic if it’s simple or turn it into a model method if not.
It’s quite rare to see examples of good helper methods outside of the default set_* or *_params methods.
Example to be avoided:
# BAD!
class PostsController < ApplicationController
before_action :set_post
def show
return render_pending_error if @post.pending?
render json: serialize_post(@post)
end
private
def set_post
@post = Post.find(params[:id])
end
def serialize_post(post)
{
id: post.id,
title: post.title,
body: post.body
}
end
def render_pending_error
render json: { }, status: :not_found
end
end
Example to be followed:
# Good
class PostsController < ApplicationController
before_action :set_post
def show
return render json: {}, status: :not_found if @post.pending?
render json: @post.as_json(only: %i[id title body])
end
private
def set_post
# only acceptable as a helper because it's re-used across other actions!
@post = Post.find(params[:id])
end
end
Avoid useless service objects
Service objects often hide the actual logic.
# BAD!
class CreatePostService
def initialize(user, params)
@user = user
@params = params
end
def call
post = @user.posts.new(@params)
post.slug = @params[:title].parameterize
post.save!
post
end
end
class PostsController < ApplicationController
def create
@post = CreatePostService.new(current_user, post_params).call
redirect_to @post
end
end
# Good
class PostsController < ApplicationController
def create
@post = current_user.posts.new(post_params)
@post.slug = post_params[:title].parameterize
@post.save!
redirect_to @post
end
end