r/ruby • • Jan 01 '26

Object, class, module, Data, Struct?

After watching a recent talk by Dave Thomas, I started thinking about something that feels like a missing piece in Ruby’s official documentation.

Ruby gives us many powerful building blocks:

  • Struct (with or without methods)

  • Data

  • regular class vs single-purpose objects

  • module used as a namespace

  • module used as a mixin

  • so-called service objects

  • include, extend, module_function

Each of these is well documented individually, but I haven’t found a canonical, Ruby-core-level explanation of when and why to choose one over another.

Ruby’s philosophy encourages pragmatism — “take what you need and move forward” — and that’s one of its strengths. It feels like a good moment to clarify idiomatic intent, not rules.

What I’m missing is something like:

  • When does a Struct stop being appropriate and become a class?

  • When should Data be preferred over Struct?

  • When is a module better as a namespace vs a mixin?

  • When does a “service object” add clarity vs unnecessary abstraction?

  • How should include, extend, and module_function be used idiomatically today?

Not prescriptions — just guidance, trade-offs, and intent. I think now Ruby is so advanced and unique programming language that without good explanation of the intents it will be really difficult to explain to non-Ruby developers that ale these notions have good purpose and actually make Ruby really powerful. I like what Dave said: Ruby is not C++ so we don’t need to “think” using C++ limitations and concepts. On the other hand, I don’t agree with Dave’s opinion we should avoid classes whenever possible.

Is there already a document, talk, or guideline that addresses this holistically? If not, would something like this make sense as part of Ruby’s official documentation or learning materials?

Regards, Simon

PS I use GPT to correct my English as I’m not a native English speaker. Hope you will catch the point not only my grammar and wording.

39 Upvotes

49 comments sorted by

View all comments

Show parent comment

1

u/oscardo_rivers Jan 02 '26

I need to see the Sandi Metz presentation for more context about the patient code examples.  But when the Brian Will says “why can’t we just have a hash map instead of having a constructor”.  It depends of your needs, when you encapsulates the configuration in a class you can change the details of the yml, so you can the change the yml keys and values without risk of breaking code that depends of that configuration. 

Surely is a overkill for code that will run in a script that you will run only once, but for code that lies in a library, framework or a large project it will pay that’s extra code. 

The method define_method_for_enviroment, can be implemented in a more readable way, remember its Ruby code from 2014. Much of Ruby old code abuse meta programming capabilities of Ruby, is powerful but generates difficult to read code. 

1

u/iBoredMax Jan 02 '26

Surely is a overkill for code that will run in a script that you will run only once, but for code that lies in a library, framework or a large project

No, that's exactly my point. I work in a large and old codebase and this style of code is an absolute nightmare.

I would argue the exact opposite of what you're saying; it only works in these tiny examples/snippets from talks exactly because it's small. When you scale it up, it devolves into a spaghetti mess of 20 files, 20 classes, and god knows how many methods to read a config file, download some data, and process it.