I'm currently working on a Ruby project, and I love the language so much! It's elegant, fast enough for me, and the ecosystem rocks.
It seems that, after Ruby borrowed from many previous languages, a lot of rubyisms went into Rust (the nice functional-style enumerations, the awesome package manager inspired by Bundler). And I'm thrilled the best of the Ruby world found its way into other languages.
A future where the elegance of the Ruby language is available both as an interpreted-scriptable tool (Ruby) or a compiled-statically-typed language (Rust) looks like a nice place to me.
Wouldn't Crystal fit the bill for a fast compiled language explicitly designed to emulate Ruby's syntax?
(I don't have any significant Ruby or Crystal experience, so if there are reasons why that doesn't fit the bill, I'm sorry)
So I do have a lot of Ruby experience, and I have used Crystal, and I've found that Crystal being Ruby-ish in syntax doesn't help with the fact that it isn't Ruby and doesn't work like Ruby. Nor does Rust, of course, though I do appreciate how Rust has liberally taken after Ruby in a lot of other ways. But I find Crystal mostly frustrating in many ways related to how it looks and presents itself. It wants to look like Ruby and it wants to court Ruby developers--by not being Ruby, but also not providing enough reason to use it over other languages.
There are tons of uses for non-Ruby languages. These days I'm primarily in TypeScript and Kotlin, even though I really, really like Ruby; as-is it doesn't scale, from the perspective of somebody who likes manageable code, as well as I'd like it to. But when I want a non-Ruby language, I am not tied to Ruby syntax (and I kind of think that Ruby's syntax works almost exclusively for Ruby? I think a lot of the expressivity of the Ruby language loses something when you don't have its dynamic approach to the world) in a way that makes Crystal, with its lack of libraries or maturity, not an appealing choice of tooling.
(I also feel similarly about Elixir, though in Elixir's case there are also some interesting things around BEAM that I might like to leverage. And I think that a typed Elixir would get my attention right quick.)
> And I think that a typed Elixir would get my attention right quick.
Elixir _is_ statically typed, it just uses strong type inference so you rarely have to explicitly type things out.
A key difference between Crystal and Elixir is that Crystal tries to replicate ruby syntax in a more performant language, whereas Elixir tries to apply the sensibilities of Ruby and the Ruby community to the Erlang VM.
I was using "typed" as shorthand for "statically typed", but Elixir is not statically typed. Typespecs aren't static typing and IMO they get messy when you want to do more than specify primitives.
Dialyzer is indeed a pain in the ass, but what is not a pain in the ass is vscode's elixir_ls plugin which incrementally dialyzes and gently nudges you into making static type declarations (your code shows up uglier when you don't do it).
Life changing. It's stopped me from pushing runtime errors probably about 20 times now, in the last few weeks that i've been using it. At this point I'd say that it's strong enough to close 95% of the difference between static and dynamic typing.
Elixir's (maybe going to be merged into the standard library) property checking semantics (ExUnitProperty and StreamData) are quite amazing and super easy[0], and will catch whole classes of things that your compiler won't so I would strongly suggest checking out Elixir now.
[0] today I implemented in an hour a property check that makes me confident that a mathematical algorithm that I implemented for a fuzzer is ok (my first attempt was wrong), and then a property check that demonstrated that that algorithm applied to a stateful set of events doesn't violate critical invariants.
Also, you will almost certainly never get a statically typed Elixir, because it makes a lot of things like hot updates hard or inelegant. Sending interprocess/internode messages is something could be extremely intolerant to a static type system, because, in a way you're breaching the purity of the functional paradigm (it's the BEAM language's "one big lie"). Go struggles with this a lot in its channel semantic, and it's why there is a ton of boilerplate in gRPC (and almost no boiler plate in erlang RPC).
Also gently breaching the type system is incredibly useful in mock tests - for example, in my current project I do about 60 high-load end-to-end tests in parallel with clones of my central scheduling algorithm - this is possible because my test suite reaches into the main body, dynamically creates a new scheduler, and appends that information into an HTTP request, which is passed into a "plain old map" and intercepted only in test environment. This not only greatly accelerates the end-to-end tests (I run the full suite as a matter of course before each commit) but it also gives me confidence that my system will run under a load that is greater than I can manually trigger.
I use typespecs in both Elm and with Dialyzer in Elixir and I haven't found either to be cumbersome, even when using complex data types.
I used to do a lot of programming in C# and Java, but I didn't miss static typing at all when I moved over to Ruby and Python. I'm sure others have differing opinions, but the absolutely last thing I worry about when selecting a language is whether or not it is statically typed.
I've only given Crystal a cursory look in the past and I think I'd enjoy working with it but can't speak to whether I'd feel as comfortable and productive as with Ruby (maybe I would). But what I do know is that you would not have the vast amount of Ruby gems available to your project, so if you feel the need for those as I often do then you might find it a bit more slow-going.
For me, Elixir fits the bill as a Ruby replacement better than Crystal does. Elixir is more mature and its community and tools are similar to Ruby, making the upgrade path easier, I think. At least that was the case for me after trying both. I also have come to love the functional aspect of Elixir over Crystal's (and Ruby's) focus on OOP.
I think we've arrived at that future. With languages like Crystal, Rust, Groovy, and Elixir, you can get some of the same powers that Ruby bestows upon you in other environments like a statically compiled binary, the JVM, or the Erlang runtime (with it's lovely OTP framework). I even see JavaScript taking on some Ruby-like characteristics these days.
Those languages each target one of those platforms only, i.e. Crystal and Rust for a statically compiled binary, Apache Groovy for the JVM, and Elixir for the Erlang runtime.
Why not use a language that targets many platforms? E.g. Kotlin targets the JVM, Android, and Javascript, as well as is natively compiled. Now that's the real future. Better than using, say Groovy, to target the JVM, then rewriting it all when you want it to run on Android.
Agreed. I feel that ES6 is very ruby-like with the functional programming parts. I'm also very happy about Groovy, Elixir, and other languages that are Ruby-inspired.
I do not agree that it "has completely different semantics". It has far more in common than not. Its close enough that I, as a long time Ruby developer, had no issues being productive with it in a very short amount of time. The syntax and API are similar enough that most Rubyists are going to be very happy and comfortable. Then when they see the benchmarks they will be even happier!
It also has different semantics for bad reasons. For example, Ruby’s if ... then ... else (single-line) has been deliberately removed because the devs have a mild preference against it. For someone like me who’s been writing that since BASIC in 1981 or so, that’s a surprisingly big PITA.
I like Crystal, but there are a few too many needless gotchas for it to be comfortable.
No. And it varies wildly - some Ruby files may run with just a couple characters (or even none) being different, and other may require a total rewrite.
Ruby is the very least favorite of all the programming languages I've had to use regularly over my career.
Its syntax strongly favors cuteness over familiarity. Wherever Ruby can diverge from expectations to give you a pointless little tickle of whimsical inventiveness instead, it seems to do so.
Visually it looks like an unwanted love child of Pascal and Python. There's no clear rhyme or reason to the use of sigils and keywords.
The standard library and built-in types are acceptable for a mediocre '90s scripting language, I guess. The difference between symbols and strings as hashmap keys is a footgun that opens up endless bugs for the type of glue code that you'd often be writing in Ruby.
Probably the only thing that keeps Ruby afloat is Rails, an extremely resource-intensive web server framework built around assumptions of what web apps were like in 2003. Everything in Rails seems to happen by pooping magic keywords in your code or in file names according to mysterious conventions, so when something goes wrong, you'll have a hell of a time figuring out why Rails isn't calling your code or is generating broken SQL. OTOH it honors the Ruby tradition of doing lots of unexpected and useless cute things like pluralizing words in your database migrations [1].
So, I'm old, and have done lots of stuff in lots of languages in frameworks. For about a dozen years, Rails was my go-to toolkit. I've written a couple dozen production applications with it. Unfortunately, Rails has really fallen out of favor lately. Even a Rails-specialty shop I worked for briefly has pivoted to using ASP.NET. I've played around in that stack, and found it lacking. (EF just doesn't compete as an ORM.) However, they've moved on to bigger corporate customers, and those places just don't use Rails.
Recently, and because of this same we-don't-"do"-Rails sentiment, I was forced into using Java for a web application. So I prototyped a site with Spring and Angular 6, thinking this -- arguably -- represents the "state of the art" when doing a Java web app. Out of frustration, I also cranked up a prototype with Rails. What was taking me literally 160 lines of Java and JS, to build two related models and a form to edit the relationship, took me 3 lines with Rails. Nothing else I've found allows me to be as productive as Rails for writing web applications.
I can understand criticizing Ruby for being clever. There are still magic tricks you can do with it I've never even tried to understand. I can understand criticizing Rails for being obscure. I realize that it took me MANY years to be REALLY effective with it. But if you're telling me the alternative for web applications is ANYTHING related to Java, I'll call you crazy.
I've just inherited a Laravel-based PHP site, which is so old I can't download the version of the framework it uses. Yikes. I did PHP for about 10 years, 20 years ago. It doesn't feel like a lot has changed.
So, I'm honestly asking, as someone who hates Rails: What framework, out there, somewhere, allows me to be as productive as Rails, but which is are "better," somehow?
I have heard a number of things like chess and go and poker described as easy to learn but impossible to master.
Rails is not like this. Rails is more like bridge where you have to learn the rules as well as this whole bidding system that fills a book before you can actually play the game.
There is no real magic in Rails, and once you learn the tricks yourself it becomes the most pleasant and productive ecosystem to work with that I've experienced. If you don't bother to learn though, it's going to be awful and slow and opaque.
By the way some of the good ideas in Ruby and Rails have made their way to PHP7 and recent versions of Laravel. So much has changed if your last PHP exposure was 12 years ago, it's not bad now.
For most parts of Rails, I agree. There is one very important one where I don't: ActiveRecord's internal behaviors are opaque enough at most levels where you care about your database to be fairly called "magic". Having to reverse-engineer ActiveRecord to make my database stop puking and to generate a make developers who know Rails but not databases not get upset that now the solution is insufficiently "Rails-y" (whether or not it is correct and whether or not it is faster than the "Rails-y" method that's causing them problems) is not great.
Fair enough, I would say that the internals of ActiveRecord/Arel/etc can be complicated but also do a lot of work. I watched a number of presentations by tenderlove and had a bit of background/interest in that area to start with. "Go watch this guy's videos about relational algebra and SQL generation" is probably not what you want to hear when there's a bug though.
By the time you've gotten there though you've certainly more than figured out how method_missing and different filename based conventions work though, you've seen what Rails is and I'd be curious to find out what you like better!
Honestly, these days? Writing my own SQL and using languages with static typing. I'll take a little longer to write code to make thinking about it easier.
I still use Ruby nontrivially for stuff like command line tools, though.
Ruby has the easiest data access tools, between ActiveRecord and Sequel (which I prefer), out there. I don't know too many folks who'd disagree with you about that. But where you're happy with Rails taking a few lines, I am as of late big on Kotlin (because I agree with you regarding Java) encouraging me to be correct. I'm building a new product using Spring Boot, Kotlin, and JDBI and while, yes, there's boilerplate - it's not the thing that slows me down. I liken it to touch typing; I don't worry if a programmer can't touch type because getting text onto a screen is never the slowest part of the process.
The thing that slows me down, as it does whenever I'm programming, is thinking, and I've learned over time that Ruby doesn't really help me with that. (A lot of other toolchains, both statically and dynamically typed--hello, TypeScript!--do.) I just don't worry about writing a query with a join - it forces me to understand my domain while I'm writing it, not when it runs and bombs out with an error because I mistyped something or got the relationship wrong in my head because my IntelliSense doesn't exist.
It depends on what you're prioritizing. I went back to the JVM for this project in part for perf, but also because I have a pretty high bar for correctness and I want to make sure my stuff works without writing in/out tests for something as simple as types.
Horses for courses.
(Also, I would submit that the frontend SOTA for "Java" is React, FWIW, same as almost anywhere else.)
The problem with boilerplate is not the typing of it (that can be automated), but the reading of it (that can't really be automated until programmers are replaced with AI). It hides semantically useful code in mountains of noise.
I agree with you about the usefulness of a language that helps in thinking about a problem, but I feel like boilerplate is a kind of tech debt we tend to underrate.
I agree with you regarding the reading of boilerplate; that's in particular why I like JDBI. It abstracts the boilerplate of building out a data access layer; you write an interface and it automatically builds the implementation from parameterized SQL queries on the classpath.
Between that and Spring Boot (which is fairly batteries-included but makes it clear when you're going off the happy path in ways I can deal with), I feel remarkably good about my choices with this and similar recent projects.
It's not just code bloat, typed languags and frameworks like spring have to dance through hoops to allow for easy testability. Spring is founded on the idea of dependency injection that's supposed to overcome that. In Rails/Python and friends you just don't need that, and consequently things have much less bloat.
...at the cost of globals all over the place and significantly fewer code-to-interface (rather than code-to-implementatation) moments.
I'd rather test a well-factored JVM or .NET application than I would any Ruby application I've ever seen in my life, to be frank. I've never, not once, had to write a mock (awful) for a test in a JVM or a .NET application, and the quality of my tests reflect that.
Yeah you just end up with race conditions everywhere causing corruption and data loss. See active-model-serializers 0.10.8 release that just found a race condition where serializers would share state across threads making the default Rails web server (puma) completely unsafe.
OK, put up. What's better for the kind of quick-to-write, developer-friendly access under discussion? Because I'd like to know; I've used a lot of the options out there.
It's true for me too. While I love ruby for its beauty and elegance, I love Sequel even more. I find Sequel to be the most powerful and most flexible tool to make RDB queries.
> So, I'm honestly asking, as someone who hates Rails: What framework, out there, somewhere, allows me to be as productive as Rails, but which is are "better," somehow?
I'm a former RoR developer (about 5 years) who's now been a full time Elixir developer for two years, so I'll make the obvious suggestion of Phoenix, which is very rails inspired.
It's a little more clunky in the basics, but it has that "magical" feel that hooked me on Rails back in the day, if you want websockets. And there's a new feature coming down the pike, called LiveView[0] that I think could be a total game changer the way Rails was.
For right now, I think of Phoenix as another rails, better in some ways worse in others, but not better enough for most people to switch. But if LiveView pans out the way I think, then it'll absolutely be the killer feature that will get new apps started in Phoenix, and it's only possible due to Elixir/Erlang's concurrency foundation.
Briefly, it takes the React data model – state at the top of the tree, render the tree based on the current state, change the state and the tree re-renders appropriately – and moves it to the server, using websockets to keep the client up to date. So every connected client has its state in a little elixir process, and interacting with the page transparently is calling functions on the server so you can update the DB or whatever with your normal server side code. And if you had a normal server-side rendered view with an `<%= if .... %>` in it, and that condition changed, then voila, that part of the page will change because Phoenix will re-render it, and send down the diff and the page will put in the new HTML.
On all the Rails apps I've worked on we've inevitably added a bit of React here or Angular there to make certain pages a little more dynamic, and then exposed an API for those to hit, and then had frontend and backend development to do. I think what LiveView will provide hits the sweet spot for most apps, so you can stay in your comfortable backend language and get a bit of dynamism for free.
Sounds nice, definitely not a game changer, the way websockets wasn't a game changer. I think being real time can be easily achieved with existing tools and it's somewhat overrated anyways.
It's not the real time nature that makes LiveView a potential breakthrough, for me, but the additional category of interactivity it gives between "server side rendered" CRUD app and full SPA. Most apps in this zone are probably using jQuery or sprinkling in react, the former of which gets pretty messy and buggy in my experience, and the latter of which is overkill and leads to a much more complicated build system and developer environment.
It uses websockets, and I think websockets are probably necessary to implement the feature well, but that's not what I'm excited about here.
I've been using Django for the last three years and no, it's not Rails. It's a very light framework and you're almost on your own for many decisions. More like a router, a test framework, an ORM and templating language put together than a cohesive framework. Easy to end up with something totally different in every project you look at. On the other side all Rails projects look alike, which is much better when taking over from previous developers.
By the way, Django's inflexible templating language kills productivity (templatetags, as with Java 15 years ago) and the ORM is (how to say it kindly?) lacking in elegance. Django's Model.objects.get(pk=1) vs Rail's Model.find(1) is the least of the problems but I'm short on time now. Because (sarcasm on) we might get confused if we omit objects, what could Model.get possibly mean? (sarcasm off)
Everything in Python seems over engineered as if only very large projects are going to use it, and Django makes no exception. Still, I'll take Python and Django all the times over Java and any of its web frameworks. My personal rankings are:
Ruby/Rails > Elixir/Phoenix > Python/Django >>>> Java/* > JavaScript/* which doesn't have any serious server side framework. I have little direct PHP experience but I'd put it between Python and Java (I managed the developers on medium sized Zend project years ago.)
As somebody who was a Rubyist for about a decade but has worked at a Django shop for several years now, I definitely see how they're similar, but I don't think Django is clearly the better of the two. Django is simultaneously less helpful (you have to do more things explicitly, such as specifying routes) and less flexible (for one example, Django doesn't have a public query builder and doesn't have a replaceable ORM — you're basically stuck with either the built-in ORM methods or SQL strings).
For me personally, Rails is the best web framework I've seen — but in an age when static typing and other static guarantees are increasingly popular, Ruby as a language is not what people want. It's an artifact of the old Lisp and Smalltalk school of thought.
Where is the evidence, outside Hacker News, for this increasing popularity of static typing? The fastest growing languages by most metrics are currently Javascript and Python, both of which are dynamically typed.
According to GitHub's 2018 stats, the two fastest-growing programming languages last year were Kotlin and TypeScript. GitHub explicitly pointed out that "type safety" appears to be one of the biggest factors influencing language popularity in 2018. And even Python, the fastest-rising dynamically typed language, has been adding new static typing features in every release for the past three years. The last new Python app I wrote was fully type-annotated and typechecked, and the new data classes feature actually requires type annotations.
python has mypy types and most places are switching to typescript over javascript. If you work with more than a handful of developers (and as such on a project large enough to require them) not having types DRASTICALLY decreases productivity.
Do you have anything to back-up you claim about "most places"? Most of the job ads on Indeed.com/.co.uk for Python and Javascript make no mention of Typescript or mypy.
Django has a lot going for it in terms of simplicity but it lacks most of Rails' advanced features and timesavers. In my experience it sits somewhere between Sinatra and Rails
Also, having to deal with Python packaging is a world of hurt. No thanks. There's about 16 ways to package and distribute Python, and they all are half-complete and a royal pain to deal with. Ruby's packaging isn't perfect, but it's a thousand times better than any of the Python packaging solutions out there.
Package management is a hard problem, but we know that good and adequate package managers do exist. I'm not sure why more effort hasn't been expended by the Python community, particularly since it's often the first thing a new user will encounter when picking up a language for the first time.
I use Pipenv currently, but only because it's the best of a bad lot and would jump in a heartbeat if a serious competitor came along. It has its own set of problems (slow, young and idiosyncratic) but offers me at least two things its predecessor didn't: separation of production/dev dependencies and seamless integration with different versions of Python, both of which have been available in Ruby since I started programming in it.
This is a perfect exemplifies my experience with both languages: I have found while Python might be better at a lot of things, the user experience is invariably superior with Ruby efforts and I wish the Python community would put more effort into this area.
Good question! When I worked at the Rails shop, we had a standard Gemfile which we started with. It had way too many things in it. Some of the absolute requirements would be to start with 'better_errors', 'letter_opener', 'haml-rails', 'simple_form', 'devise', 'cancancan', and (probably controversial, but my favorite) 'cocoon' (i.e., the thing that makes nested models take so little code). You can probably throw in twitter-bootstrap too, but...
Also, I'm still using RVM. I never made "the switch" to rbenv; I never saw the problem with RVM.
MySQL vs PostgreSQL doesn't matter to me. I've done a lot of both. And Oracle. And SQL Server. I've never seen a problem with using any database with ActiveRecord.
Starting a new project, I just install the latest, stable Ruby, install the bundler gem, then grab the latest, stable Rails, add the basic gems, bundle, and start letting rails generate the basics.
I'm bootstrapping my projects with Vue support, because I think that's the JS framework that fits most-nicely in Rails, and there's always a presentation-heavy page that needs that kind of treatment.
(I'm assuming a Mac or Linux here. I've done this on Windows for a time, but WSL has changed the game there, and I've not actually tried to use it in anger.)
Just read through https://guides.rubyonrails.org/ Unlike the sibling comment I suggest staying away from additional gems as much as possible especially if you're a beginner. Do things the officially blessed Rails way and you will run into the least amount of problems. All gems that try to 'fix' something in Rails will often have downsides of their own and can cause hard to debug issues in corner cases.
I don't understand your bit about "cuteness over familiarity". Can you give an example outside that's not Rails-related (given that Rails seems to be the main source of your concrete complaints)?
Sigils in Ruby actually do have strong and clear meanings. And the difference between symbols and strings is a useful distinction. And contrary to your statement, Ruby's stdlib is far more complete and more internally consistent than what you get from Perl or Python, so I'm not sure what your beef is with that.
It's fair not to like particular decisions a language has made, but from what you say, I'm not getting the sense that you understand the decisions Ruby has made well enough to criticize them effectively. Again, it seems like your experience was colored heavily by Rails, and fair enough if that's the case. But stick to criticizing the actual source of your problems.
Yes, maybe my problem is more with Rails. (Because of monkeypatched APIs, it’s not always obvious to me whether a particular weirdness originates from Ruby’s standard library or is a Rails addition. Arguably this is something the language has also encouraged though.)
Is there any reason to use Ruby outside Rails? Its niche seems to completely overlap with Python and modern JavaScript, and those have enormously more ecosystem support and everything that comes along with it: faster VMs, better tooling, large corporations on committees developing language features, etc.
I view Ruby as a sort of “COBOL of Web 2.0”. A generation of programmers learned the trade with it, and it powers important legacy apps, but I can’t imagine building anything new on it.
I work with Ruby on the web, but rarely with Rails. Apart from the Ruby language itself -- which I love, even though I sympathize with those who don't -- I can't imagine giving up these two libraries by Jeremy Evans:
[Sequel](https://github.com/jeremyevans/sequel) - Sequel is the best ORM I've ever used, in any language. Fast, stable, unbelievably well maintained, and offers great low-level access to the database when you need it.
[Roda](http://roda.jeremyevans.net) - This dynamic routing library is conceptually similar to React Router, in that there is no static list of routes; routing is a function call. But it's faster than React on the server, and has better support for HTTP verb support, database I/O, etc.
As for there being "better tooling" in modern JS, I'm not sure I agree. Babel and ES6 are impressive, and I love writing the code they make possible. But I appreciate being able to write Ruby and know that it will just run. Writing packages for node means choosing one of two incompatible module systems, or adding transpiler bloat.
I came here basically to write this same comment. Can't give enough love to Jeremy Evans and his toolkit, Sequel and Roda are both "gems" of open source (pardon the ruby pun).
Utter nonsense. Whilst Ruby/Rails may no longer be cutting edge Indeed.com/USA currently has 302 Rails jobs by title search compared with 567 for Node, 204 for Django and 142 for Laravel. That's a long way from the “COBOL of Web 2.0” by any stretch of the imagination. Rails also maintained a high score in the review of last year's Who Is Hiring:
Monkeypatching to a large extent fell out of favour with Ruby developers maybe a decade ago, largely because of Rails. It's still being used, but with much more care and it tends to be far more "opt-in" (as in providing the facilities for you to specifically ask for it).
> Is there any reason to use Ruby outside Rails?
Personally I've disliked Rails for about as long as I've used Ruby (14 years). What appealed to me about Ruby then, and still does boils down to:
- Concise while being by far the most readable language I've worked with. The day something beats Ruby on that, I'll consider switching. If they don't beat it on that, they'll have to bring immense other advantages.
- The flexibility the blocks and meta-programming brings and general Smalltalk influence on the object model.
Ruby is in many ways basically a well supported Stalltalk with pretty syntax.
I'd turn it around: I don't see any reasons not to use Ruby for any of the type of work I do.
> faster VMs, better tooling,
The faster VMs would be nice, but Ruby performance is improving fast enough. In some niches it will matter, but you can call out from Ruby to other languages easily enough - you can run JS, C, Python code from Ruby if you need to, so both the performance and tooling is largely moot for my uses, while I can understand it's an issue for some.
The last time I saw a need to rewrite any code in C to speed it up was a decade ago. Of course that depends what you're doing, but for a lot of areas, it's just "fast enough" that there's little need to worry about speed. Premature optimisation and all that.
> large corporations on committees developing language features, etc.
Yeah, no thanks. That's a good reason for me to prefer Ruby as well.
Python already existed when Ruby came out and before rails was a thing. I understand you don't care for the language but the main reason for its creation was to have a completely object-oriented (in the Smalltalk sense) scripting language which python just isn't. Personally, I like a language where everything is classes and methods and I don't have to remember to use a function rather than a method to get (for example) the length of arrays as I have to do in python
I'm learning Java and was surprised to read your comment about ruby being completely object oriented. I always assumed ruby was very similar to Python. I would be interested in learning ruby especially if it is easier for someone with an object oriented background in Java. So, how difficult would coming from Java to Ruby be? And what books or MOOCs would you recommend for the transition?
Yes, everything -- even integers --- are objects in Ruby -- you can say 5.methods and Ruby will respond with a list of methods integers know. I think the best way to learn Ruby is Dave Thomas' classic "Pickaxe Book". This describes pure Ruby, as it predates Rails (not that I have anything against Rails, but a lot of people confuse Rails with Ruby which is a mistake). There is an updated version of the book for sale for Ruby 2.X, but the original is free at http://ruby-doc.com/docs/ProgrammingRuby/ and because most of the changes between versions are minor, it would serve nicely to learn current Ruby.
That's amazing. With integers being objects it's even more object oriented than Java. That's great to hear. The book you linked does I assume no prior programming experience? If so, I would prefer not going over what I already know from Java since both are strongly object oriented. I also hear MHartl's tutorial is good. Would you recommend it fir learning Ruby?
I use it all the time (and have for at least 9 years now) as a general purpose scripting language. Like, stuff that I could do in bash, but if I do it in ruby it will be 10x more understandable and way more concise to boot.
Sure, I could also do the same stuff in perl or python, but personally I find ruby to be far more expressive.
Same reason you'd use any language I suppose. It works as a scripting language, etc. For example, docker-sync, which solves file syncing issues with Docker for Mac (and works on other platforms, but less of an issue there) is written as a Ruby gem.
With AWS recently adding Ruby support to Lambda, my presumption is there's a customer demand there.
Myself, I write a lot of Ruby code that isn't Rails.
> Its syntax strongly favors cuteness over familiarity.
Funny, I recently made a stack switch from Ruby to Python, and I had the exact opposite impression. Ruby coding style/syntax tends to favor convention over configuration (at least in terms of Rails setup), while Python to me seems less so.
Ruby also seems to me a bit more consistent across it's versions. One of the biggest gripes I've had about Python so far is how many things are broken across various versions of the language, and the odd way some issues have been handled (having two distinctly different types of strings with distinctly different syntax according to encoding for instance). Perhaps Ruby simply doesn't offer familiarity to you individually.
I'm more comfortable with Ruby as I used it much longer, so I may be biased, and I am not shitting on Python either. It has things I don't particularly dig, but that may be my own bias. Both languages have their pros and cons, and both are certainly viable as scripting languages in this particular epoch of programming.
Try passing a std::string in from C/C++ code. It treats it as a byte string, which you have to prepend with 'b', and Python 3 will not do any nice casting under the hood back and forth between the two types.
Sure, I am picking out one particular use case, but it isn't uncommon to wrap C code in python scripts to mung data going in and out of it.
You are right though. String manipulation does appear to be easier than Python 2's implementation.
That's because std::string does not carry any sort of encoding information, std::string is basically a wrapper around bytes (hopefully I'm not misreading this, I'm far from an expert C/C++ programmer). Due to this, python can't make any assumptions about encoding/decoding without the possibility of getting it wrong.
"Note that this class handles bytes independently of the encoding used: If used to handle sequences of multi-byte or variable-length characters (such as UTF-8), all members of this class (such as length or size), as well as its iterators, will still operate in terms of bytes (not actual encoded characters)."
It can hold any bytes, it just happens that one way to contruct/represent it can be done with a string-like syntax as a convenience for developers. But you can actually built it in another way, or make it hold data in any other format:
So it makes sense that Python is treating it has a raw bytes array (what you call "a byte string"): it has no way to know that it is UTF8 or CP850 if you don't tell it.
But because of c/c++ experience or habits from python 2, one tends to confuse the concept of text (represented with the type "str" in python) with some specific low level implementation (the raw bytes array).
Python explicitly avoid this problem, by defining that either you know what it is (utf8 text, big endian number, etc) or you don't (raw bytes array). Manipulating text as a raw byte sequence manually would be the equivalent of manipulating directly the IEEE 754 representation of a number: it's not what you want for a high level scripting language, and hence it's why Python 3 doesn't do that anymore.
> Try passing a std::string in from C/C++ code. It treats it as a byte string
Because that's exactly what it is? std::string is a bytes buffer, not actual text. There's no guarantee that the contents of std::string will be in any encoding, let alone a specific one.
FUD is never easy to read, and I'm not always wise enough to answer in the proper tone.
As I do a lot of Python for a living, and still work on both Python 2 and Python 3, I have talked a lot with people writing new P2 apps in the last few years.
My experience is, either you have very niche constraints, or somebody made an unwise/uneducated engineering decision. Unfortunatly, I meet way more of the second type, and of course, most of them pretend to be of the first.
On what planet was my comment you were replying to FUD? I simply pointed out a few things I'm not fond of in the language (with one point in particular stemming from my own ignorance of the language, which was corrected by folks). I was quite clear in stating that python is a language with pros and cons like any other. At which point did I claim anything to be objectively wrong with the language or spread any FUD whatsoever about using it?
Ours were niche constraints (legacy hardware still in-use), as I bet much of the world is. Oh the tyranny of libc...
I would, however, like to question this wisdom of always having to run the latest and greatest. Yes there are security considerations but properly hardened, old software and runtimes run fine. You need an actually security guru, though, and not some startup promising turn-key solutions.
The problem is that "modern python" really includes Python 2 in addition to 3. You can't practically ignore it the way you can ignore ruby 1.x. Yes, things are very slowly moving to python 3, but there is a reason most systems have python 2 and python 3 and even now it isn't uncommon for /usr/bin/python be python 2.
The fact Python 2 has been well supported because the community cares does not make it modern, nor recomended. Just like I wouldn't call php 4 modern, nor recommend it over php 5 or 7.
And the reason you don't see that for ruby or node is because their community said "move or die". And many, many projects just died. I've seen the graveyard in the corporate world.
Whimsical inventiveness is the one thing that keeps me enjoying the art of programming.
There's a tension in programming between being verbosity and ingenuity. More flexible languages and programmers general favor ingenuity, while rigid ones favor verbosity. When people complain about the "magic" in Rails, it's usually because it's a pattern that is new to them, and they would have preferred an older pattern even if it was a more verbose one. Which is fine, but it is a preference amidst a large spectrum of tradeoffs. Unfortunately, many people tend to not see most tradeoffs in software engineering and try to come up with as many reasons as possible for why their way is right and the other way is trivial, stupid, cute, or useless.
> "Whimsical inventiveness is the one thing that keeps me enjoying the art of programming."
A personality difference then. Reading clever code does nothing for me. I'm much happier digging around hulking layered codebases that may look ugly but do something valuable for the user.
I agree that the cuteness of a programming language is just a matter of taste and habit. I'm not going to pretend my criticism was anything deeper than an expression of why I personally dislike having to work in Ruby.
I think there's more to it. Ruby, to me at least, seems objectively more difficult to understand intuitively when scanning the code. Maybe it's just a superficial lack of knowledge on my part, but my brain makes base assumptions on how code should work, and whenever something magical happens, it's cool, but slows down the cognitive understanding enough that it seems to me to be a net negative. There's a crossover point where verbosness becomes too much to grok as well. Maybe spending more time in the language raises the bar enough to then become massively more productive. I'm assuming this is the case with Ruby, but I've not given it enough time to make that determination. Python, on the other hand, is immediately understandable to me, and I can jump in and be productive with no previous experience in the language and just an open webpage to the documentation. To each their own, but this is a continuing question for me. The perfect example I think is Perl 6. To me, when I look at everything they're doing in Perl 6, it really does look like the next generation in languages. It's got so many good ideas and insanely helpful constructs. However I'm not so sure if the ability to do things cleverly is a benefit. I look back at Python and see how simple it is and how productive I can be in it immediately and ask myself.. what's the catch. I'd like to use these complex languages for fun's sake, but the alternative is very, very, intuitive.
> Ruby, to me at least, seems objectively more difficult to understand intuitively when scanning the code.
Reading Ruby code always reminds me a bit of trying to understand how xmonad configs work.
E.g. the Sequel example:
require 'sequel'
Nitpick: IMHO import-operators should operate on names not strings, because they essentially are equivalent to "foo := $magic".
DB = Sequel.sqlite # memory database, requires sqlite3
Why isn't this a function call? How would I pass options, e.g. the file name here? Why is it Sequel. here, but "sequel" above? Does "require" dump a bunch of unspecified names in my namespace?
DB.create_table :items do
primary_key :id
String :name
Float :price
end
What kind of construct is this? Where do all these names ("primary_key", "String", "Float") come from? They were never imported. Is this like ":name => foo" but because that doesn't nest we now have ":name do ... end" for nesting dictionaries?
I think this is just the usual lack of familiarity that you'll encounter with any language that has any non-C-like syntax.
The do...end bits are "blocks" and are the most powerful feature in Ruby, not just because of what they do but also because how they do it. Similarly for other comments.
When I first looked at Rust code it looked weird to me too but once you are familiar with the language a little bit it makes sense. The only thing special about Ruby here is that it allows you to be very terse.
Reading clever code does nothing for me. I'm much happier digging around hulking layered codebases that may look ugly but do something valuable for the user.
I don't think these need to be at odds with each other. Just because code is useful doesn't mean it needs to be hard to read.
What made me switch to Ruby was after I as an experiment rewrote a queuing middleware server that was about 5k lines in C, into about 500 lines of Ruby that had more functionality. It was slower, sure, but it drove CPU load from 1% to 10% of a single core before we hit disk IO limits, so it just didn't matter. What did matter was the improved maintainability of simplifying the codebase that much..
The point being that often the "hulking layered codebase" doesn't need to be.
"pluralizing words in your database migrations" is ispired by convention over configuration pattern, and comes from an age where there weren't almost any standard rules, even table names were some singular, some plurals, some ALL_UPCASED, some all_downcased, some MiXeD, some dash-erized, some camel_ized, ... I come from that age and it helped a lot.
I was taught singular table names back in the 90s, and as far as I remember it was the convention everywhere prior to Rails becoming endemic. And AFAIK it's what Codd and other relational luminaries mandated.
pluralization seems to be somewhat orthogonal to the "no standards" issue you raise; one could have introduced standard rules to help with that 'wild west' and still left out pluralization. pluralization brings with it runtime overhead and edge cases (which can be dealt with with more runtime overhead, of course).
I'm curious, where does pluralization of table names bring runtime overhead? AFAIK, they are stored in the model and not generated every time they are needed.
apparently, my bad. my earlier reading of rails from years ago was that this was runtime inflection, not at generation time.
it still, imo, adds some cognitive overhead, and other orms I've used (grails/gorm, for example), don't try to pluralize. you can pluralize by hand if you want to, but the default is just to name a table whatever the class name is.
But you’re writing an ActiveRecord migration. It’s explicit in the same way that echoing a string out is ‘puts’ instead of ‘print’ because this is Ruby and not Python.
> Ruby is the very least favorite of all the programming languages I've had to use regularly over my career.
> Its syntax strongly favors cuteness over familiarity
How do you define regular? I use both Ruby and JS almost daily, and have previously used Java and python for several years. I find ruby a joy to use and have no issues with 'familiarity'
If I used Ruby daily, I'd probably be used to it. Right now it's something I have to touch 2-3 times a week to implement specific features in a fairly large Rails codebase, and it always feels jarring to make the switch from the familiar JS/C++/Obj-C spheres of syntactic overlap.
Your complaints regarding ruby has been noted.
It's not you favorite language and that's cool.
Every language out there has pros and cons with different set of tradeoffs , you can't point at a language and objectively say X is better than Y.
Ruby has its place and whilst you think Rails is "magic" the internet begs to differ.
Of course any framework looks like "magic" if you don't bother digging into implementation details of it. That is the whole point!
The fact that so many successful companies are using rails in production and scaling it, just shows the complete opposite of what you claim: "an extremely resource-intensive web server framework built around assumptions of what web apps were like in 2003."
There has been plenty of times where i wondered how a piece of AR worked and popped over to the Rails github repo and quickly glanced over the details and had no problem understanding it.
You are entitled to your own opinion, but from the outside, it looks like you are just not familiar with ruby.
"Ruby has its place and whilst you think Rails is "magic" the internet begs to differ. Of course any framework looks like "magic" if you don't bother digging into implementation details of it. That is the whole point!"
I think most people including many Rails proponents would agree that Rails has a huge emphasis on "magic" compared to other frameworks. It's a feature. Convention over Configuration implies magic and that is one of Rails' most famous tenets.
Love it or hate it, magic is Rails' modus operandi
Magic or abstraction layers should be intuitive, so you understand them and are able to solve edge cases. If the abstraction layers are too foggy or magical and you are unable to fix edge cases yourself, something is wrong.
I think you need to share your favorite programming languages so that we know the type of language you are biased towards, and why you might dislike ruby.
How long did you program in ruby? Since its an OO programming language the keywords are per object which makes things simple to understand. Ruby was the first language I really enjoyed and allowed for some really nice DSLs. Even Rust borrowed syntax from ruby (although more ugly IMO).
Early in my career, I only "knew" a little C++ from a high school programming class I had taken, and I knew a tiny bit about Java.
Then I found Ruby, and people talked very highly of it. But it had all these "Gems", I couldn't figure out what a Gem was. I didn't know enough. I thought it was like a compiler plugin or something. I thought that just like there were different versions of Java, there were different versions of Ruby called Gems.
Then I found Python, it had "libraries", I knew what a library was, it was something you could download and use in your code. I learned Python and liked it a lot. If Ruby had "libraries" instead of "Gems" I would have learned Ruby instead since I was exposed to it first.
Python has a Cheese Shop full of Eggs. I love straightforward names as much as anyone, but I don't think Python is exactly the leader in this department, either.
I did a Google search for "hacker news ruby" and "hacker news python" and then searched the top results for "gem" or "egg" or "wheel" usage. It's not a big study, but it is empirical.
Comments about Ruby say:
- "the webpacker gem"
- "Simple to integrate gems"
- "supported via gems"
- "few dozen obscure gems"
- "the I18n gem"
- "the ruby-each-line gem"
- "vast amount of Ruby gems available"
- "working with so many gems"
Comments about Python say:
- "packaged either as a Wheel or an Egg"
- "The numpy module is a wheel"
- "a wheel is specifically not a source distribution"
- "NumPy publishes a lot of wheels for a given release"
All those Python related comments are from one single comment who's author was discussing the technical differences between Eggs and Wheels as packaging formats. Arguably only the last Python comment uses "wheel" as a synonym for "package" or "library".
With a similar background I tried both Ruby and Pyhton at about the same time many years ago.
I didn't dislike Ruby, but I found Python much more intuitive, as you did, but I suspect that in great part was because it had a similar syntax and concepts as C++/Java.
It was like programming in C with a much cleaner syntax and writing 1/3 of the code, it really was an epiphany.
Ok I'll bite. Ruby's biggest flaw is implicit context, due to its emphasis on convention over derivation. Which means that (for example) a developer new to Ruby/Rails won't know that paths are automatically generated from routes.rb, or how those routes and paths automagically connect to controller classes. It's not clear in the beginning how symbols relate to strings or why you would even want them (they are like enums so have better performance, but other languages get around this with better string comparison techniques), or how hashes relate to the associative arrays in other languages, or why hash method work differently from array methods. For example:
Which doesn't recursively flatten like Array#flatten, even when depth is specified. To me, most of these choices are arbitrary or done for performance reasons which get less compelling with each passing year.
I never know from one day to the next which new concept is going to be thrown at me, or how much I'm going to have to memorize. Whether it's Rails, or Rspec, or any other gem - each has its own ecosystem of technobabble that can't be derived from first principles.
In the end, I don't know what problems Ruby is trying to solve. I find it no faster to write than PHP or Javascript. I find that having multiple ways to specify blocks with begin/end and {} merely increases the permutations I must hold in my head as I'm trying to grok code. This is all very perl-like, which makes sense for a 90's language. But I wouldn't advise learning Ruby or using it in production today. Better to go with a more formal language such as Go/Rust/Swift/Kotlin, even though each of those has its own unique set of flaws and pain points.
P.S. If you are struggling with learning Ruby, I highly recommend learning PHP/Laravel first. It has most of the same concepts as Rails/.NET but builds on the existing context that C-style language programmers tend to be familiar with. Then from there you can create a virtual errata document in your mind to store any arbitrary conventions that Rails introduces.
You just never bothered digging into Rails and going through at least the majority of the documntation. I tried playing around with Spring, guess what? It sucks, the amount of reading you have to do just to try and get a hello world is immense.
Agree about symbols though, that's not a good thing. Every language has mistakes though.
googling "ruby MINWAN" yields a bunch of floor-waxing results, and also your comment. it does not actually help me find out what MINWAN is supposed to mean.
So true. Best was ActiveRecord, the most cumbersome ORM I have ever met, it could create 20 SQL requests out of a simple query.
There must be a reason that Ruby dropped few places on Github's Octoverse 2018.
While I was never against Ruby, every time has its tools, it was the culture of the Ruby community which I didn't like. Being a Rubyist was always a good excuse to not help on the frontend or help with some devops.
Now they escape into Elixir which is the next good academic excuse to not help with the frontend because React is so working class...
I wholeheartedly agree. My main gripe is that people insist Ruby is 'easy', because it 'looks just like English'. Yeah, well, it doesn't.
Programming languages are different from normal languages because they have different goals, different users and different requirements. The result in of this forced unification in Rails is something that resembles English, if you squint really hard, but in order to do so, it uses a massive amount of non-intuitive assumptions (sorry: conventions) that I as a programmer somehow should know. This makes debugging unnecessary hard. Also, when developing new features I'm constant guessing whether I should this or that form. The only way to find out is trying things out. This is fun as a hobby, but irritating when you're on the clock.
The idea that a programing language can be unified with a normal language is offensive to me both as a programmer and as a writer. They only benefit is that people who are not programmers can dabble around and still make something useful. Which isn't nothing, but not for someone who programs professionally.
I discovered Ruby in 2005 and immediately fell in love with it. Then came across Rails which really tested that love, what with it's opinions and everything!
And finally reached Sinatra, then Roda and love prevailed! Along the way, discovered and enjoyed working with so many gems both in Ruby as well as part of it's packages!
So, after 13 years now, I'm glad I chose the right language. A language which always asks, is there a simpler, more beautiful way to do the same thing?
I’ve also been using Ruby full time for 13 or 14 years and I am really hoping its popularity and commercial viability continues for another 13 years (or another 25).
I’m certain my level of mastery contributes to my enjoyment. And it’s not that I don’t like learning new things, I do! But Ruby is just an absolute pleasure to write, and it’s hard to imagine spending 8+ hours a day living in any other ecosystem.
> Ruby isn't the most beautiful language out there
Huh, I sure think it is. I wonder what the author thinks the competition might be? Ruby has its issues for sure, but aesthetics ain't one of them - far and away my favourite out of any major language.
The author of this piece is Dave Thomas, who also wrote:
"I came across Ruby in 1998 because I was an avid reader of comp.lang.misc (ask your parents). I downloaded it, compiled it, and fell in love. As with any time you fall in love, it’s difficult to explain why. It just worked the way I work, and it had enough depth to keep me interested.
"Fast forward 15 years. All that time I’d been looking for something new that gave me the same feeling. Then I came across Elixir, a language by José Valim, that puts a humane, Ruby-like syntax on the Erlang VM."
So while he loves Ruby he's mostly moved on to Elixir, which he loves partly because of how it builds on the ideas in Ruby.
> I wonder what the author thinks the competition might be?
I think he meant beautiful in the conceptual sense (e.g. a beautiful algorithm) not the aesthetic sense.
Aesthetically speaking, Ruby would definitely be in my top 3 and possibly first. For me its main competition is ML-syntax languages, in particular Standard ML and F#.
Sincerely, truly a thing of beauty. After writing Lisp code, I don't even understand what people mean when they talk about beauty with respect to programming languages. It's like there are rivers separating the aesthetics of Algol-like languages and an ocean between them and Lisp.
But this brings up a debate I've been having with some folks. I have the memory of a gnat, so I can't keep a lot of context in my head. I prefer the previous two examples to this one, simply because with this one, I have to remember a lot more contextual vocabulary.
It's a pet-peeve of mine to pull up a source file, and then have to ping-pong around between 50 different function calls, when the entire thing could have been written linearly in fewer than 50 lines of code.
On the other hand, small functions like yours are easier to verify at a glance and move on. I haven't figured out what the right trade-off is.
Well, I would say that the primary refactoring done in Slackwise's example is just to assign names to the different conditions and the list produced by range. I think it makes most sense to break these things out and assign them to names when they both become a common idiom in your code (it is used in multiple places) and the logic spans a few lines or has sufficient complexity. I, too, would rather look at one piece of code than have to find out what each function is attempting to do if the name is perhaps ambiguous. For Slackwise's example, I would say that that is too much abstraction because you've basically created as many pieces of abstraction (the conditionals and list) as there were lines of code without them. Maybe the decision for when to abstract can boil down to:
* Is a common idiom in the code base / same logic used in multiple places
* Has "sufficient" complexity
* Can be replaced with a good name that is generally clear with what it will achieve
For Slackwise's example, I think that the names used in the abstractions are exactly what I would use, but I also think that they're not really descriptive enough. If I wasn't the original author and thought I should refactor the names, I would probably try to choose divisible-by-3?, divisible-by-5?, and divisible-by-15? because what the hell is a fizz or a buzz anyway? Maybe you had already thought about all of this and wanted a deeper response; sorry to disappoint.
1. So what? It's not always that case that people on HN reply (or must do so) to a question with an answer that exactly answers the question and nothing else. Diversions are fine and done a lot by users here, within reason. Otherwise these threads would look and sound like classes in logic or theorem proving, ha ha. We're humans here.
2. Why are you interpreting what he (or she) meant? Let them do it themselves.
3. I qualified my earlier comment as saying that it is not necessarily the best way - up front.
4. Beauty is in the eye of the beholder, and beholders vary a lot in their tastes, whether programmers or non-programmers. Like the "de gustibus" quote:
> I'm not sure what language would be more beautiful than ruby.
Elixir (with static type analysis) - gets a bit of an edge, IMO, thanks to pipes, which are way prettier than .then:
defmodule FizzBuzz do
@spec fizzbuzz(integer)::String.t
def fizzbuzz(int) do
cond do
rem(int, 15) == 0 -> "FizzBuzz"
rem(int, 5) == 0 -> "Fizz"
rem(int, 3) == 0 -> "Buzz"
true -> inspect int
end
end
end
1..100
|> Enum.map(&FizzBuzz.fizzbuzz/1) #[0]
|> Enum.join("\n")
|> IO.puts
#[0] function variables are a very slightly "ugly
#syntax" part of the language due to erlang legacy
Other stuff that's really pretty in elixir is the first class documentation. Elixir docs are out of the box prettier than ruby docs.
Compare from the official (but as a user you get these docs too):
But again, it's only a bit prettier. Of course, if you try to browse both on mobile, Elixir wins handily. This is great for when you have to use the bathroom at the same time as you're in the middle of debugging and need to look up what a library module member function does, so there's some developer benefit edge too.
This gives me full visibility over the data transformations that are happening. And removing the IO.inspect's are trivial with an IDE like atom, vscode, etc. Also the way that the BEAM handles concurrent IO means that none of those strings that I send will be interrupted by other content, which is critical to interpretable println debugging in a concurrent environment. I haven't used the debugger (or IEX.pry, whic I hear is powerful) once.
# don't really know what IO.inspect is doing
# but guessing something like this?
def IO.inspect(value, label:)
puts "#{label}: #{value.inspect}"
value
end
value.pipe do
IO.inspect(label: "A")
do_something
IO.inspect(label: "B")
do_something_else
IO.inspect(label: "C")
end
as per Jpakotal's comment elsewhere this might be even prettier:
1..100
|> Enum.map_join("\n", fn
int when rem(int, 15) == 0 -> "FizzBuzz"
int when rem(int, 5) == 0 -> "Fizz"
int when rem(int, 3) == 0 -> "Buzz"
int -> inspect int
end)
|> IO.puts
One interesting thing about this set of solutions is that many of the languages seem to use a pattern-matching approach (e.g. Elixir, F#, Rust, others, IIRC). As a result, having been reading about pattern-matching recently (in F# and OCaml), I was able to understand the gist of the solutions in those languages, although I did not know those languages well or even somewhat, in some cases. Of course, this is for FizzBuzz, for which the logic is easy, which makes it easy to make guesses about how the code works (for many languages at least).
I'm curious: do you genuinely find that beautiful?To me all the enumerable/map/frozen string literal stuff seems pointlessly overcomplicated compared to the simplicity of just writing down what you're supposed to do:
(1..100).each do |n|
a = String.new
a << "Fizz" if n%3 == 0
a << "Buzz" if n%5 == 0
a << n.to_s if a.empty?
puts a
end
(Disclaimer: not my code, on mobile so I stole that off GitHub)
I changed it to a relatively KISS and IMO genuinely beautiful version in the parent, for others' benefits here's the version you were referring to in the above comment:
#!/usr/bin/env ruby
# frozen_string_literal: true
module FizzBuzz
Integer.include self
def self.array(enumerable = 1..100)
enumerable.map(&:to_fizzbuzz)
end
def to_fizzbuzz
"#{:Fizz if (self % 3).zero?}"\
"#{:Buzz if (self % 5).zero?}"
.then
.find { |s| !s.empty? } || to_s
end
end
puts FizzBuzz.array
Ruby was my re-entry into programming. Before it, I had tried programming in highschool (c++) and, while I did well at it, felt like it wasn't for me. I was going to go into some other field like Photography instead.
By chance I had to do a programming class in college, and they had put me into the wrong one by accident - a final year software project in Ruby. I did really well at it, fell in love with the language and got into other programming languages from there.
I've been doing Ruby for 12 years now and it's my go-to language when I can choose. My entire programming career has Ruby to thank.
Me too actually. I flirted with programming around uni-time and after - PHP, java, friggin' ada - and just couldn't see myself enjoying it so I went into network management instead.
10 years later I was thoroughly sick of that, so started to look around and heard about this little language called Ruby - and it was love at first sight. Then this little software project called Rails started to gain momentum and there was no looking back. 13 or so years and counting.
And now funnily enough just when I feel like Ruby is lacking a few necessities in our always-connected world, along comes a project which is basically reworking Erlang to look a whole lot more like Ruby - Elixir. I'll always love Ruby but Elixir feels right for the next step, that kind of instant attraction I never felt for the likes of golang. Here's to the next 13 or more years of Ruby-like programming joy!
I don't get this Elixir as the natural progression for Rubyists. OO/mutable Ruby and functional/immutable Elixir are worlds apart beyond the superficial syntax similarities.
> worlds apart beyond the superficial syntax similarities
I never understood this argument. That "superficial" syntax is what I have to stare at, reading and writing, for 8 hours a day. That I actually enjoy doing so is therefore hugely important to me.
I mean, you can make the same argument against Elixir itself, and I've seen it done - Erlang old-timers arguing against the necessity of these "superficial" syntax improvements. Suffice to say that I profoundly disagree.
Ruby does lend itself to writing a lot of functional code. One can write Ruby so that it looks very similar to Bash or other Algol-derivatives, but it's also possible to write code which avoids side effects, mutable state, or variables in general.
Genuine immutability, ie. the deep copy variant, isn't that easy to work with in Ruby. At least not without a significant performance hit and who wants to add a performance hit on top of Ruby's baseline performance?
Years ago, as a (traditional) designer trying to learn how to code, I spent what felt like an eternity trying to wrap my head around JavaScript. This was in the ES5 days. After a lot of effort I could usually do something approximating what I wanted, but there were a lot of stumbling blocks that got in the way of really understanding what was going on.
Once I learned Ruby, the fog parted and everything started making sense. Compared to JS, Ruby was transparent. Everything was just a bunch of objects sending messages back and forth to one another. The simplicity of defining classes and methods made it easy to think about how a program could model aspects of the real world – domain modeling, abstraction, etc. One early experiment I recall was using Ruby's built-in Enumerable and Comparable modules to represent a deck of playing cards in code (complete with > and < methods which respected suit, royalty, etc) – this was a real "aha" moment in my learning process.
Reading code written by others was much more straightforward (making it easy to learn from the masters), and writing extensions/plugins to existing tools to add features that I needed suddenly became feasible. Books like David Black's "The Well Grounded Rubyist" and Sandi Metz' "Practical Object Oriented Programming in Ruby" were great, accessible introductions to the art of programming.
I don't write much Ruby any more, but I'm in total agreement with Dave Thomas here. Ruby for me was the "royal road" into learning how to program, and it continues to inform the way I think and write code in other languages. As a non-CS person, I can't think of a more accessible way to learn about software development.
There is one thing I really dislike about Ruby (and other languages like Scala that have the same feature), and it's non-parenthetical function invocation. I get that it's good for writing DSLs and similar endeavors, and you're only supposed to use them where its implicit what you're doing, but in my opinion, it really hurts readability (though Scala is much worse when it comes to flexible yet opaque syntax).
Unfortunately you really can't get the refactoring capabilities without being able to substitute a method for a local variable transparently, which is extremely useful over the long run.
It seems like it is currently Ruby's turn to take a beating just like Java before it. I guess people relentless hate on Java even to this day, so maybe it will never get much better. But Ruby certainly holds a special place in my tool box. Here's to another 25 years.
Ruby's readability has been a huge plus for me, and I love working with Rails. I've only completed one Rails project, and I want to work with it again in the future.
This makes me wistful for the 00s and Ruby back when people like _why were around doing fun, weird stuff that felt more like art than engineering. Of course much of that is mixed up in my own early 20s and Ruby as the first language I truly fell in love with. I'm sure just as much (probably more) great weirdness is going on right now, so maybe I'm not mourning that as much as experiencing a maudlin touch of nostalgia.
Great writeup! I agree that Ruby is a remarkable language. One that changed my perspective about what a language could be while at the same time combining some of my absolute favorite ideas from Perl, Smalltalk, and Scheme into a syntax far cleaner and more satisfying than almost any other language I've worked with.
Dave Thomas's Programming Ruby was a fixture on my office desk for a decade. One of the best programming books I've ever read, with a fantastic reference section (built from Ruby's own excellent baked-in docs), my copy is well worn, and I still find reasons to dig it off the shelf from time to time.
I can't give enough Kudos to Matz, Dave, and the rest of the Ruby community for bringing this language into my life. The community they've built is truly amazing, and the language has endured even as it's grown with far fewer bumps and jolts as compared to other similar languages over the same time period.
In summary, quite simply amazing! Happy Birthday, Ruby!
All my accomplishment happen because of ruby. I've been unhappy and depress with java(2006-2010) and then I manage to move to ruby. And I totally like the language. I'm sad when people say python is more nicer, or the nicer and better language there. I've done python and I never find it appealing as ruby
After getting tired of Java's verbosity in 2008, I switched to a Ruby job, where I was fortunate to work with an incredibly talented developer and Ruby expert. It was a joy coding in Ruby after 4 years of Java and XML.
After that, I moved to Groovy, which seemed like a nice middle ground between Ruby and Java, or as I called it at the time: Java as it should have been.
I don't hear much about Ruby and Groovy lately, and while I focused more on front-end development, my back-end work rolled back into Java, which, I admit, has gotten slightly less painful with Java 8. At least in some ways; in other ways, it's just become an even bigger mess where some parts are sensible while other parts are dragging the weight of decades of poor choices with them.
I hear Kotlin is nice, though.
My Ruby skills have gotten a bit stale, sadly. The last thing I did with it was in 2013 I think, when I ran into trouble with Ruby's handling of unicode.
Java may suck to some, but it pays huge chunk of corporate salaries. Although there is the best of both worlds: JRuby! Scripting JMX and some heavy JDBC stuff with Ruby saved me so much time.
They've been overtaken by Python and Kotlin, respectively, as developers' first choice of programming language. Kotlin even runs on Android and natively, whereas Apache Groovy is limited to the JVM.
> I ran into trouble with Ruby's handling of unicode
Ruby's developed mainly in Japan, and Japan's the last holdout in the world against the widespread use of Unicode.
The decision to implement DSLs by overriding method_missing seems to have opened a can of worms and the community has never managed to put the lid back on. More than anything else, this is the thing that seems to cause no end of consternation with Rails. At the same time, it's pretty much the defining feature of Rails.
I'm not aware that this has caused much consternation. I disagree that DSLs are a defining feature of Rails. There are other ways to implement DSLs besides `method_missing`, and rubocop and other style guides warn against using this method.
Rails is a web framework. It's an easy one to use, and often the way to express something is concise enough that I would feel okay saying that "Rails is a DSL for web applications". That would be a simile, however, and not literally correct. It would be more literally correct to suggest that Rails was composed of several DSLs, but that probably stretches the definition as well.
The routing system in Rails is definitely a DSL. You might say that defining model properties was a DSL. You can probably call an ORM query interface a DSL. The controller and view layers are going to look like just about any other framework. Rails is a full-featured framework, which can be configured with a minimum of fuss, bother, and actual code-writing. For toy apps I don't think there's anything else that's faster for development, and for real apps I'm pretty sure that all frameworks are roughly equivalent.
There are Ruby projects which do provide a "DSL for web apps", of which I believe Sinatra is the most popular. Rails incorporates some DSL-like features, and I would agree with anyone who said that it "is basically a DSL for web apps", but I would consider that a figure of speech.
After 25 years it seems Ruby is in gradual decline these days? You will find one ruby related post at HN after reading 500 of Javascript and/or Python posts here for example.
I agree with the other poster who says it's mature, not in decline (so maybe that's boring to the crowd that likes to always hop to the latest tech). Basically most of the kinks have been fixed and desired features have been added, and now it's about gradual improvements and adding new functionality as it comes. Students also commonly learn Python and Javascript in college and are probably more active on social media like HN.
I think Rails is the obvious choice for backend apis these days. It's robust, takes care of most of the hard stuff, saves you time and mistakes. Use whatever you want for frontend (React for me) in tandem with it. Many of the job postings I've seen have listed Rails + React.
It used to get accused of scaling poorly, but tell that to Github, Gitlab, and other large-scale sites with millions of users. It's true that bad Ruby is slower than bad Java, but the solution is to write cleaner code.
I know this was all about Rails. I use Ruby for scripting work as well, and it's enjoyable to use.
> It used to get accused of scaling poorly, but tell that to Github, Gitlab, and other large-scale sites with millions of users.
I've worked on one such large-scale enterprise-level web app, and it really does scale poorly in some areas, specifically database management. ActiveRecord tends to get extremely expensive when db's take on large amounts of records and complex relationships start forming between those large tables. You need VERY good software engineering practices and understanding of which choices will utterly kill you down the line in terms of performance when using this ORM, and it's hard to see those consequences at the outset due to the fact that Rails code is so easy to pick up and understand.
Isn't this true of any language? I mean the language isn't what decides how you connect or build your sql queries? In rails I could choose to write a pretty scary join
```
User.joins("left join ponies on ponies.user_id IN (select id from foobars where user_id=users.id").group("so_funny").count
```
or I could have a policy to avoid joins at all cost and reject any commit that uses a join and get fun things like:
```
users = User.all # all fucking hell
JSON.parse(HTTP.get("http://your-things.json"))['results'].select {|r|
users.detect {|u| u.id == r['user_id'] } # for realz??
}
You are right, but aren't really attacking the point I was making. Even with totally optimized sql, one language's ORM will be inherently slower than another due to the intrisics of how the records being operated on are represented in that particular language. In Rails's case, EVERY single record pulled out of a database gets its own object. There is overhead to being able to represent table members from a relational database in a language with all of the lovely convenience methods tacked on to the resulting object (things such as treating ranges of records pulled like a hash, for instance.
This is compounded by the fact that ActiveRecord obfuscates much of the sql code you posted above (not always, but in many cases). When a user new to Rails goes in and sees "Oh, all I have to do to set up foreign key relations is to just say this model belongs to this other one? NICE!", it isn't immediately clear what the implications of whats happening under the hood to accommodate that are, and all of the ways which this can quickly be misused to cause a huge performance bottleneck. That syntactic sugar smooths over some of the pitfalls of efficiently interacting with a relational DB.
It's important to note that these things do not make ActiveRecord a bad ORM in and of itself, as many users will not build projects large enough to have to worry about such bottlenecks, but it CAN and DOES cause problems when projects get larger and have to start taking on overhead from the resources allocated for all those records. That is what people are complaining about when they mention Rails doesn't scale well (or at least one of the reasons).
> it's hard to see those consequences at the outset due to the fact that Rails code is so easy to pick up and understand
Yes, there are tools in ActiveRecord that can help mitigate some of the performance issues, but as I noted above, it's extremely easy to overlook such tools until you are too far down stream to really do much about it. The symptoms of not using such features may not show up until much later when the number of records swells, and some code someone wrote 2 years ago starts slowing down the whole shebang simply because they used a select rather than a pluck. This is ESPECIALLY true in large corporate web app environments where the number of records is large and the number of people with their fingers in the code base is equally sizable. And good luck convincing management to go back and fix old ORM tech debt until the whole thing starts falling apart at the seams.
Hell, pluck didn't even exist until 2012 with the release of 3.2.1.
Might depend on the amount of spaghetti, but I've typically been able to retroactively fix bad AR patterns backwards compatibly, and get huge speedups. The only time it's a real issue is when an API endpoint is just returning way too much and you have a lot of clients depending on that API returning all that data.
What's a lot harder to deal with is AR callback hell, which can be very slow if you have enough nested callbacks, and can be really hard to fix without breaking everything. Using many AR callbacks is just a bad idea for a big app!
Mature is a humble way to describe stagnancy. Something/one has stopped growing and will likely never become better than it is now. This is on shortterm no decline, but will longterm evolve into it.
For a programming-community this is very very bad. Programming is not only about the language itself, but also the libs, frameworks, tools, and that's what most enytrys about python or javascript are. When the community of Ruby on a nerd-meltingpot already is so low that they hardly share any content, then how much less recognition will they receive in more mundane and conservative communities?
Now less recognition will mean less new users, less new libs/frameworks/tools&support. Over time the existing users will move away or just die, which means the decline has started.
I think this is more indicative of Rails falling out of favor that actual vanilla Ruby declining as a scripting language. Rails is Ruby's only real killer app framework, and it really isn't killer any more. It was pretty inevitable that enterprise Rails apps would go the way of the dodo once folks got wind of ActiveRecord's pretty awful scaling issues, and the fact that Ruby isn't overly performant compared to other popular scripting languages in and of itself.
I think the focus on Python these days has more to do with the fact that it's often the language people learn first these days, and the fact that it has effectively supplanted Perl as the swiss army chainsaw of scripting languages. I think Javascript is popular due to the fact that it is essentially the native scripting/programming language of the modern web (or at least it will be until WebAssembly really catches on), and the ridiculous preponderance of decent frameworks that are out there now for that language.
Ever since the famous twitter drop out of Ruby/Rails many new enterprises adopted it. Gitlab, Stripe, Coinbase, these companis are worth tens of billions of dollars. I'm not talknig about the older generation (Shopify, Airbnb etc), but new successful companies that chose Ruby or Rails in the last 5 years.
https://blog.planetargon.com/entries/18-companies-using-ruby...
If you go to RubyKaigi you'll get a completely different view of the ecosystem.
On the other side of the world, Ruby has many adherents in the embedded development world. A large number of the Japanese talks are about mruby and that has motivated many of the last few years of the languages' improvements.
Ruby's bare word syntax, while sometimes clunky, is usually nice to read. Other than that, Ruby is a stain on software engineering. If you have the choice, don't make it your first language! Ruby has the most fundamental flaws of any of the scripting languages.
It seems that, after Ruby borrowed from many previous languages, a lot of rubyisms went into Rust (the nice functional-style enumerations, the awesome package manager inspired by Bundler). And I'm thrilled the best of the Ruby world found its way into other languages.
A future where the elegance of the Ruby language is available both as an interpreted-scriptable tool (Ruby) or a compiled-statically-typed language (Rust) looks like a nice place to me.