6 ms·
I think the point about expressiveness is exactly what makes ruby so divisive: It is great when you are deep within the ecosystem or do exactly what the ecosyst
by bakuninsbart 3y ago
I think the point about expressiveness is exactly what makes ruby so divisive: It is great when you are deep within the ecosystem or do exactly what the ecosystem expects you to want to do, and an absolute pain if you want to do anything non-standard.
The supports_feature-method is probably defined somewhere 5 abstractions deep. If you are lucky that is, it might also be part of some library's weird meta-programming of supports-* that no LSP can point you towards. I've never worked in an ecosystem that celebrates implicitness as much as ruby does, and it is driving me nuts.
The fact that finished code looks great and reads well doesn't balance the scales in my book.
- pqdbr 3y agoIn my experience this is almost never the case. #supports_feature? would be defined right there where you'd expect - in that Subscription model. Even tough you can reach for metaprogramming (like define_method or method_missing), that's really not how the entire ecosystem of guides and tutorials will point you. Anyways, when in doubt, just plug a debugger and call "@subscription.method(:supports_feature?).source_location`, and generally that's all it takes.
- mplewis 3y agoRails is the biggest Ruby project and it’s heavily based on metaprogramming. Even Rubymine has trouble finding the canonical definition of a named method sometimes – it has to guess. I love Ruby but I totally understand this criticism.
- sodapopcan 3y agoRails is a library, though, the advice applies to application/business code. Metaprogramming is extremely useful for making really simple-to-use libraries. If your business logic is full of metaprogramming, that's more of a problem, especially in this day of age where it's common for developers are only sticking around at any given job for 2 to 3 years.
- Fire-Dragon-DoL 3y agoThe most common framework in ruby disagrees. It wiuld be 5 layers deep
- rezonant 3y agoWell, it would probably be 2-3 layers deep in a concern, really. Concerns are just fancy modules, and modules are just reusable parts of a class. In Rails basically everything is a concern. To a concerning degree actually, as a professional Rails developer of many years, I think they went way overboard with it. My team and I also curse it's single minded design when we have to drill down there. Thankfully that's a pretty rare thing to have to do. As for the abstraction, Rails does take it pretty far, but you also have to take into account that it's a framework that supports numerous pluggable strategies and disparate backends, and extensibility. I think most mature frameworks are pretty complex-- the goal of the framework is that it's all encapsulated away from you for the vast majority of tasks, and in Rails, that is extremely true.
- Doctor_Fegg 3y ago> The supports_feature-method is probably defined somewhere 5 abstractions deep This is the classic mistake of confusing Ruby with Rails. That might be true of Rails. It absolutely isn't true of vanilla Ruby. The article was not "I love Rails".
- madeofpalk 3y agoDoes Rails not use Ruby?
- lstamour 3y agoIt does, but at this point it’s like saying that JavaScript is DOM even though you can use it outside a web browser. Or it’s like blaming Python for TensorFlow. Like, yes, Rails is a use case for Ruby, and a popular one, but not the only one.
- lloeki 3y agoAgreed. Ruby is not Rails in so many ways, even on philosophical grounds. Rails is full of magic, implicitness, and conventions, which enables a great deal of very speedy development but also becomes† a minefield if you steer away from The Way; while plain Ruby is very explicit and in plain sight, there's no magic. It's a blank page, an open field, it's raw material for creative ground. Rack or Minitest for example are very Ruby. RSpec on the other hand is full of Railsy magic, just yesterday testing some threaded stuff I was bit by `let` because it has concurrency consequences, and the magic becomes darkness as you have to look behind the curtain and beat it into submission in roundabout ways that obscure the thing you're actually doing. † or sometimes is a minefield, all by itself, like this nonsense: https://github.com/rails/rails/blob/1512cf2ba578282c898b8eb68ac401ea5243b7b5/actionpack/lib/action_controller/metal/live.rb#L261-L263 https://github.com/rails/rails/blob/1512cf2ba578282c898b8eb6...
- rezonant 3y ago> also becomes† a minefield if you steer away from The Way Reminds me of Angular vs React-- In my opinion it's much easier to get immediately productive in React, but it's very easy to produce a rats nest over time if you aren't experienced with the framework. Versus Angular which has a lot of upfront learning curve, but it's prescribed structure makes it fairly easy to scale out the app over time. Rails is definitely more like React in this respect. It turns out you can absolutely color outside the lines and still enjoy the speediness, but it's not something that I experienced devs should try to do without making a huge mess.
- pdntspa 3y agoIt's a pretty simple heuristic to track down the source of metaprogrammed functions... just check for method_missing() or define_function() or a handful of other keywords. I believe the regular syntax is just shorthand for these features anyway. edit- as another comment points out, you can just do `@subscription.method(:supports_feature?).source_location` too
- rezonant 3y agoAnother strategy is just to step into the method call in pry/byebug. I've done that for particularly tricky cases. At that point it's pretty easy to walk it up to the mechanism that does the metaprogramming.
- notjoemama 3y ago> The fact that finished code looks great and reads well doesn't balance the scales in my book. IMO this is because software engineers both get bored and feel a need to compete. The more abstract they can make code the better (more safe?) they feel. That lets them play chess on their terms and eliminate the competition. But that's just my take, I may be wrong. Fortunately the most commonly used gems wrap this abstraction into usable APIs, and most have good documentation. While this can be correctly attributed to ruby or the devs in its ecosystem, I've been on teams with staff using other languages and stacks that let their completion/anxiety fly making it hard to read and understand their code. I guess my point is it's a good critique, but it falls beyond the meta programming in ruby.
- rezonant 3y ago> The supports_feature-method is probably defined somewhere 5 abstractions deep. Yes, but pro tip: you can do object.method(:supports_feature).source_location to inspect where it comes from. It may be a module included into the class, the class itself or one of its super classes, or a concept built on modules like ActiveSupport "concerns". But source_location works in almost all cases. > might also be part of some library's weird meta-programming of supports-* that no LSP can point you towards Yes, if this comes from method_missing, you can't check it's source_location. You need to use your knowledge that the method name works and that method_missing is how such things are done, and then you do object.method(:method_missing).source_location and read the logic there. The lack of safe and reliable IDE introspection and design-time type support are my number one issue with Ruby, and why I tend to use typed languages instead. However, there are workflows for inspecting a codebase that work, they just don't fit in well to the usual LSP+IDE pattern. You are expected to use irb/rails console to do your inspection of the structure and behavior of your programs.
- vidarh 3y agoTo me this is why I don't like IDEs. My Ruby projects often have a wrapper that reloads code and puts me in a pry prompt. I can edit code and introspect objects live as the code changes. It's a natural extension of Ruby's Smalltalk legacy. I recently replaced my X window manager with one I've written in Ruby, and I can just attach to it and modify state or change code live to test or fix things. Being confined to JS and Java in VS Code for work is like having one arm tied behind my back.
- geospeck 3y ago> My Ruby projects often have a wrapper that reloads code and puts me in pry prompt. I can edit code and introspect objects live as the code changes. That sounds very interesting! Can you please share the wrapper that does all that magic? Thanks!
- vidarh 3y agoPry provides most of the value, so my script is usually basically just something like this: def reload load "app.rb" # If you want to load multiple files, remember that if app.rb # uses require/require relative, the files will only be loaded # once; you can change that but really it's not usually what # you want for production; in that case either look into a proper # reloader, or you'll want to load the rest of the files here. # Sometimes it's fine to e.g. do a Dir.glob("*.rb").each {load _1}. load "dev.rb" # Put "dev niceties" in this file. E.g. maybe load table_print or # awesome_print, Hirb, or whichever nice formatting tools you # want, or define any custom introspection methods that are # helpful. Eg. for an analytics project I worked on had a few tools to # wrangle CSV test data there. (I really ought to extract the best # from my various projects into a gist or something, but these # files often accumulate really project-specific stuff. end require 'pry' reload binding.pry # Throws you in the Pry prompt at the top level scope. It does require that you're somewhat careful not to make the loading of your files too stateful, which is a good practice anyway, and you do need to be mindful that things will occasionally fall apart if you reload the running code as it will modify the classes of objects that already exists but not e.g. update their instance variables, so if you add a method that expects @foo to have been initialized, but existing objects do not have it initialized, things will go obviously go badly. Since pry supports "edit some_method_name" and will spawn $EDITOR you can even do edits in the same terminal that way, but I tend to prefer to have my editor open in another window. (And since so many here seems to struggle to find methods, in addition to "edit", "show-method some_method" in the right context in pry is also highly useful) Sometimes I'll keep ways to trigger pry in applications during regular runtime because it's so useful for debugging issues, and sometimes even fixing issues in a running process. EDIT: While I prefer pry, it's worth noting that Irb has gotten a lot better (lots of features from pry) in recent versions, and also "rdbg" (debug gem) is awesome if you don't want to use a separate script like this - you can equally well run your code under rdbg and just have a script handy to load tools you want for a debug session; the downside of rdbg is if e.g. attaching remotely you'll be running in a trap context, which means you don't have quite the same freedom with respect to what code you can actually run - that may or may not matter.
- deleted 3y ago[deleted]
- znpy 3y agoWeird that nobody is mentioning how poorly ruby is documented on its main site. There is no proper tutorial, only links to external resources of varying accuracy and levels of update-ness. It really doesn’t help with grasping such a customisable runtime.