Beyond Java - Bruce Tate [56]
Ruby containers will feel altogether different. You won't have to deal with the maddening type casts or generic syntax. Code blocks simplify iteration. You don't see too many types of collections, but don't let that fool you. Using the rich methods, you can use Array as a list, queue, stack, or any other type of ordered collection. For instance, let's use Array as a stack:
irb(main):001:0> stack=[1,2,3]
=> [1, 2, 3]
irb(main):002:0> stack.push "cat"
=> [1, 2, 3, "cat"]
irb(main):003:0> stack.pop
=> "cat"
irb(main):004:0> stack
=> [1, 2, 3]
Similarly, you can use Hash whenever you need a set, dictionary, or any type of unordered collection. You'll find yourself doing more with collections, and less customized iteration.
Files
Iterating through a file works much like iterating through a collection. You'll create a new file and pass it a code block. For example, here's a simple GREP:
File.open(ARGV[0]) do |file|
rx = Regexp.new(ARGV[1])
while line=file.gets
puts line if line =~ rx
end
end
To use it, type it into a file called grep.rb. Then, you can call it (outside of irb) like this:
ruby grep.rb filename regex
Notice what you don't see. You don't have to close the file or manage exceptions. This implementation makes sure the file will be closed if an exception occurs. You're effectively using a library that specifies everything on the outside of a control loop that iterates through a file. Ruby does the repetitive dirty work for you, and you customize the inside of the control loop with a code block.
Why Should You Care?
By now, you should be getting a feel for the power and simplicity of Ruby. You can probably see how the lines of code go down and the abstraction goes up. You might think it doesn't make any difference. You could lean ever harder on your development environments and on code generation tools like XDoclet , and shield yourself from some of the problem, but let me tell you: lines of code matter!
You still have to understand anything that your tools generate. I work with dozens of people every year that don't understand the SQL that Hibernate cranks out, and others who have to maintain generated code, after they tailor it for their needs.
The more code you have, the more bugs it can hide. Unit testing can take you only so far. You'll still need to inspect code to enhance it or maintain it.
Writing code is not the only cost. You also need to consider the cost of training, maintaining, and extending your code.
Each code generation technique that you use limits your flexibility. Most Java developers now depend on tools to do more and more. Each tool that you adopt carries a cost. I'm an IDEA man, but some of my customers use Eclipse. I'm nowhere nearly as effective on it, so my customer loses something when I am forced to use it. XDoclet increases the feedback cycle.
Java developers rely increasingly on XML for configuration. Remember, configuration is still code. Developers from other languages often find Java's over-reliance on XML configuration annoying. We use so much configuration outside of the language because configuration in Java is painful and tedious. We do configuration in XML rather than properties because...well, because overuse of XML in Java is a fad. Meanwhile, configuration in Ruby is usually clean and comfortable.
You may be willing to pay the costs related to lines of code, but you should also consider higher abstractions. With Java, you must use unsightly iterators. With Ruby, you wind up building the iteration strategies into your containers and reusing that logic.
Said another way, Java customization usually happens with an outside-in strategy. You build big chunks of reusable code that fill out the inside of your applications. But that's only one kind of customization. For many jobs, you'd like to keep a generic implementation of a job, and customize a few lines of code on the