5 ms·
One of the perks of Rails is that Ruby itself makes it more compelling. When you need to get to something that the framework doesn’t expose, Ruby makes it easy
by brightball 2y ago
One of the perks of Rails is that Ruby itself makes it more compelling.
When you need to get to something that the framework doesn’t expose, Ruby makes it easy to get to it without having to rewrite the framework, extend a class and replace it in multiple places or fork it just to use your modification.
This applies to the entire gem ecosystem too.
Over the years this ability has saved me numerous headaches with only a few lines of code. IMO it’s the real super power of Ruby.
- it_citizen 2y agoI agree. But with great powers comes great responsabilities.
- Gigachad 2y agoRuby is my least favorite part of Rails by far. The lack of type checking makes every single gem and rails update extremely dangerous in ways that are incredibly difficult to predict. For example the redis gem updated to return an int from exists() instead of a bool like it did before. This doesn’t raise any exceptions because all ints work in if statements. They just always return true. Silently breaking all of the code using it. You can read all of the change logs and search your own code base, but will constantly run in to situations where another gems code is using the method that just changed. As well as the fact that almost every method has one param “options” where the available options are never listed in the documentation and are impossible to find without reading the source code. Rails itself I quite like for being an all inclusive framework that just works out of the box, but untyped languages should be avoided at all costs these days when we have much better options like typescript.
- lazylester 2y ago"...but will constantly run in to situations where another gems code is using the method that just changed". I've worked with Rails for 20 years and haven't seen this. Have I just been really lucky? I'm sure your test suite showed the warnings about the Redis `exists()` change for many versions prior to its actually being changed, right?
- Gigachad 2y agoI’ve worked on rails apps for a while now and on previous jobs it wasn’t so bad, but those were smaller apps. At the current company, almost every update manages to slip something through CI that blows up on production. Even with 30,000 rspec tests and tons of cypress tests. The CI is set up to raise exceptions on warnings, but I think it only applies to warnings raised by rails. I guess rails works alright at the start, but eventually your app gets so big that it becomes a nightmare to verify updates before they roll out.
- jack_riminton 2y ago30,000+ tests and it can't detect breaking changes?
- Gigachad 2y agoIn this case no because the broken code was in another gem (sidekiq) using the redis gem. Our CI does not run the unit tests for every library we import. Only our own.
- jack_riminton 2y agoDo you not have tests for your Jobs?
- Gigachad 2y agoYes, we do. In this case the issue was very much inside some internal logic of sidekiq around managing the jobs, not any of our own code.
- mdji 2y agoHave you checked out sorbet?
- oleg_antonyan 2y agoMy escape from this: https://github.com/olegantonyan/typerb https://github.com/olegantonyan/typerb
- tvink 2y agoIt's wild how all the huge successful applications written in it manage to stay alive eh
- potamic 2y agoAnyone maintaining software in the public domain needs to understand Torvald's first rule of kernel development. YOU DO NOT BREAK USERSPACE! Seriously, how hard is it to understand? The collective impact across thousands of users will always be greater than any overhead in versioning. It's equivalent to willingly shipping a bug, and you would never do that, would you? Arguments about keeping the interface simple are weak because it only helps potential new users at the expense of existing users. As users, we need to encourage such norms by not adopting or advocating for software that has a history of breaking changes. Some communities are better at this than others, and the difference in developer experience is very evident for those of us who have seen both.
- Gigachad 2y agoThe argument for changing it was that the redis gem was meant to mirror functionality of the redis api method with the same name. What really blows my mind though is that they did it as a minor patch release. Combined with Ruby having no type checking and allowing nonsensical stuff like if statements that always return true.
- fabianholzer 2y agoWell, that is still no reason to introduce a breaking change in the existing interface. You introduce a new one, using a different signature and mark the old one as deprecated, and keep it around until as long as reasonably possible.
- exe34 2y ago> Anyone maintaining software in the public domain needs to understand Torvald's first rule of kernel development. YOU DO NOT BREAK USERSPACE! That's why they offer refunds!
- TeMPOraL 2y agoIndeed. Let's not forget the greatest invention in history of software development, unparalleled in how it improved productivity of software developers: THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- freedomben 2y agoI appreciate the example because I've heard people complain about this but have yet seen a good example of it in practice. I think you make a good point, and were I maintaining redis gem I wouldn't have approved a contract break like that. Even in a typed language, changing the return type of an existing function is IMHO not something you do, especially once you hit v1.0. But you make a good point that a compiler in a typed language would have at least notified you at build time of the breakage. Personally I'm willing to give that up for the benefits, but I can understand why someone wouldn't.
- speleding 2y agoI agree that it's very bad they broke the exists() behaviour in a point release by changing the return value from a boolean to an integer. But I think strong typing is not the answer. It's a drag on productivity and I can think of several other ways they could have broken the user space API that would not have been picked up by strong typing. You really need good test coverage, and ruby/rails makes that easy. If you have great test coverage then strong types are superflous, if strong types help you then your tests are not good enough.
- RUnconcerned 2y agoI totally disagree. I think not having static types is a drag on productivity and maintainability. I have to work with both Kotlin and Ruby codebases, and the Ruby ones are always a nightmare whenever you need to make a change deep within the application's core, even though the Ruby one has more extensive tests. The idea that test coverage is a replacement for static types is nonsensical. I won't insult your intelligence and say that by great test coverage you meant testing the shape of your inputs, because only an idiot would say that would serve as a replacement for something that is done automatically by a compiler, but sometimes minor naming mistakes (like `job` instead of `jobId` when you're passing an ID and not an instance of `Job`) will make it past code review and will place a totally unnecessary mental burden on the next programmer who has to look at the code and figure out what exactly he's looking at. With static types there is no need for that, it's right there in the code.
- speleding 2y agoGood tests do indeed not test the detailed shape of inputs and outputs, they test the system end to end. And they should be cheap to run, so you run them after every change. As soon as someone mistypes jobId the test will break and you will know where to look. If that would slip through then your tests simply aren't good enough. And because tests do not test the detailed shape of inputs and output it becomes easier to try out a quick refactor of your code later, without having to change a zillion signatures just to experiment a little. Agility matters.
- 2y ago
- cies 2y ago> The lack of type checking makes every single gem and rails update extremely dangerous in ways that are incredibly difficult to predict. This. I found a typed-Ruby in Kotlin (OO-core with lots of FP niceties; code even looks similar to Ruby in many cases as type inference it quite good). Kotlin + http4k (analog to Rack+Sinatra) + JTE's KTE (or kotlinx.html) + SqlDelight (or jOOQ; fuck ORMs anyway: also ActiveRecord) is a dream to work with. I'm not sold on TypeScript. Yes it helps but it allows for very messy code.
- brightball 2y agoThe type checking argument comes up in every language discussion and IMO it’s not worth it. Some people love static typing and swear by it as you clearly do here. Others do not find static typing helpful and manage to do well in environments without it. Your critique here isn’t even a critique of Ruby in these use cases, it’s a critique of any dynamically typed language. The Ruby functionality I mentioned could easily bail you out in this situation by allowing you to monkey patch the redis gem to restore the old functionality until you were ready to get around to fixing it in your codebase or until you determined that the other dependent gems had been updated. If anything, this is a great example of exactly my point about the flexibility of Ruby.