Lessons learned from some of the best Ruby codebases
blacklane.github.io
blacklane.github.io
> This elegant trick of having a class inherit from Module allows us to use a class in a kind-of module context and to use a module in a kind-of class context.
This summarizes exactly why I hate Ruby: bizarre syntax tricks all over the place, and (not only junior) developers desperately trying to figure out how that instance variable over there teleported over here, because some gem developer wanted to be clever.
> Procto turns your ruby object into a method object. The code example from the README speaks for itself so I’ll just paste it here:
No it doesn't. What is even going on in there?!?
> This whole chunk of code looks a little more complex than it actually is:
Another thing that I often encounter in Ruby code, particularly in gems.
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? -Brian Kernighan https://en.wikiquote.org/wiki/Brian_Kernighan
I love Ruby. I hate Rubyistas that make code that's impossible for others to read or comprehend. I find the rails source actually pretty good here.
No it doesn't. What is even going on in there?!?
LOL didn't you read lines 385-472 of some_ruby_interpreter_file.c on MRI version 2.2.1p347?
...
When we're looking to write programming languages to make our ability to program more concise and powerful, clever tricks and hacks defeat the purpose. Those belong in the 90's and earlier.
There is nothing wrong with clever tricks (would you dismiss HAKMEM?), as long as they follow from simple principles that can be applied systematically. Alas, everything is ad-hoc in Ruby-land.
Python feels more restrictive (in that it doesn't encourage you to use fancy tricks - even though they are often available). But I feel I write clearer more maintainable code.
As an example of why clever tricks aren't always a bad thing, Haskell's lens library is essentially a big bag of tricks for manipulating compound data structures. However, lens differs from your typical dynamic metaprogramming library in significant ways:
(0) Its design actually follows from a few, simple and very general principles. So you don't need to memorize the entire lens API; instead, you can use the principles to discover the API. The only other thing that offers a similar degree of discoverability is IntelliSense, but IntelliSense for dynamic languages is typically not as good as it is for languages like Java and C# - especially when dynamic metaprogramming is used!
(1) You don't need to resort to arcane reflection hacks to figure out what's going on in lens code. Parametricity (free theorems) and type class laws (provided that you follow them, and this is usually very easy to check) tell you everything you need to know.
(2) Since lenses, traversals, prisms, etc. are ridiculously general, the time and effort you invest in learning them pay off over a wider range of projects.
Also, I see nothing wrong with the tone of the comment.
It's quite clear to me, but I've been programming Ruby for quite a long time. Conversely, I have the same reaction you're having when I look at a lot of "modern" javascript. So I'm not sure the problem is with Ruby as much as they way some programmers try to be clever, no matter the language.
Too much class level and module level munging morphs code into a sub language only readable by the author.
I am generally supportive of this, though, if it masks enough underlying complexity.
In this case it's just syntactic sugar.
In general, anything that makes the static structure of your program less discernible to whoever has to read it, can be considered technical debt. If you find yourself doing lots of dynamic metaprogramming, chances are you need to rethink your application's architecture.
I really think that we (rubyists) go for style points way too much. Side-effect of metaprogramming, and a younger-ish audience? Maybe.
I don't think this is an esoteric technique, any gripes about the specific examples chosen notwithstanding (probably chosen for their simplicity, not their utility). It's little different to inheriting from a template in C++.
The problem is of definition. My definition of clean is readable, clear and understandable. If it takes a significant portion of a blog post and the research before hand to understand what the hell is going on, I wouldn't call that clean as I define it.
Ideally, you want code that is understood quickly so that it can be maintained with the least effort. Seeing an object used as module violates my understanding of how modules were designed to be used and I would have to spend time figuring out how. It may be 2 minutes or 10 but regardless it's time that need not have been spent.
Cool magic can sometimes be helpful. Often its just cool.