Optimizing Ruby Path Methods
Posted by weaksauce 2 days ago
Comments
Comment by matltc 2 days ago
Versus active record, mvc, yaml configs, bundler, beautiful syntax, robust and trivially extendable stdlib, amazing native debugging and cli docs out of the box, everything out of the box if you're using Rails
I do not understand why it becomes increasingly irrelevant, especially in web development. I kinda get scripting--bash and python tend to run everywhere
Comment by gejose 1 day ago
Care to provide some examples of this? This hasn't been my experience, in general.
Comment by anand_dev 21 hours ago
Comment by wanderlust123 2 days ago
An absolute shame given how good the functionality is baked into RoR.
Comment by krowek 1 day ago
Comment by craigmcnamara 1 day ago
Comment by teaearlgraycold 2 days ago
God forbid you get forced to fix bugs before they reach production.
Comment by chalmovsky 2 days ago
Comment by teaearlgraycold 1 day ago
Comment by somewhatrandom9 2 days ago
Comment by chi_features 2 days ago
Wow! I'd love to hear more about how that's achieved
Comment by byroot 2 days ago
As mentioned in the post, the only thing really limiting CI parallelism is the ratio of "setup time" vs "test time". If your setup time is too long, you hit diminishing returns fast.
Comment by chi_features 16 hours ago
Comment by faangguyindia 2 days ago
Comment by kimos 1 day ago
More EC2 workers means more parallelism means tests map to more workers and the CI build finishes faster. It’s just CI perceived complete time.
Comment by DeathArrow 2 days ago
Maybe kids started using JS exclusively. But what happened to older developers? Did they move over?
Rails seemed to enable very fast prototyping and iteration. Isn't it still the case?
I see PHP usage going down, but PHP doesn't seem to have any advantages over JS, .NET, Python or Go. While Ruby coupled with Rails promised easy and rapid development.
Of course, Ruby might not be best suited for large code bases or microservices but probably 90% of the Internet are small to medium web sites.
Comment by bluerooibos 2 days ago
Ruby/Rails powers some of the largest platforms on the planet - Shopify, GitHub, GitLab. Both have had something of a resurgence lately, too, with Ruby 4 and Rails 8 shipping recently, and people rediscovering that Rails is excellent for vibe coding.
I've been a Ruby developer for 10+ years and have never struggled to find work, and the communities feel very active and growing - so I'm honestly not sure what you mean by "what happened to Ruby". If you don't actively follow or participate in the community, I can imagine you wouldn't hear much about it day to day.
I don't pay attention to the JS world these days - what happened to JavaScript?
Comment by swat535 2 days ago
Comment by pmontra 1 day ago
I'm working on a project with a Rails backend and a Vue frontend.
I've been working on a JS backend and frontend project in the early 2010s but I think that it was the only project with a JS backend. There are plenty of projects with server generated HTML. In my case the backends were Ruby, Python, Elixir, Java, PHP.
Comment by TiredOfLife 1 day ago
Comment by faangguyindia 2 days ago
People moved to efficient IO requiring smaller servers.
If you make Ruby on Rails in a typed compiled language and show people how fast it is. People will switch in an eyeblink.
Comment by vidarh 2 days ago
git doesn't care about mtime, but git maintains trees whose hash changes if any constituent part of the tree changes. It'd seem tempting to check for a .git and if present use the git tree to determine whether to invalidate the cache.
Comment by byroot 2 days ago
Comment by vidarh 2 days ago
Comment by _rwo 1 day ago
Comment by byroot 1 day ago
Alone it wouldn't have been very noticeable, but I did many small optimizations like that, which ultimately shaved about 20 seconds of setup time.
Looking from another angle, the app boot time on CI (not eager loading) was a bit more than 10 seconds, this saved over half a second, so a ~5% gain for an afternoon of work.
Comment by _rwo 1 day ago
Comment by nixpulvis 2 days ago
Comment by blinkbat 2 days ago
Comment by flats 2 days ago
Ruby is not without its drawbacks & drama, but it’s elegant in a way that few languages are to this day (how many JS programmers _actually_ grok prototype-based object-orientation?) & compared to NPM, RubyGems is (lately) unexciting in the best way.
Comment by vidarh 2 days ago
(Yes, I'm taking it a bit far; my prototype Ruby compiler is self-hosting finally, so I guess sometime in the next 20 years I'll end up booting into a Ruby kernel for no good reason...)
Comment by simonask 2 days ago
But like... something like a font renderer in Ruby? The thing that is incredibly cache sensitive and gets run millions of times per day on a single machine? The by far slowest step of rendering any non-monospaced UI?
The Earth is weeping my brother.
Comment by vidarh 2 days ago
https://github.com/vidarh/skrift
(Note that this is a port of the C-based renderer libschrift; the Ruby version is smaller, but much less so than "usual" when converting C code - libscrift itself is very compact)
Comment by andreynering 2 days ago
Comment by nixpulvis 2 days ago
Generally speaking Ruby has the best APIs.
Comment by t-writescode 2 days ago
ActiveAdmin is best in class, Rails is fantastic; but there’s a lot of insanity in the API for a language that “gets out of the way” and “just works”
Slice is my favorite example. (It’s been a bit since I’ve used it)
[0].slice(0, 100) == [0]
[].slice(0, 100) == …
exception? Or nil? Why does it equal []?For a “give me an array back that starts from a given, arbitrary index, and auto-handle truncation” not having that behavior continues to confuse me from an intuitive perspective. Yes, I understand the source of it, but why?
Comment by bradchris 2 days ago
So saying “give me the array containing the first 100 elements of this array with one element” would obviously give you the array with one element back.
Saying “give me the array containing the first 100 elements of this array with zero elements” would follow that it just gives the empty array back.
On top of that, because ruby is historically duck-typed, having something always return an array or an error makes sense, why return nil when there’s a logical explanation for defined behavior? Ditto for throwing an error.
Seems thoughtfully intuitive to me.
Comment by saghm 2 days ago
Comment by t-writescode 2 days ago
[].slice(5, 100)
^-- *THIS* either returns nil or throws an exception.Edit: Longer example:
puts "[1, 2, 3].slice(1, 100) -> #{[1, 2, 3].slice(1, 100).to_s}"
puts "[1, 2, 3].slice(3, 100) -> #{[1, 2, 3].slice(3, 100).to_s}"
puts "[1, 2, 3].slice(4, 100) -> #{[1, 2, 3].slice(4, 100).to_s}"
Yields: [1, 2, 3].slice(1, 100) -> [2, 3]
[1, 2, 3].slice(3, 100) -> []
[1, 2, 3].slice(4, 100) ->
So, there is a behavior difference between "array a little too short" and "array slightly more too short" that creates unexpected behavior.That's not a big surprise in a tiny example like this; but if you expand this out into a larger code base, where you're just being an array and you want the 100 through 110th values for whatever reason - say it's a csv. Suddenly you're having to consider both the nil case and the empty array case; but then why are they different?
Comment by saghm 1 day ago
Some additional things I discovered when trying to figure out why it might work like that:
* the behavior also seems consistent whether using `array.slice(a, b)` or `array[a..b]`
* `array[array.length]` and `array[array.length + 1]` both return nilComment by weaksauce 1 day ago
The easiest way to get around that if you are not carefully using the ranges would be to do `Array(array.slice(a, b))` as that will guarantee an array even if it's invalid. you could override slice if you really wanted to but that would be a performance penalty if you are doing it often.
Comment by t-writescode 1 day ago
Comment by saghm 1 day ago
Comment by weaksauce 1 day ago
``` If offset == self.size and size >= 0, returns a new empty array.
If size is negative, returns nil. ```
either way if you are doing stuff with arrays and not checking bounds you can throw an `Array(some_array.slice(x, x+100))` and it will always behave.
Comment by saghm 1 day ago
Comment by bradchris 2 days ago
[0, nil, nil, nil, …x100, nil] is the same as [0] in terms of access.
In both cases, trying to access the 100th element (e.g. [0][100]) will give nil.
Comment by weaksauce 2 days ago
[].slice(0, 100).each do |x| puts x end
that shouldn't be an error and it seems to be the principle of least surprise imo.
Comment by t-writescode 2 days ago
[].slice(5, 100)
^-- *THIS* either returns nil or throws an exception.( I made the other comment like this longer, please use that one for context )
Comment by digitaltrees 2 days ago
Comment by stackghost 2 days ago
For web stuff, with server-side rendering and partials it means minimal requirement to touch the hot mess that is JavaScript, and you can build PWAs that feel native pretty easily with Hotwire.
Ruby is slow as fuck though, so there's a tradeoff there.
Comment by matltc 2 days ago
Comment by Lio 2 days ago
For anything "slow" I can put it in Sidekiq and just run the worker code with TruffleRuby.
I have high hopes for ZJIT but I think TruffleRuby is the project that proves that Ruby the language doesn't have to be slow and the project is still getting better.
If ZJIT, JRuby or TruffleRuby can get within 5-10% of speed of Go without having to rewrite code I would be very happy. I don't think TruffleRuby is far off that now.
Comment by matltc 2 days ago
Comment by stackghost 2 days ago
Comment by digitaltrees 2 days ago
Comment by x3n0ph3n3 2 days ago
Comment by vidarh 2 days ago
Comment by akerl_ 2 days ago
Comment by claudiug 2 days ago
when I touch js, and python... I prefer ONLY AI agentic style of working.