# 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:
1. It's very short (1-3 lines)
2. It's only used in one place
3. It replicates an existing helper function or merely wraps it
4. 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:

```ruby
# 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:

```ruby
# 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.

```ruby
# 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
```

```ruby
# 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
```