ezekg
4 days ago
I feel like this is a solution to a problem nobody really has in practice, by simply following conventions, and I've been using Ruby for over 10 years. If byroot -- who works at Shopify on the largest Rails codebase in existence -- echos the same sentiment, then maybe it should be scrapped.
Umofomia
3 days ago
I will share a concrete example where I've recently run into this problem.
In order to make use of OpenStruct, `require 'ostruct'` first needs to be declared. Our code neglected to make that declaration, and we saw failures when it was deployed. This code, however, passed all of our tests. We discovered it was because our testing framework included rspec-expectations, which has a dependency on diff-lcs[1], and diff-lcs itself declares `require 'ostruct'`[2]. Because of this, ostruct was loaded globally before our code was tested, which silently masked the underlying issue.
This being said, I do understand the sentiment that this feature seems superfluous and may introduce unnecessary complication, especially from a Rubyist's point of view. The underlying mental model of Ruby dependency management is different from many other languages, and it's something to keep in mind when coming from other languages that do have scope for declared dependencies.
[1] https://github.com/rspec/rspec-expectations/blob/v3.13.3/rsp... [2] https://github.com/halostatue/diff-lcs/blob/v1.5.1/lib/diff/...
mjbamford
3 days ago
Very helpful example.
halostatue
3 days ago
`diff-lcs` no longer uses `ostruct` as of 1.6.0 (granted, that was released in February).
quesera
3 days ago
Does that mean you develop code without running it locally?
The first execution of new code is in CI?
viraptor
3 days ago
They didn't say where it was deployed. I'd often only test some changes in staging rather than locally, because they rely on some specific other service I don't want to spend time setting up. It's very common.
ljm
3 days ago
Locally you’d have all the dependencies installed. In production you’d leave out development and test dependencies.
lukeasrodgers
3 days ago
Typically with rails applications, test dependencies are not used for local development (i.e. running the rails server on your local machine), they are separate groups in the Gemfile.
ljm
2 days ago
Spring and bootsnap muddy the waters. You do not have hermetic dev and test environments in Rails.
user
3 days ago
user
3 days ago
user
3 days ago
graypegg
4 days ago
I really like Ruby, I do sort of wish it could focus on it's own identity a bit.
Some new features feel almost prescribed from other languages? Like, RBS and Namespaces specifically... they don't really fit the model of Ruby exactly, but they need to be there so Ruby can be presented as "having" type-safety and a-solution-for-monkey-patching. I'm all for taking inspiration from other places, but Ruby wasn't quite built around the same axioms that other programming languages started from.
princevegeta89
3 days ago
I used Ruby a lot a long time ago and built medium to large scale enterprise apps on the Rails framework before I moved on to other projects involving Golang and Elixir. Somehow I had more fun and more safety working with Elixir, which was only just getting started as a brand new language trying to establish itself.
It was only after working with Go that I realized how much compile-time safety and performance I was missing out on with Ruby.There's no doubt I would use Ruby today again, but I can't imagine going further beyond simple scripts and workflows. I have recently tried building a very small website with Rails, and I was somewhat surprised the framework did not mature all that much, and type safety and IDE support still seem to be iffy. There is so much unwanted magic that I still see with Ruby on Rails in general. I was looking up to Crystal to address some of the issues I described above, but unfortunately it just remained as a less mature language. Elixir was great, but with the experience I have had, I will actually drop heading into the functional programming world. That leaves me with only one choice, which is Golang. I am not a fan of everything it has, but it is fairly easy for my fellow engineers to pick up, and the IDE support has been nothing short of fantastic.
This is really really a big stretch, but I have always been hopeful towards looking for a TypeScript sort of compile-time layer for Ruby. It may probably never happen though, sadly.
jweir
3 days ago
Sorbet helps. We’ve even created a typed HTML template engine and it helps catch a lot but also allows using the Sorbet LSP to rename things and of course correct autocomplete.
brigandish
3 days ago
> I was looking up to Crystal to address some of the issues I described above, but unfortunately it just remained as a less mature language.
I'd be interested to hear what you find lacking in Crystal, too. For me it would be editor support, last time I tried the LSP I couldn't get it to work.
princevegeta89
3 days ago
Last time I checked I heard the compile times were still awful. And the entire community lacking some basic packages and enough developers that it still made it hard to find support or help for issues one may encounter.
brigandish
4 hours ago
Compile times seem fine to me, compared to other code I've compiled. I haven't noticed a particular basic package that's missing either, but that may depend on who is asked. I've also had reasonable responses from the existing devs, it feels more like Ruby in the late 2000's (friendlier, less political).
debugnik
3 days ago
> but with the experience I have had, I will actually drop heading into the functional programming world
Could you elaborate on this? It's a valid resolution, but I consider Elixir to be on the pragmatic side of the functional paradigm, so I'm wondering what pushed you away.
princevegeta89
3 days ago
Sure, this was a few years ago. Don't get me wrong, I liked it, but all the other existing and new engineers on my team have expressed a lot of concern about the entire paradigm shift and that Elixir was unnecessarily complicating things in terms of implementing simple logic. A lot of junior engineers also have been unhappy with the kind of shift going away from the traditional procedural/oop styles. If I was working on a solo project, I would pick Elixir over Rails any day. The LSP server and tooling alone makes it stand up very strong.
viraptor
3 days ago
Almost every recent (in years) Ruby feature is not a novel idea. Even the origin was a Perl/Smalltalk/Lisp crossover so the axioms were pretty well known.
rco8786
3 days ago
Yea generally agree with this take. Feels like we’re getting features shoehorned in.
andruby
4 days ago
I would like to second (or _third_) this opinion.
I've been working with Ruby for 20 years, and I've not needed something like this. This feels like adding a lot of complexity for little practical benefit. The trade-off feels off. I don't think this is worth the additional complexity.
usrbinenv
4 days ago
I disagree. I've also been working with Ruby for almost 20 years and quite a few times I came across a situation where I definitely wanted to wrap my library in a module for name-spacing and it was almost always cumbersome. I'd rather not wrap it and let others (or myself) use the library name-spaced under whatever name they choose. Right now, if you're working on a gem, you have to think really hard how to name it so its top-level classes an modules don't conflict with any other modules and classes found in the Ruby ecosystem.
ezekg
4 days ago
> Right now, if you're working on a gem, you have to think really hard how to name it so its top-level classes an modules don't conflict with any other modules and classes found in the Ruby ecosystem.
Follow gem naming conventions and this is a non-issue -- both FooBar::Record and BazQux::Record can coexist for foo_bar and baz_qux gems, respectively. If a gem is defining other top-level constants outside of their gem module, then that's considered against convention, i.e. bad practice, and the language should not be modified to allow such a thing.
I'd like to hear of a real use case for namespaces that existing conventions don't already solve.
usrbinenv
4 days ago
Wrapping `Record` in `Foobar` or `BazQux` is just not a good pattern, even if it's common place and is included in current guidelines. Most of the time, you don't have gems that would use the same class and thus would rather not type a long name-spaced name every time you want to use `Record`. But when you do have gems with conflicting classes, you'd have the power to wrap one of them or both in a short namespace identifier and be in charge of the naming. Using modules for wrapping is a pattern currently, but modules should primarily be used for mixins, not name-spacing.
vidarh
3 days ago
If you don't have a conflict, and the module is wrapping everything, nothing stops you from doing "include <yourmodule>".
Similarly, if you want to group modules that don't conflict together under a short module name, nothing stops you from doing:
module MyGroup
include Module1
include Module2
...
end
In other words, wrapping them doesn't remove your ability to use short non-namespaced names.Using `include` of specific functionality into a class that will use it is furthermore an idiomatic way of avoiding that extra typing without polluting the global namespace
For that matter, you can often achieve close to what you're arguing for as well without actually making any changes to Ruby:
def wrap_load(path) = class_eval(File.read(path), path)
module Test
# some_file.rb will act as-if defined within Test
wrap_load("./some_file.rb")
end
You can do better than that, to get closer to emulate `require` rather than `load`, and handle dependencies.Overall, I think the fact you can do these things suggests you could probably write a good enough plug-in `require` monkeypatch suitable for the rare cases where `include` from within a class or module without needing a language extension.
ezekg
4 days ago
What's the difference between FooBar::Record and ns1::Record? Nothing, except the latter pushes encapsulation onto the user.
This is not the Ruby ethos.
ljm
3 days ago
Realistically it would be FooBar::Record and ns1::FooBar::Record too, unless gems start replacing their top level module FooBar with FooBar = Namespace.new.
And why would you bother doing that when it would be a breaking change?
usrbinenv
4 days ago
On a purely syntactic level snake_case gives me a clear indication this is something different (not a module). But the underlying mechanics of how namespaces would work, as I've mentioned in another comment, is that the choice of picking namespace identifiers is shifted to users of gems/libraries. I think the proposal might further benefit from maybe giving libraries default namespaces and, for example, Go does exactly this: you can import a package with the namespace prefix defined by package author, but you can also change it or import it without a namespace prefix at all.
fellowniusmonk
4 days ago
I think byroot got it exactly right with:
>First, I'm not convinced by the motivations:
>
>Avoiding name conflicts between libraries: Applications can require two different libraries safely which use the same module name.
>
>Is this a problem that happens on a regular basis? I believe Ruby has a pretty well established convention for libraries to expose a single module with a name that correspond to their gem name.
I really don't think we want to make it easier for newbies to alter gem naming conventions and run multiple versions of a gem within the same project, this sounds like a genuine nightmare to me. I've found from jumping in to fix broken and crippled rails projects for startups that the fuckup surface area is already high enough.
werdnapk
3 days ago
I've been working with Ruby full time for pretty much 20+ years as well and there's many parts of it I've never used, although when I need one of it's many features, I love that it's there. I just used a refinement for example last month for the first time to help clean up some code that I didn't want polluting top level classes everywhere.
drogus
4 days ago
While I agree with the sentiment here, ie. that Ruby doesn't necessarily need namespaces, I think it's also not necessarily good to base Ruby usage on what Shopify is doing. They have so many expert Ruby devs, and whole teams that write extra tooling, that I'd argue they shouldn't be compared to pretty much most of the usage of Ruby/Rails out there
byroot
4 days ago
Shopify would benefit a ton from "some" namespaces. In a way, packwerk[0] was an attempt at bringing some namespaces benefits.
But I don't personally think Shopify would benefit from this specific implementation of namespaces (a couple colleagues do). I'm personally not even sure Namespace is a proper term to describe that feature. It's more some sort of lightweight sandboxing to me.
Also:
> They have so many expert Ruby devs
If anything, the average Ruby expertise at Shopify is likely noticeably lower than in most Ruby/Rails shop.
poorman
3 days ago
Try using the Pay gem and others that assume a global singleton for a multi-tenant app (as in multiple different websites under different domains with different Stripe API keys). Lots of gems assume this and their configuration is global.
I personally would love to have this feature!
ezekg
3 days ago
Can you expound a bit more? It seems like Pay encapsulates itself pretty well. I'm not sure I really grok how namespaces could improve or fix whatever is broken here.
chao-
4 days ago
I shared my quick take in another comment tree, but I reread and understand the semantics a little better now, and I like it less, especially the notion that an instance of an object might transform when crossing Namespace boundaries. I get that it is similar to refinements in some ways, but this feels like it would be even more surprising, and I can foresee some gnarly bugs coming from this unless it is trivially easy to visualize the changes to an object between namespaces.
I'm updating my opinion from "mixed feelings" to "against" on this.
tobyhinloopen
3 days ago
That's because you are aware of the limitations. Ruby is really powerful and allows you to manipulate existing modules, but you shouldn't do that because it will leak everywhere.
This namespaces feature allows you to manipulate existing globals, but keep it isolated in your own namespace. That seems pretty good to me :) Because it remains isolated, you can also use these features more aggressively.
hosh
4 days ago
I thought being able to do this with Nodejs was a near capability.
Over the past two years, I have come to understand that this contributes to the nightmare that is the Nodejs ecosystem (and the browser JS exosystem in general), at least when it comes to writing reliable software.
thunky
3 days ago
> I've been using Ruby for over 10 years
Maybe after a decade or two I wouldn't care, but as someone who has only used Ruby casually I would steer clear of it for anything serious, largely due to the lack of namespaces.
90s_dev
3 days ago
Why am I not surprised Shopify uses Rails.
hartator
4 days ago
Yeah, and I rather them focusing on performance instead of features. 2.7.8 is still the fastest and it’s getting old.
tiffanyh
4 days ago
You can see Ruby core perf improvements at the link below, going back 4-years.
Even though this is from the YJIT folks, they include the non-jit improvements as a comparison.
chao-
4 days ago
Having upgraded one large and two small applications in the last few years, this is not my experience. Even without YJIT, just upgrading to Ruby 3.2 and beyond saw performance improvements over the same application on 2.7.
dalyons
4 days ago
Huh? How is 2.7 the fastest ? There have been tons and tons of major performance gains since then, even without getting into yjit