6 ms·
The often impossibility of finding the definition of the methods I'm calling is the main thing that soured me on Rails. I think a more explicit style is more co
by sanderjd 5y ago
The often impossibility of finding the definition of the methods I'm calling is the main thing that soured me on Rails. I think a more explicit style is more common nowadays, which is a good thing.
- grncdr 5y agoMaybe you already know it, but I find `something.method(:mystery_method).source_location` points me to the right place more often than not. I only mention it because I have noticed a lot of people work productively in Ruby without leveraging it's dynamic/reflective features[0], but little idioms like the above are absolute lifesavers for me. [0]: A big disadvantage of the above is it's not statically resolvable, so you couldn't really build an IDE go-to-definition with it.
- Lio 5y agoThe two tools I'd recommend for navigating ruby code in addition to #source_location are Solargraph[1] and, my favourite, good 'ol exuberant ctags[2]. Solargraph is an amazing project but ctags is still just so fast and low overhead that it's what I mostly use. ctag support is available for most editors and is built into Vim. You need to first generate a tag file (or have an editor plugin do it for you[3]) and then press Ctrl-] to go to definition. 1. https://solargraph.org/ https://solargraph.org/ 2. http://ctags.sourceforge.net/ http://ctags.sourceforge.net/ 3. https://github.com/tpope/gem-ctags https://github.com/tpope/gem-ctags
- nitrogen 5y agoAnd don't forget the option of just calling into pry at the line in question and typing ls and show-doc. Also ripgrep is incredibly useful for navigating new codebases.
- sanderjd 5y agoYes, grep + debugger / pry were how I solved this when I was still writing lots of Ruby. I find it much more productive to be able to get these answers statically, but I was too strong when I said "impossible"; there's always some way to find the right code, or the VM wouldn't be able to run it :)
- Lio 5y agoYes, you’re quite right! Thank you again, I must remember to use pry more. With ruby 3.1 I think we’re getting a new default debug.rb gem. It will be interesting to see if pry or the beat ideas from pry can be integrated with that.
- devoutsalsa 5y ago“git grep” is pretty amazing for tracking things down.
- rhizome31 5y agoOf course that's what we end up doing in practice, using external tools (CLI or IDE) to work around a limitation in expressiveness of the language. This advice is a testimony that there's indeed a problem upfront :) And it comes short when searching from commonly used names...
- nitrogen 5y agoThis advice is a testimony that there's indeed a problem upfront Indeed, and the problem is that IDEs have encouraged developers to write convoluted code and to forget how to navigate a filesystem. Reading code and commit history is a much faster path to understanding a system than an IDE's autocomplete. I learned this from Ruby, and it serves me well in C, Kotlin, Scala, PL/SQL, Typescript, etc.
- maccard 5y ago> IDEs have encouraged developers to write convoluted code and to forget how to navigate a filesystem. I would argue the exact opposite. Developers who force tools designed 30 years ago to dictate programming language best practices today are holding back the entire industry. There is no reason for my tooling to depend on my filesystem; imagine if my IDE integrated directly with vcs, and a language server provided both of those tools semantic information about my code, available on any device. Let's not kid ourselves either, utf-8 isn't human readable on disk, it's still a binary-like format.
- rhizome31 5y agoYou're right to remind that the filesystem is a metaphor, a model and not the reality of what's going on on the computer. The thing is it's still the common denominator between different IDEs and text editors. IDEs cannot be used in every situation so any professional developer who uses an IDE also knows his way around with a text editor. If we were to come up with a better abstraction than the file system, it would have to be shared between different IDEs for interoperability. My understanding is that Smalltalk was such an attempt but somehow that aspect of it didn't really spread. Are you aware of current progress being made in this area?
- inopinatus 5y agoIt isn't a good thing. My first advice to all newbie Ruby programmers is to stop thinking about methods and start thinking about messages.
- saagarjha 5y agoI don’t see how this helps?
- inopinatus 5y agoRuby's dispatch is Smalltalk-like, not Java-like; it is (very) late-bound. The consequences for interface design are dramatic, the natural style being one in which objects notify each other, rather than telling each other what to do, and the result is loose coupling and ease of composition. People trying to write Java-like OO in Ruby end up confused and frustrated.
- chespinoza 5y agoThere's plenty of people writing java-like code in Python too, just check Amazon SDK for python or GCP SDK, it's a mess, I don't know if they get frustrated but they do get SDK users confused and frustrated.
- saagarjha 5y agoOk, but Objective-C also does messages and most of them are defined statically and can be easily searched for in a codebase. I’m not saying Ruby needs header files to send messages to something, but being able to figure out where the code for something is isn’t off the table for languages with dynamic dispatch and it can come in handy.
- inopinatus 5y agoFor that, there's object.method(:name).source object.method(:name).source_location but frankly this is still thinking in a rigid mindset that suits other languages better. Ruby isn't just "dynamic dispatch"; a typical metaprogramming technique handles all incoming calls without named methods, or by dynamically writing the code. To put it bluntly, assuming there's a method on the other side of your message, is practically the antithesis of Ruby. It's similar to the category error that leads folks to conflating type with class, and writing type checkers that look for class signatures.
- Raphael 5y agoWould a Ruby IDE be able to figure it out?
- t-writescode 5y agoIn my experience on a IntelliJ with Ruby extensions (so working like RubyMine), no. Input and output parameters on a program with hundreds of thousands of lines becomes .. rough, to say the least. DryStruct has helped a lot; but several teams working on a single codebase with their own opinions of method calling patterns evolved over several generations all in a single codebase, and it’s … rough.
- sanderjd 5y agoRubyMine was impressive (because it's a hard problem) but still hit or miss when I was writing Ruby about 5 years ago. It may very well have improved a lot since then!
- chenmike 5y agoThis magic is delightful in small codebases I’m familiar with and absolute hell in large codebases I’m not familiar with
- sanderjd 5y agoWell put. Totally my view of it.
- rhizome31 5y agoI've worked with Ruby in the past and I currently work with Python and Elixir. This is a caveat that Elixir inherited from Ruby. In Elixir there's the `only` option of `import`, but it doesn't seem idiomatic to use it. In Python there's `import *` but it's an actively discouraged practice whereas in Ruby and Elixir it's the norm. I like all three but on this particular point I think Python got it right.
- sodapopcan 5y agoI _much_ prefer Elixir’s way of not using imports much and prefixing most function calls with the module name. That way when I jump to a function definition, I often don’t need to do any further jumping around—I know exactly where everything is coming from right there. I especially hate when language idioms encourage using a shorthand name for the module when importing. Just be explicit!
- MrWiffles 5y ago> [...] I especially hate when language idioms encourage using a shorthand name for the module when importing. Just be explicit! THIS. 100%! I also think Python seems to do this better with the namespace pattern of `import x.y.z`. Never seen the `import *` pattern before, didn't know Python can do that (never done Python really though either, only browsed some code here or there). But one addition to your statement I'd like to add: not just idioms, but documentation can spread this antipattern too. Noobs come to a language, read the documentation for some tool, library, etc., and understandably come away thinking "Oh ok, this is how it's done" when in reality, while they're not doing anything wrong per se, they're being taught a bad habit right off the bat. And that makes the inevitable hard slap across the face that reality (or a co-worker) eventually hits you with all the more shocking, possibly even leading to resentment of others when this happens. I myself had this problem many years ago; "why the hell do you need all these subclasses and so many layers of abstraction?!" I once asked. "Because those class/method names already exist within other classes loaded at runtime, or will likely be added in future external dependencies, and we don't want to accidentally overwrite those." Well, I thought that was a stupid idea. In my (very limited at the time) experience, when I had that problem, I just insisted on finding a damn good descriptive name that wasn't going to be used for anything else, even if it was wicked long or a pain to type. Too long? Don't be lazy. Typos more probable with length? Learn to copy/paste. That was the approach I learned at some point from some documentation somewhere on the internet, and it always worked for me, so it was the "one true path" and all others were inferior, making proponents or users/adherents of any other way "wrong" and inferior to me and my superior, non-lazy intellect. You're telling me that you do it differently? You must be stupid or lazy, and I'm neither therefore I'm better than you; thus forcing me to adopt your inferior standard?! Preposterous! Insulting! Offensive! That's how I saw it. God, was I dumbass. I developed this attitude by learning my skills in a near total vacuum, other than documentation written by people on the internet back in the 90's. Not official company-published technical docs, mind you, but forum and BBS posts, mailing list discussions, and way too much IRC to be considered "healthy" by any stretch of the imagination. Those who taught me did so in a way that was efficient and they did no wrong at all of course - this failure was entirely of my own making, from my own arrogance. But it's also true that had I been taught at the same time that "there are other ways in other languages that are totally valid; this is just for simplicity's sake" and then been shown, or better yet required to use other patterns in school/projects/etc., I might have been able to see the short-sightedness of my own arrogance sooner. Instead, it resulted in an antipattern that allowed me to become overconfident, arrogant, and more difficult to work with than I should've been. ---------- In case you're wondering, I can't remember what I read or where that came from so long ago. Sorry. Might have been C, C++, Java, DOS BASIC (non-GUI/non-Windows), Visual Basic (before .NET) or maybe even PHP 3.something, no idea - that was 20+ years ago. I was inexperienced, arrogant, and a fool; none of that was the author's fault whatsoever. We're all young and stupid at some point in life. I'm no longer young, but at least now I know I'm stupid! :-)
- MrWiffles 5y agoYeah that's been a major pain in my ass more than once, totally get where you're coming from there. One tip for you, and anyone else who might be reading this from the future (hi! do we have flying cars yet? what about time machines? can you bring me one of each, in like, 10 minutes?): RubyMine, the IDE from JetBrains (commercial, Java-based desktop app but not nearly as bad/sluggish as you might expect, though not native fluidity) has a feature to show you where a given method ultimately comes from, going all the way up the chain of source code and abstractions to where it's really defined, including within Rails or other libraries/gems/imported files in a given project. It's a really killer feature for this particular pain point, in my opinion. Short of that, assuming all your dependencies are unpacked under your project's directory (likely .gitignore'd but there nonetheless, instead of in somewhere like /opt/ or /usr/local/lib or something) you could also `grep -ir 'def method_name' | less` or something to try to figure that out, though it's nowhere near as smooth as RubyMine. Other editors have Ruby and/or Rails plugins that may help ease this pain point as well, though personally I haven't done anything with that on the editor front in a very, very long time. Generally I'm outright militant about keeping my dependencies to an absolute minimum in a project, and doing everything the most "vanilla" (standard, accepted, most widely adopted patterns, naming conventions, etc.) way possible, and therefore I usually know what gem/lib is providing what particular method, so I don't really need that kind of utility most of the time because I can google up some API docs...when there are API docs anyway. But in cases where you're having a legacy project/monolith dropped in your lap and nobody knows anything because "the business guy" fired the one developer who actually knew how everything worked and now that guy won't answer his calls because working for free is dumb? Yeah, in those cases, RubyMine or a real good editor plugin can be a lifesaver for this.
- sanderjd 5y agoIf that RubyMine feature works well these days then that's great! In my day it was nice but hit or miss.
- t0mbstone 5y agoYou need to be using RubyMine. Simply command-click on ANYTHING to jump to the definition, even if it's nested deep in a gem that your project uses. RubyMine, and the "jump to definition" feature in particular, is the primary thing that enabled me to really "get" Ruby and finally understand how everything worked together.