Look, let’s face it: Ruby tools are terrible.
If you’ve worked in any Lisp you know what I’m talking about. If you’ve worked in Java or C# anytime recently you know what I’m talking about. If you’ve worked in Haskell you know what I’m talking about.
“But Avdi! Lisp is homoiconic, and those other languages are statically typed! That’s an unfair comparison!”
Well, if you’ve worked in Smalltalk you definitely know what I’m talking about.
Recently Sarah Mei tweeted:
Can't figure out how a simple thing works in a codebase with a zillion tiny objects and a billion levels of indirection?
— Sarah Mei (@sarahmei) July 8, 2015
Congratulations, you're a better engineer than whoever wrote it. Don't let them fuzz you with "best practice software design" or some shit.
— Sarah Mei (@sarahmei) July 8, 2015
To which Steve Klabnik responded with that wonderful old Smalltalk saw:
@sarahmei "In Smalltalk, everything happens somewhere else." – Adele Goldberg
— steveklabnik (@steveklabnik) July 8, 2015
I’ve only spent a tiny amount of time with Smalltalk, but the fact that “everything happens somewhere else” hasn’t really bothered me there. It’s ludicrously easy to navigate code in a Smalltalk environment. Half the time you develop by tracing execution until you see where code is doing the wrong thing; rewriting the code in-place to do the right thing; and then hitting continue. There is no “OK, now let’s open the file where that was defined” step.
(“ZOMG that’s not TDD!” – relax, the “wrong thing” might well be “making the tests go red”).
All this, and so much more, is possible because Smalltalk was evolved hand-in-hand with its tools; more, it is its own tools. From that point of view, Ruby is Smalltalk but with one entire lobe of its brain lobotomized.
Ruby has terrible tooling. We can write new code at runtime, but we can’t hit a button to see what the generated code looks like, the way we can with Lisp macro expansions. Tracing and debugging is primitive and unreliable; I’ve learned to avoid Ruby debuggers because it’s too easy for funky code to render misleading debugger output, or just crash the debugger outright. We have duck-typing, but no reliable way to get a comprehensive list of every object that might be able to quack. We have rudimentary warnings, but no way to granularly control which ones we see. Most of our editor-integrated code-navigation tooling boils down to glorified grepping. We wait for our CI servers to tell us about potential code smells instead of our editors pointing them out to us as we type. We automatically reach for Google when we want to look up library documentation, rather than use any of the local tools built for that purpose. And don’t even talk to me about debugging concurrent code.
Strictly speaking, the information available to us at runtime should always be a true superset of the information statically available at compile time. And yet, there is no way to “dry-run” a method to get a list of all possible objects it might communicate with. Let alone get us the kind of detailed picture that any modern statically-typed language can give us. And anything we do discover through dynamic runtime analysis then has to be mapped back to static code on disk, which has to be loaded again and configured again and run again before we can see if our changes were the right ones.
And yet.
And yet, in the early 2000s, long before Rails drove throngs of people to learn Ruby, very smart people who knew about Lisp and Haskell and good tooling, fell in love with Ruby. People like Dave Thomas and Martin Fowler and Jim Weirich.
And I did too, for reasons that still aren’t wholly clear to me.
Why do we love this language which is, in so many ways, the worst of many worlds? A Smalltalk without an image or browser; a Lisp without code-as-data; a Java without the static comprehensibility that automates refactorings; a Perl without… no, never mind, it’s still a better Perl than Perl.
It’s not because of corporate hype, because there was none. There’s some kind of weird worse-is-better thing going on here.
It reminds me of UNIX vs. Windows. Windows had COM and ActiveX objects which, whatever else they were, were wonderfully self-describing. You ever develop in VBA? You could poke around through the APIs and object models exposed by every single DLL on the system, core or third-party alike, with full method signatures and hyperlinks to documentation. You could learn how to use Excel programmatically without ever leaving the IDE, just by using the API explorer.
And then there was UNIX, with its horrible mess of different config file formats, and inconsistent command-line interfaces with dodgy documentation—if you knew where to find it. Or maybe you just needed to write the correct magic number to a magic file. And yet somehow, it still felt better. And we glued things together and we got shit done.
There’s something subtle going on here, and I still don’t fully grok what it is. A sweet spot that has no business being as sweet as it is. But I think we ignore it at our peril.
That said: it’s also a mistake to think that the way we do things in Ruby, or the way to do things well in Ruby, are universally best practices. An enormous amount of what we consider “best practices” or “lessons learned” or whatever are really just coping patterns for a language with horrendously bad tools.
Or, flip it on its head: the way people do things in other languages are only possible because they have the crutches of tooling to lean on. You can look at it either way.
Bottom line: the Ruby ecosystem was shaped and molded by awful tooling. It still is. You can reject the language; embrace it anyway; or try and fix it. But to ignore this truth is to lose a vital element of context.
EDIT: Because I’ve been too close to the problem for too long, I left something implicit which I should have made explicit. Ruby’s lack of decent tooling has nothing to do with laziness or distaste for tools on the part of its community. It simply makes writing advanced tooling extraordinarily hard. The choice to be inspired by Lisp but to eschew homoiconicity makes it difficult to edit code semantically instead of syntactically. The choice to be entirely dynamic makes it impossible to do more than basic and/or heuristic static analysis. The choice to be like Smalltalk except to also have keyword control flow makes it difficult to write some dynamic analysis tools (e.g. you can’t write a probe object which is treated as “falsey”). The choice to drop the “image” aspect of Smalltalk means that there is always a gulf between the dynamic behavior of a program, and the static code that creates that behavior, a gulf that is difficult to bridge in a reliable automated way. The choice to let anything be [re]defined anywhere means that unlike in Java, tools can’t trivially find the on-disk definition of a given class or method. Writing nice tools for Ruby sucks, simply because of the trade-offs that went into its design.
EDIT 2: And yes, if you throw money and humanpower at the problem it might improve slightly. But again, you’re working against the language. See the RubyMine IDE, which I am increasingly using for Ruby work: after many years of effort, it has analysis engines and “smart” refactoring tools unavailable anywhere else. But for anyone familiar with tools for C#, Java, Lisp, or Smalltalk, after all that time and effort it still feels like stepping back a couple of decades.
EDIT 3: If you were watching carefully, you may have noticed that I’ve taken two positions without saying one is “right”. I hesitate to tie this up with a neat red ribbon, because the whole point is to make you think about the forces that shape language cultures.
But if you want a suggestion of what to think on further: In the year 2000, nobody programmed in “C++”. They programmed in “Visual C++”. Tools were synonymous with languages. If you told a group they were going to be doing a project in Perl, they’d ask you where to find the install disks for Visual Perl 1998.
And then The Pragmatic Programmer came along, and said: Stop! No! Wake up! Your tools are not your language! Know your language, don’t rely on your tools! In a way, it was a survivalist’s approach to programming: the power may go out someday, so program like it has already gone out!
And it was good. Because we were being burned by bad tools. Our thoughts were constrained by tooling. Our mental models were atrophied because the tools thought about all that stuff for us.
Perhaps most importantly, The Pragmatic Programmer freed our minds to consider new languages, even if there wasn’t a corporate-approved IDE yet. And so we started using languages like Ruby, which is in many ways a survivalist’s language. If the power went out and your intellisense went away, which language would you rather type character-by-character: Ruby, or Java?
But the absence of tools shapes an ecosystem and a culture just as surely as the presence of them. Today I can watch myself hesitate to create a new class, and dig down deep and realize that my resistance comes from years of conditioning about the opportunity cost of pulling out the code, making a new file, making a new test file, dis-entangling the tests from their old home; as well as the hindbrain knowledge that I’ll have very little tooling help in seeing the code’s old home and the new class as a communicating family rather than as isolated, unrelated classes. Today I can watch Ruby programmers talk about how essential it is to unit-test all of the things without realizing just how much we do that to make up for uncertainty that doesn’t exist in other language ecosystems.
The point of all this, you ask? Programming languages cannot be considered separately from their ecosystems. Our sense of goodness is shaped by what is easy, and what is hard, and what seemed easy but burned us over and over until we made rules about not doing it. I’m not here to tell you to use Ruby, or Smalltalk, or Lisp. But if this article has made you think a little more about how much of your judgements about what makes for “good code” are influenced by the ecosystem you work in, then I’ll call it a success 🙂
(Featured image by Derek Finch, made available under the Creative Commons Attribution 2.0 license)
Can it be fixed, Avdi?
Do you know anyone that could do this kind of job?
So much people love ruby, I’d definitely put money to make it better, and I believe many people would.
Find the people to do it, put a kickstarter on, I’m pretty sure the money will appear.
See the edit I just added at the end… it’s really a language issue.
It means that it will never be totally fixable?
Everything will likely always be harder in Ruby, which means compared to other languages it will get good tools much more slowly.
That’s what it means, yes.
A remarkable example of what fixing a language’s tooling requires and can achieve, is the work of Facebook on PHP with Hacklang and HHVM.
Avdi, although the only tool that you mention for Ruby (RubyMine IDE) gives me cold sweats, I think there are some tools that I would never classify as terrible.
Rubocop for instance.. after some years using Ruby as my main language, I started using it and I can finally open old .rb files without crying 🙂
The fact that RuboCop took so many years to appear, and the fact that we run it on CI servers instead of having that intelligence built into all of our editors, is a symptom of what I’m talking about.
As a former emacs user (6 years) I think you should definitely try Github’s Atom it has integrations with RuboCop (as you type), beautifier and syntactic auto-complete. It isn’t perfect and by no means close to smalltalk but definitely better than emacs.
It sounds like you’re not familiar with everything emacs is capable in Ruby these days 🙂
In Emacs I’m using Enhanced Ruby Mode, Inferior Ruby and Flycheck, which offer syntax highlighting, syntactic auto-complete (via RuboCop), and built in REPLs (rails and irb).
The only gripes I have are, demonstrated by Avid’s edit, ultimately language related.
Atom has syntactic completion for Ruby? How does it look?
I’m pretty sure Rubocop was integrated in emacs before all others. Look who wrote it!
There is rubocop support for vim. And I’m 99.9% sure there is one for emacs as well. So I’m not sure what you mean here exactly 😉
I really understand what you mean about the “sweet spot that shouldn’t be as sweet as it is.” More and more often I feel that way about Ruby.
The closest to an accurate-feeling summary I’ve seen is Reg Braithwaite’s “Ruby: Programmer Happiness Through Featuritis.” But is it really just that the standard library is amazing, RubyGems is huge and code reuse is really easy? It feels like more than that. But I can’t put my finger on what, either.
It seems like if we could figure it out, we could purify it, get the same benefit with something much smaller than Ruby. But every time I try that, even as a thought experiment, it feels like I picked the wrong subset.
No clue.
Ruby is like society. Healthy societies are messy societies. Periodically someone tries to “purify” society down to its essentials, and, well…
On top of all that, Ruby is one of the slowest languages in popular use. Considering the compiler/interpreter as part of the tooling, that makes sense.
The design decisions going into Ruby seem to be maximizing flexibility and dynamic behavior. I think that’s the “developer happiness” that Matz talks about, and I know that’s certainly why I like it. That flexibility makes it easy to fit into whatever you’re doing currently, which makes it easier to adopt for progressively larger pieces.
Having spent (yikes) 10 or so years doing Ruby, I am trying to develop new stuff in Elixir for most of the reasons you cited, and so far am having fun with it and learning a lot of new things. I have full AST access and “true” macros via “quote” and “unquote” (unusual in a non-homoiconic language!), a Ruby-flavored syntax, an extreme level of concurrency, failure-embracing instead of failure-avoiding, immutable values, typespecs and Dialyzer, easy access to a library of already-written Erlang code, hot code upgrade hooks, and the tooling I’ve seen so far is nice (although still a little immature). And hey, Dave Thomas likes it. So, I invite you to try it out if you haven’t already!
If you peruse the archives you’ll see some stuff I wrote about Elixir 🙂 I even wrote the Elixir dotenv library.
I’ve been slowly becoming more and more convinced that the way forward for tooling is to determine things through run-time heuristic, logging, and analysis.
If you know, for a given piece of code, what happens with it when it runs, you can make informed choices on how to change it after the fact. For a language like Ruby, I think that is the only real way forward.
I can’t help but think that Pry addresses most of these issues quite well. If you want generated code to appear as actual code, I know how to write that if it’s really something to be desired.
With pry you can simply:
$ Foo#bar
to see the source of Foo#bar
? Foo#bar
to see the documentation
cd MyGeneratedClass
to get inside it and take a look around, and several other things.
Briefly: I love Pry, but it is far from the experience of coding in a Smalltalk environment. It’s a qualitative, not just quantitative difference. And as long as Ruby stays Ruby that’s not going to change.
Which is fine, because this blog post is not about Ruby needing better tools.
Great article. Duck typing does not scale. Runtime efficiency matters. Javascript is a good language, but that is largely because of the fantastic runtime engines. You want to see a well designed language, learn Haskell.
Great article Avdi. Good job! Smalltalk is the best technology to work with for a developer I’ve seen.
Actually Smalltalk is terrible. http://c2.com/cgi/wiki?WhyIsSmalltalkDead
You have absolutely no idea what you’re talking about. The development environments available in Smalltalk are orders of magnitude more powerful than anything Ruby has today (Smalltalk did it 25+ years ago btw) and Smalltalk as a language is cleaner and far for efficient than Ruby as a language.
The fact remains that Ruby is a very close cousin to Smalltalk. If your statement is true, then “Ruby is terrible” because we could find hundreds of ways in which Ruby borrowed directly from Smalltalk or shared language concepts.
As someone who spent 8 years as a Smalltalk developer before moving to Ruby, I would say that Smalltalk use declined because of 1) greed and 2) failure to adapt to the web. All major providers of Smalltalk in the late 90’s and early 00’s where charging thousands of dollars for their IDE (upwards of $7000+); it is impossible to separate Smalltalk from it’s IDE so if you wanted to get started with the language you were looking at a tremendous up front cost. You can confirm this by looking at the pricing on the Instantiations website (http://www.instantiations.com/products/purchase.html) which distributes one of the better IDE’s.
Having said that, Smalltalk use is on the rise, especially in Europe. You may very well see Smalltalk come back to life …
Anyone who loves Ruby could be up and running as a Smalltalk developer in a day and feel right at home. The syntax is a little different, but it’s just objects calling methods on other objects. That’s ALL Smalltalk is and that’s why it’s beautiful and easy to learn.
I share Avdi’s call for better tooling. If Rubyists had tools like Smalltalkers had, it would be amazing. Imagine being able to execute any piece of code you want, at ANY TIME you want, simply by selecting it and telling it to “Execute” (no need to fire up a Pry console – every editor in Smalltalk IDE is already live). Or, what if you could code write code directly in a stack frame inside your debugger, then tell the debugger to restart execution from the parent frame ….
The only thing terrible here is your understanding of Smalltalk and the tools we use as Rubyists.
I think you hit the nail on the head when you say:
“Programming languages cannot be considered separately from their ecosystems.”
Let me be the douche who links his own blog posts by sharing http://blog.dossot.net/2013/11/more-than-language.html where I similarly posited that Platform, Ecosystem and Tooling should all be considered when deciding on a language. My post was inspired by Ruby/Rails but I didn’t want to explicitly say it for fear of language trolls and bigots.
I spent the first few years of my coding career in a Microsoft environment, and thought working with a coding tool like Visual Studio was the only way to do it. Moving to ruby was a revelation to me. It felt like I’d been unshackled from a beast. I’d moved out of an environment where developers were confused if they couldn’t drab and drop widgets into a gui, and help systems that were impossible to navigate from outside the IDE.
For a while, I started building a similar reliance on NetBeans for my ruby coding, and then Oracle took it over and I was thrown a curved ball. This coincided with me starting contracting – and rolling up to environments where I had little choice OS, let alone IDE, and that forced me to be able to use the basic tools.
And the result is I feel liberated and able to code in whatever environment I need to. I still use NetBeans, but am happy to code in whatever text editor is available.
So for me, ruby’s lack of tools suits me just fine.
I have to stop reading your blog entries on Pharo, they make my blood pressure go up! Because they tell me what I already know is true, and have known to be true since the early 90’s. Many people tweet your blog and I have to click it! Thanks a lot Tim Bray! Reading your blog just makes me frustrated because I have to go back to the real world and write Java, Ruby, Python and Oh God yes,that virus JavaScript for the rest of the world, though in the early 90’s it was C/C++. I can only hope that Pharo gets the kind of community that Rails has and creates a huge Smalltalk resurgence. Maybe your blogs can start that!
I love Ruby. I’ve written some medium sized projects with it – which often become prototypes of a larger project. They become prototypes because the act of refactoring in Ruby is time consuming. This is definitely caused by the lack of quality tooling.
I also find myself writing unit tests to cover things that a type system would resolve naturally during compilation. I don’t want to do that – write unit tests like this – but I like that type systems can prove correctness.
I don’t really know if I would hold the tooling — or lack thereof — as a root cause of all of this.
I think I might go a step slightly higher, and say it’s the lack of “magic” in some places, and the existence of it in others, which ultimately leads to what people will tend to or hesitate to do.
If I think of Java, I think of the refactoring tools that people are capable using to eliminate the pain of splitting classes and tests up. But this magic only extends so far, and then you find Java classes which no one touches, because they aren’t amenable to automated refactoring.
If I think of Ruby, I think of the magic people rely on to make things just happen implicitly. This magic sometimes extends farther than we intend, and we might be just as tempted to go and fix the thing affected by the magic, than decide the magic isn’t worth it.
I’ll spare other languages, but I wonder if there’s analogous situations we can find there.
To tie this back to tools, some aren’t so magical. Some are. Automatic refactoring is magical. Code analysis, maybe not so much. Whether valuable or not, the magical things seem to be the things that are heavily favored.
It all feels a little bit like magic. But to a magician, magic isn’t magical. It’s just an illusion; it’s where humans perceive the abstraction incompletely, because our minds were never equipped to see all of it.
It takes philosophy to get beyond magic. I think this might be why, in the morass of crazy file formats and other things in Unix, the basic text tools became pipeline-able. Nothing really seemed to force them that way, other than it seemed like a good philosophical choice.
In software, we have available the parts to complete the abstraction, to understand the magic. To think philosophically. But we perceive a high opportunity cost to doing so, just as a magician’s routine may seem to imply a high opportunity cost to understanding how it works.
Different languages, and the design decisions they trade-off, enable different sorts of “magic”. I honestly wonder a little if the Pragmatic Programmer guys might’ve been thinking more broadly “Know and understand thing, don’t rely on magic and magical things!”
Oh, and thanks for the post. Definitely thought provoking. 🙂
I work in Scala and I often say there’s no magic in scala. That’s not entirely true, but a lot of things that would be a “magic” language feature or monkeypatching in another language are just ordinary Scala code in an ordinary Scala library.
It’s not as helpful as you might think. You can click through to the source of everything, which is nice, but if you don’t have a concept of what the thing is then you may not understand it. You can have a codebase that in Java would have been AspectJ + Spring-AOP + goodness knows what else, where you have to read random XML files to understand where something is coming from. And in Scala that codebase will be just code, and it is better, it’s easier to follow. But then you realise it’s not actually that much simpler; your complex framework stuff has just been replaced with complex code.
While the Pharo introduction video shows a lot of niceties, it also demonstrates a reliance on window-and-mouse heavy workflow. At least, that’s my impression from it, and from the few small attempts I’ve had at getting familiar with it. That’s a turnoff for this Emacs user.
Ruby dropping the “image” aspect is not a definite weakness as well, we can still launch the application we’re currently developing, and perform introspection (via, say, Pry), edit and re-evaluate methods at runtime, etc, similarly to what SLIME does. I think both Pry and Pharo have things easier for them when implementing, say, code completion though, because both CL and Smalltalk seem to be more statically inclined than Ruby.
In CL you have modules and are forced to write imports, basically in each file. A code completion or navigation tool can take a look at those and severely limit its search space. Even Python has something similar. In Ruby, on the other hand, you dump every class and function that’s been loaded into one big shared environment. That’s the least favorite trait of the language for me.
Smalltalk, from what I’ve seen, also inclined toward more constraint. In the other video, for instance, you were forced to declare the local variable in advance, at the top of the function. I’d wager there’s less reliance on meta-programming as well. Does it even have something as easy to (ab)use as Ruby’s define_method, instance_eval, etc?
SLIME and Pharo, I mean.
Um no, Smalltalk isn’t inclined toward more constraint — although I can see how you might surmise that if you’ve only watched videos of it being used. If you’ve only seen instance variables defined before you use them in ST examples, it’s easy to assume that there is no other way.
I did ST programming in the late 80s and into the 90s, and I’d say that ST was/is actually more inclined toward meta-programming and fewer constraints: You have ridiculously easy access to everything — every class — all of the time. You could very, very easily redefine “Class” as easily as you could “Integer” as easily as you could any inspector or editor. It would be foolish to do the first two (almost always) but encouraged to do the last two so that you could create your own version of emacs and/or templates and/or macros. Creating your own lightweight customized IDE that fits your workflow is not hard at all.
Meta-programming was probably just as common as in Ruby. And it could be just as abused, or even more so because you could so easily changed how anything was parsed or evaluated or defined. Don’t like how the language is parsed? Want to add your own keywords? Change keywords? OK. Not a problem.
Not to say any of that is a good idea or good practice or good pattern, but just that the system was so totally open and so totally At Your Fingertips, that you could, and with very little constraint.
Does ST have the equivalent of “instance_eval”? Oh my, yes. And then some.
Thanks for the reply, point taken. Guess I should look into it more.
P.S. “your own version of emacs”? 🙂
Great thought provoking post!
I wouldn’t say that Ruby is “defined bad terrible tools”, though. Sure, I wish the tools were better, a lot better in fact. But “terrible” seems too strong for me.
Also, given the experience from my projects, I’m worried about too much/heavy tooling. One project was using C#, and it depended on tools such as ReSharper being present, or you couldn’t productively work.
Mind you, ReSharper is a great tool. And yet… If a project gets very hard to handle without such a tool, well, maybe there something wrong with the project — and neither the language nor the available tools.
Do you (all of you) think we can improve the situation for Ruby? Is it really that necessary? If something doesn’t happen, such as (drastic) Ruby-tool-improvement at the moment, it may mean the need isn’t (yet) big enough.
I agree. Most of time the real need is to improve ourselves and our code.
I think you might have mistaken the thrust of my article. This is not a post about Ruby needing better tools.
LOL. second time u say that in this comment thread.
R u over ruby or do u want it to change. Or both/neither?
U do claim its just the nature of the beast
U be u. I’ll be me. Ruby will be ruby. Se la vie then yeah?
So I guess one q. JavaScript ain’t much different, and I use that at work everyday client and server. I haven’t played with those other languages u mention much, no time till maybe like today recently. (Which is why I’m reading blogs! w00t!)
Can u compare ruby(lack of tooling and why) and the chrome debugger(And its tooling and why) in comparison to the small talk(experience and why) — where why/experience mean anything interesting about those comparisons/experiences etc. Elixir too perhaps.
i think I understand what this article is about – ruby is dynamic as all heck, I get that, but what the trade off actually is and feels like, etc – for someone who never knew they were really missing something – is unclear and based on assumptions of ur own experience. True or false?
Most companies/repos/$$ seem to be moving towards JavaScript – those stuck in their ways simply have no interest but the young and curios could give two shits about an IDE when they’ve never needed one and can code fast and well without one
Do u think ur perspective is in anyway tainted by not having the constraint of being brought up without an IDE or vis-a-vis – I am the one without enlightenment.
Ive always highly regarded ur thoughts – and came across this by accident this morning and glad I did. Curious though I am of what ur heart does feel within.
Is ruby becoming < Date.now() for u?
Omg. I thought this day would never come.
Worse is better is right. I think what it boils down to is that formats have to be lowest-common-denominator. If you build a beautiful structured format but it’s closed, can only be used in your own little world, then it’s not going to be as useful as something ugly that interoperates with the wider ecosystem.
Unix vs Windows was that. So is images versus code on the filesystem – images are nice but you can’t check them into version control, can’t grep them, can’t use whatever random third-party tools you want to with them, and so ultimately files end up winning. So I think is SOAP versus “REST” (I can’t abide HATEOAS fundamentalist REST) – a highly structured format that you need to use specialised tools for is ultimately less useful than an awkward ad-hoc thing that any HTTP tool understands.
Or to put it another way, the more structured something is, the harder it is to write tools for it. Certain kinds of ruby tools are hard to write. But a larger class of tools becomes really easy – method_missing and the like mean if you want to create a dynamic network client then it’s simple, which in a language with a stronger metamodel would be hard.
Something doesn’t feel right about this article. I would love to have the same tooling that Smalltalk has but at the same time I don’t belive neither Java or C# have the same level of tooling that Smalltalk has.
You say “Most of our editor-integrated code-navigation tooling boils down to glorified grepping.” I’ve been using Rubymine for years now and I can click on a class or method and get the definition directly. You say “We wait for our CI servers to tell us about potential code smells instead of our editors pointing them out to us as we type.” Again, Rubymine has implemented many best practices that integrate seamlessly while I’m typing.
You mention Rubymine in your Edit #2 and although I must admit I’m no expert in Lisp or SmalTalk, I would say that the difference in Rubymine and IntelliJ (for Java) doesn’t feel to me like 20 years. I wish I would have had something like Rubymine for Java 20 years ago!
I’m a profesional programmer and have no problem paying for my Rubymine license every year or for the need for more processing power and RAM than using Textmate/Sublime/Atom. If it gives me a better picture of my codebase or let’s me refactor or even run a single test easier then it has paid the cost over and over.
I do understand that the limitations of the language make it hard to build tools. That’s one reason I’ll keep supporting people that do all the hard work.
Ruby is great because it can be beautiful (try “elegant” or “expressive” if you prefer). “Can be” because it is always possible to do hideous and incomprehensible things. Just as it possible with a real human language.
Lisp and Smalltalk can be beautiful. But there is no way that Java or PHP can ever be made beautiful – that was just never part of the genesis of those languages.
I don’t know if the expressiveness of Ruby inherently requires the sacrifice of the sort of tooling you describe. Perhaps there’s another Beautiful language to come that will give us all those things – and rainbow unicorns.
I completely agree with Jason May, my main point when I stick with Ruby is that it’s elegant. Extremely elegant. And yeah I checked Haskell and Scala and they are not yet as elegant as Ruby (maybe Haskell yes, I have to dig deeper into it, but I watched some code samples).
Sure, Ruby has weak points, but indeed it has strong points. And your argument against being completely dynamic is indeed one of the strongest (and more pleasant) features I found in Ruby.
That being said, I came from C# and stopping using visual studio in favour of a simple text editor felt like an improvement, so I don’t agree at all for the editor part.
Interesting post Avdi.
I started working in VB6, then moved to C#, VB.net then Java and then finally I moved to python/perl, and ruby for the fun.
The moment when I tried to move from the MS stack into a more unixy world I discovered myself looking for the right IDE that would provide the right intellisense to CTRL+SPACE my way through code.
It took some time, but thanks to the “pragmatic programmer”, “destroy all software”, and some thinking I realized that I needed to detox myself from the IDE dependance that MS got me into.
Today I work with VIM all day, and I do look a bit over the shoulder to the people who “need” their IDEs to do work.
I think I do feel better with myself for not needing a specific vendor tool to be productive, or better said, I just need a simple text editor, which allows me to jump from one language to the other seamlessly, without changing my shortcuts.
That said, the complexity of the projects I work with these days is not as high as the projects I did in Java, but also thinking this through a bit more. I wonder how much of this complexity was introduced by the power of the tooling itself.
Probably because I “only” have text editor I am forced to “simplify all the things”, which in the end enables building things in a way that “I can fit in my head”™. This is not always true, off course, but at least I find myself thinking more and more about the code comprehension than when I could just CTRL+SPACE or F3 my way through the project massive code base.
Tell this to @garybernhardt
I want to say that I love Ruby and Ruby on Rails because it takes a lot of pain of development out of my hands and I can focus on getting things done. But, I still have a hell of a time debugging some of the magic that Ruby on Rails provides using my RubyMine editor.
Because of the tooling, I am keeping an eye on Kotlin, simply because it looks like it has almost everything I love about Ruby, but it will have the tooling there because it’s built by the tool makers (JetBrains).
“If you’ve worked in Java or C# anytime recently you know what I’m talking about.”
I know what you’re talking about from a Lisp and Smalltalk perspective, but I don’t know what you mean by bringing Java or C# into the discussion. They seem no better than Ruby to me, and in many ways worse.
You later suggest that “static comprehensibility […] automates refactorings”, but that does not match my experience. As Steve Yegge once pointed out, static typing only goes so far. Java is low-level enough that if you don’t want tons of duplicate code (and no good programmer does), you end up putting it in XML files, or passing it around in strings, or stuffing it in database fields. Static refactoring tools can’t help you here.
And if you just want to do basic things like “extract method” or “rename variable”, then a simple text editor mode will do about as good as a static refactoring engine. Better in some cases, worse in others.
Lisp has great tools because it’s decades old, and was designed in such a way that it’s easy to make good tools for it. The tools for Java and C# are still kind of a yawn.
Reading this article I just realize my career path went from MS Windows with it’s slick Visual Studio IDE to Linux and loving to code in VIM. Personally for myself there is something magical about Linux, the (ugly) command line tool environment and rolling up your sleeves and getting stuff done.
Well, VIM it’s a great editor but the fact that no one created a new, upgraded version of it is sad. I mean, I’m quite sure it’s possible to have a nice, good-looking VIM (NeoVIM is on the way, infact)
You guys amaze me. You have grown so spoiled with your expectation of “tools”. When I got started in software development, there were no “tools”. Back in 1980, I and another guy wrote a C compiler and a new Operating System FROM SCRATCH. You know what I used to debug the OS? Stack dumps, print outs, register dumps and the like.
Has the software development profession gone so far downhill that today’s developers need all this hand-holding to get anything done? Today I develop Ruby code with nothing more than Emacs and Pry. I have tweaked these “tools” by hand to suit my needs perfectly. I even have a macro defined in Emacs to automatically insert and remove the Pry breakpoint when I need them.
I have played with RubyMine, but it sucks. It’s designed to develop monolithic apps, and it’s difficult to tweak, and it crashes during debugging A LOT. And they have the audacity to charge for that.
I find Pry to be sufficient for debugging, and the Pry console is nice because you can “cd” into an object and see all the methods and variables with an “ls”. And it comes with some nice plugins to allow you to do more.
It is my opinion that if you require a lot of hand-holding, like, for example, those annoying popups for name completion and the like you see in many of the IDEs today like RubyMine, Eclipse, and others… if you really need all of that, maybe you’re in the wrong profession. I find those things annoying because they change the behavior of the Return key while I’m typing in code, and then I have to waste time undoing what it did… Even Facebook adopted that mis-feature…
I’ll stick with Emacs. Works well with Ruby, C++, Python, Java, Lisp,…
fully agreed and exactly my thoughts when i read the article. Even thought i didn’t even live in the times you refer to. But i really cant tell where this dependence on tools is coming from.
I was going to make a comment about the project where the only debugging tool I had was the ability to write codes to a single byte of memory with a known address, which I would then read with the help of a logic analyzer (and a hardware engineer who knew the right places to put the probes). True story!
…but then I remembered that this piece is not about Ruby needing better tools, something I have clarified over and over again. If you read this whole thing and still all you could think about were your tool preferences, you may want to review the article again, as well as your approach to client requirements.
I am a firm “believer” that an article’s title should reflect what the article is about. Yes, it is more about the assertion that a language cannot be considered separate from its tools, to which I would sharply disagree. While tools are nice and can definitely make some tasks easier, a language must stand on its own. Developing dependencies on a set of tools surrounding a language to the point you are unable to function with, say, a plain old text editor, is not a good sign in my book.
I am not saying to throw away the tools. I personally have tweaked Emacs to make me more productive with Ruby after getting disgusted with RubyMine.
In the end, to each his own. Do what you’re comfortable with.
Obviously i am rather alone with this, but i prefer languages that i can write in a simple file structure in a basic text editor. I use Sublime Text or Atom with nearly no plugins, i dont care about fancy autocompletion other than my own variables or functions, i dont care about included debugging or anything else therelike.
I like to have my terminal open next to my editor to do those things, after all thats also where i git commit my changes when everything works, i am no clicker.
You are not alone. I make heavy use of both Emacs and Tmux, and use multiple monitors so Emacs is on one and a Tmux session is on the other, complete with Tmuxinator to preload all my windows and pane layouts.
The power of the Dark Side of Simplicity. Muahahaha!
I watch my colleagues use Intellij, and they click and click and click… functionality hidden in tiny little icons at the corner somewhere. On Macs, where you don’t as conveniently have virtual screens like I do on KDE / Ubuntu.
I have all kinds of keyboard shortcuts to launch the CLI full-screen, Emacs, other tools I use regularly.
How do experienced Ruby developers adapt their workflows or adopt workarounds to mitigate the impact of the tools that are considered less than ideal?