5 ms·
Prove Productivity scientifically.
by exabrial 4y ago
Prove Productivity scientifically.
- DoctorOW 4y agoWhy?
- exabrial 4y agoBecause it underpins the argument above. If Ruby is "so productive", that's a quantifiable measurement, no?
- bin_bash 4y agoWe gonna double-blind developers or something? I know Go and Ruby very well. I know what it takes to write in one vs the other. Ruby is faster to write and more concise by a long shot—certainly if we're talking back-end web services. I prefer Go to Ruby generally but it's weird that Go developers tend not to even see how much yak shaving is involved with it. Or really any downside with it. Try writing this in Go: records = User.limit(10) records.select { |user| user.is_admin? }.map{|user| "#{user.id} : #{user.name}"}
- howeyc 4y agoI may be wrong, but aren't you doing two loops by doing it that way? One for the select, and another for the map? Or does ruby compile out the select loop with smarts. In Go, the intuitive way would be one loop with an if inside it. So it would be easy to spot this performance issue if you did it the ruby way with two loops. https://go.dev/play/p/ixDKuosxPNp https://go.dev/play/p/ixDKuosxPNp I bet I wrote my for loop as quickly as you wrote your map. The character count isn't that much higher.
- kaba0 4y agoNot sure about Ruby, but Java’s streams would do one loop only here, as they are lazy. Also, both solutions are O(n), so unless this is the hot loop of your program, or it iterates over some insane amount of entities, it is a completely meaningless microoptimization.
- bin_bash 4y agoThe amount of times in my career where the performance would be even measurable between these 2 styles is vanishingly few. If I cared I could just use #filter_map or a classic for-each loop. If we're assuming the project is written in Ruby in the first place, clearly we're not valuing performance that highly. The more important thing is the ruby version is chainable and more readable—and that matters far more often.
- gkop 4y agoYou had me until > more readable Without having more context, User in your code is possibly an ActiveRecord class, so to read the #select, you have to consider that it could be radically different and heavier than Enumerable#select (eg. it may execute a DB query as a side effect). So I like your example still, because it’s representative, and certainly expressive, but not readable per se. IMO this sin here is simply that ActiveRecord shouldn’t have overloaded select.
- bin_bash 4y agoThat’s more of an argument against ORMs which I realize my example used. I was mostly trying to convey using map/filter against POROs though. Using an ORM was a poor choice on my part. I agree the magic there does harm readability since it makes it a lot harder to understand what it really is doing.
- Lio 4y agoRuby has had lazy iteration[1] for quite a while but as n here is only 10 there's really not much to loose in not using it. In fact given that only a subset of users will be admin users for the second loop n is going to < 10 anyway. I believe it was Rob Pike that actually said something along the lines of not bothering to optimise until you know that n is large[2]. 1. https://ruby-doc.org/core-2.5.0/Enumerator/Lazy.html https://ruby-doc.org/core-2.5.0/Enumerator/Lazy.html 2. https://users.ece.utexas.edu/~adnan/pike.html https://users.ece.utexas.edu/~adnan/pike.html
- pjmlp 4y agoThanks to generics, assuming there is some stream/sequence like type records := Stream.Limit(User, 10) records.Select(func(user User) bool {return user.IsAdmin()}).Map{func(user User) string { return fmt.Sprintf("%d %s", user.id, user.name) } Yes a bit more verbose, that is the price to pay for static typing without full type inference as in the ML language family.
- bin_bash 4y agoIt blows my mind why Go didn’t have generics at launch. I suppose they just didn’t want people to be able to have abstractions like this at all?
- pjmlp 4y ago> In retrospect, we were biased too much by experience with C++ without concepts and Java generics. We would have been well-served to spend more time with CLU and C++ concepts earlier. https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf...
- bin_bash 4y agooh wow thanks for this. I haven't been actively using Go since around the time this was written so I've missed it
- AzzieElbab 4y agoStream.limit and Stream.select(…).limit are not the same thing :) records.collect({case u if u.isAdmin => s”${u.id} ${u.name}”}).take(10) guess the language
- pjmlp 4y agoWell you can argue semantics, it doesn't change the fact that it is possible to implement the same concepts in Go with generics. That line of code could be Scala, or something else. In any case, the point is that there are compiled languages that offer similar productivity like Ruby, with AOT/JIT compilers out of the box, and great IDE experiences.