Struggling to organize code in Rails

Published Nov 10, 2020

Okay internet, here’s something I’ve been struggling with in Rails: how do I organize code that doesn’t fit into one of the framework concepts? In particular, I’m trying to write some code that works with data from about 5 models, is not involved in HTTP requests, will be used by an asynchronous background job, and is reusable outside the context of that job.

I’ve heard of service objects / service classes, but there’s no real “service” that this behavior is a part of. It doesn’t make sense to put it on any one of the models because it’s more business code than data code. I really dislike working with code that makes me do ThingDoer.new.update_stuff(arg). Maybe it’s aesthetics, but I also don’t like creating a whole new object that performs a single function and has no state.

Do I create a new module with a single function and call it as ThingUtils.update_stuff(arg)? Does it make testing weird when a module does database things?

Should I shoehorn a service definition and call it as ThingService.new.update_stuff? That feels like over-engineering if .new doesn’t take any arguments.

In procedural or functional programming, I’d define a top-level function in a module that gets imported as the name service. So I’d be able to do service.update_stuff(arg). Is the idea that Ruby trades out import service for service = Service.new?

Is there some pattern here that I don’t have enough object-oriented programming experience to see? This is making me think that I’m missing some really obvious basic software design principle.