Michael Smolyak started working with Java technologies in 1996. His experience as a developer, a technical lead and an architect covers all tiers of enterprise Java ecosystems. During his journey through Java which strated with Java 1.0.2, Michael has become Sun Certified Java Programmer, Developer and, most recently, Enterprise Architect. Michael holds a Master of Science degree in Management Information Systems and a Bachelor of Science degree in Applied Mathematics.
Michael is currently working at DataSource, Inc on an exciting and powerful tool called Jetson, created to make development of robust and well-designed enterprise Java application a simple and straightforward task.
| Author(s) | Stuart Halloway, Justin Gehtland |
|---|---|
| Publisher | The Pragmatic Programmers |
| PubDate | 2007, First Edition |
| Reviewer | Michael Smolyak |
Right off the bat the book authors tell us for what types of Java developers the book is intended (following the famous joke about 10 categories of people - those who understand binary notation and those who do not): those who want to program in Ruby and Rails and ... those who don't. Consequently, if you belong to one of those 10 categories, the book is for you. The authors are excited about subjects of Rails and Ruby and this excitement is palpable throughout the book. They list the following strong merits of Ruby on Rails:
Coming from Java background themselves, the authors' preferred audience are experienced Java developers with whom they share a common language and background. The authors' stated goal "in visiting this new world (Rails) is to learn by comparison with our shared history (Java)". To draw parallels between Ruby on Rails and Java, the book presents a Java application developed using what authors felt were technologies most familiar to Java developers - Struts, Hibernate and Axis.
You would expect people working for a company called Relevance LLC to be on good terms with this concept. Indeed, Messrs Halloway and Gehtland do not disappoint. At the very beginning, they state what their book is (a Ruby and Rails introduction for experienced Java developers) and what it is not (not a step-by-step tutorial on Ruby or Rails, nor is it an RoR introduction for managers). The authors suggest alternative texts for readers not belonging to the intended audience. I think the authors take their "not a Rails tutorial" approach a bit too far. Most of the samples in the book are designed to be looked at. Although the book comes with two Web applications, Struts and Rails-based ones, there are no instructions on how to run them. Instead there are many references to the code of these two applications.
Being somewhere above Dreyfus Model (popularized by Andrew Hunt's and Dave Thomas's talk "Herding Racehorses and Racing Sheep", http://www.pragmaticprogrammer.com/courses/racehorsesheep.html) Level 3 in Java topics and at Level 1 in Ruby-related subjects I certainly appreciated the fact that all the Ruby concepts are illustrated with Java analogies. At the same time due to my inexperience with Ruby I was able to only gain a general understanding of certain advanced concepts - unfamiliar Ruby syntax was frequently in the way. Thus, if you are a Ruby beginner, reading a step-by-step tutorial before attacking this book might be helpful.
Reading the "Getting Started with Rails" chapter felt at times more like being thrown into the water with the intention of testing whether the reader can swim. The chapter gives you a whirlwind tour of Rails ecosystem. You learn about the sources of Rails downloads (I used Instant Rails), Rails IDEs (there is an Eclipse plug-in Radrails) and Ruby and Rails documentation. In this chapter you install the Rails environment (along with Apache and MySql), generate Rails application and explore the structure of the newly-generated Rails app. The great thing about Rails (which is part of what make programming it fun) is that it just works. By a single command you generate a complete (albeit primitive) MVCWeb application with persistence tier. You can immediately start your Web server and connect to your application. The chapter shows you how to add such simple functionality as new persistent fields, data validation, search logic to the generated system. Each exercises is short, to the point, and they all work. The chapter describes the three Rails environments, development, test and production, whose configurations are generated automatically, their purpose and how to switch between them. Next, the authors introduce Ruby interactive shell (irb) and Ruby scripts generated as part of each Rails application. The individual pieces of the generated sample application are then mapped to the book chapters covering those topics in detail. Having covered the basics of Ruby runtime environment, the authors introduce the sample scripts supplied with the book and provide instructions for running them.
As they promised, Messrs Halloway and Gehtland illustrate each Ruby concept (types, string operations, objects, lists and maps, control flow, inheritance, exception handling, etc.) with an example of Java code followed by an equivalent Ruby snippet underlining the similarities and contrasting the differences between the two languages. The authors tactfully tackle the issue of type safety not bashing Java's static typing in the "Beyond Java" style, but pointing out instead that margin of safety gained by static typing is rather thin. There is a gentle introduction to blocks in the sections on Collections and Ranges. A Java developer in me marvelled at the compactness of Ruby compared to Java. Ruby does not require creating classes for one-line programs. Statement if ( x ) checks whether x is null (nil) if it is not Boolean. A simple condition can be written as a=b if b > 0. Equally compelling are such Ruby features the power of case statement (as compared to Java's), integration of regular expressions in the language, ease of iterating using blocks, and terse notation for accessor methods.
This section of the book continues Ruby exploration by contrasting it with Java. If the "Programming Ruby" chapter concentrated on the topics where Ruby is more or less similar to Java (and thus easier to grasp by Java developers), this one handles concepts which are either unique to Ruby or are implemented in a manner very different from that of Java. Having almost no Ruby background, I found the chapter "Ruby Eye for the Java Guy" much harder to swallow. One of the reasons is that this book is not intended as a Ruby introduction, which means that many advanced Ruby features are treated in a very compact manner, sufficient to introduce the concept but requiring much more details for full understanding. In the words of the authors, they "improve your Ruby accent" by tackling
The chapter "Data Access with ActiveRecord" explores Ruby persistence mechanism by comparing Hibernate with ActiveRecord. The main difference between the two frameworks is more power offered by the former offset by the greater simplicity of the latter. In Hibernate most operations are performed through a Session object. The POJOs being persisted are unaware of Hibernate. ActiveRecord, by comparison, is a more invasive framework. The entities are ActiveRecord objects. This make the API much simpler since the CRUD operations are performed on the objects themselves. No sessions means no caching in ActiveRecord, but it also makes it unnecessary to open and close sessions, detach or attach objects to them. Dynamic typing of Ruby and ability to map arbitrary method names (even those that do not exist) to some logic using "missing_method" idiom provides a very feature-rich API using a small number of actual API methods. The power vs. complexity trade off holds for other persistence aspects. Data validation, callback methods, association mappings do not require XML configuration files or special classes. All these features are implemented through methods on domain objects themselves. For example, a 1-M relationship between Person and Quip (a clever remark) objects is implemented by a single line on Person class:
has_many :quips, :foreign_key=>'author_id'
This line supplants both XML mapping used by Hibernate and a series of methods to traverse the relationship which would normally be declared in Java on the Person class. Simplicity does mean less power though. Object inheritance mapping in ActiveRecord is present but only for Table Per Class Hierarchy technique. Cascade saves are supported but only in a fixed direction. Only local programmatic transactions are supported (no container- or distributed transactions). The chapter also covers ActiveRecord support for optimistic locking, reading data using joining, and connection pooling. In the words of authors, ActiveRecord "does not provide a kitchen sink of O/RM services, but it delivers the Active Record design pattern with an API that is clean, simple, and beautiful".
"Coordinating Activities with ActionController" chapter introduces the reader to the Rails Web tier by explaining the operations of ActionController. The key Web concepts such as of URL routing, processing of Web pages associated with CRUD actions, Web session, page validation and filters are illustrated by a juxtaposition of two "people" applications, one implemented in Struts, one in Rails. Curiously, the explanations of mechanics of Struts application with the samples of Java code and XML configuration files take as much if not more space than the treatment of the corresponding Rails topics. The reason is not hard to guess: mechanisms used by Rails for URL routing, or for accessing request and response objects, or for accessing Web sessions are much simpler and more compact than those employed by Struts. URL routing, for example, is defaulted to a simple scheme, but can be easily modified by overriding a single method on an ActionController class. The request and response objects do not need to be passed around, they are implicitly available as instance variables on the controller. Forwarding to views also happen implicitly but can be overridden. There is no equivalent of separate Struts "form" objects in Rails, the domain (ActiveRecord) objects are used for that purpose. The Rails applications, according to the book, avoid a separate data access layer. The controller code (think Struts actions) accesses the database directly through ActiveRecord. There is a Plato-like imaginary dialog between a Java and a Rails developers discussing the virtues and hindrances of Java layered approach, where the authors defend the "layers on demand, less tooling" approach as more suitable to Ruby. At the end, the chapter introduces the topics of logging (a much simpler affair than Log4j) (while giving a good tongue lashing to JDK Logging), profiling (built into the environment, easy to use but quite primitive) and debugging (there is a built-in command-line debugger).
Having covered an MVC topic of Rails controllers, the authors take on the subject of views in Rails. I found my lack of Ruby and Rails knowledge to be a significant obstacle in tackling this chapter. The chapter starts with .rhtml files using Embedded Ruby, which are similar to JSP files, then moves on to View Helpers (Ruby classes whose method are automatically available to the .rhtml pages). The authors mention standard Rails helpers and provide an example for writing a custom helper. It is when it came to the templating mechanisms called Layouts and Partials and Form Builders (another Ruby-based mechanism encapsulating the rendering logic) that I started gasping for air. After a Form Builder sample, when the authors suggested that "this code looks a bit tricky, but what it does is not that complex", I was completely lost. On the plus side, the "tricky" Form Builder helped achieve an "enormous improvement in readability" of the .rhtml form, so, I guess, it was worth it.
The remainder of this very dense chapter introduces such variety of topics as an alternative templating language (Markaby), caching mechanisms in Rails, enhancing Rails web pages with Ajax (which could be a subject of an entire book), Rails JavaScript (a code generator converting Rails code against a page object to JavaScript), Selenium - an browser-based IDE for recording and executing black-box test of Rails applications. The authors summarize the chapter describing Rails approach to views as "Ruby-centered simplicity" contrasting it with Java, where building views requires knowledge of multiple technologies.
This chapter tackles a subject dear to the heart of every Agile developer. The chapter is very readable since it covers a narrower set of topics, addressing each with greater deliberation. Ruby's approach to unit testing is similar to that of Java. Unit tests are classes extending a TestCase class (part of Ruby standard library) and consist of lifecycle methods (setup and teardown) and test methods. Assertion methods are also used for logic validation. What is different is the testing infrastructure generated automatically along with the Rails application. It includes tests for model and controller classes, fixtures (sample test data), an automation tool, rake (similar to Ant) which includes number of tasks for running tests. Ruby allows the user to generate three types of tests: unit tests (for model classes), functional tests (for controller classes) executing Web request-initiated processing and integration tests, which may cover processing associated with a complete application test case (e.g., user login). The chapter provides good coverage for functional and integration tests doing walk-throughs of sample application tests of appropriate types. The remainder of the chapters is dedicated to more advanced test-related subjects such as code coverage (rcov tool) and usage of mock and stub objects (flexmock gem) to reduce dependencies between the components being tested.
From the beginning of the chapter I was given yet another reason why developers find it easy programming Ruby after living for years in the Java world. This chapter discusses Ruby automation tool, rake, a counterpart of Java Ant. The two things that set rake apart are the fact that rake uses Ruby as a scripting language and the fact that the Rails application is generated with a rakefile (think build.xml) already in place. Ant requires you to learn a new XML-based language for writing Ant scripts. I find it very cumbersome adding logic to Ant by either using <if>-like tasks or by writing new tasks in Java and then integrating them with Ant. Extending rake is easy since it requires the language a Ruby developer already knows and the full power of Ruby can be used to write new rake tasks. And as far as the generated rakefile goes, the authors claim that for simple application one may not have to write a single line of rakefile. The chapter illustrated rake task writing with several examples. At the conclusion of the chapter the authors discuss the use of continuous integration tool called Cerberos.
"Creating and Invoking Web Services" chapter continues the saga of the simple ways used by Ruby designers to support sophisticated enterprise services. Predictably, the authors start the discussion of web services not with SOAP-based, but with much simpler RESTful services. In the example, the authors generate REST scaffold for a single Ruby entity allowing the entity controller to respond to two types of requests, HTML and XML-based. The same generated endpoint responds with its HTML and XML representation depending on the request type. Consuming REST services appears to be as easy with ActiveResource API.
In the section dedicated to SOAP web services the authors take a lighthearted jab at Axis-based Java web service implementation by contrasting it with that of Ruby. After the service implementation is written, Java version in their estimation requires 5 steps and more than a 100 lines of code to publish the method as a web service. Ruby's version requires a single method call in the implementation class allowing convention (not configuration) to take over. A simple example of consuming SOAP web services in Ruby using a build-in tool soap4r follows.
The rest of the chapter discusses YAML - a much simplified version of XML used by Ruby for data representation; XML parsing in Ruby using REXML, which supports SAX-, StAx and DOM-style parsing; XPath support (including an interesting discourse on why Java APIs use abstract factories, while Ruby uses direct calls to object constructors); and Building XML with Builder library (builder concept is also central to Groovy language), where missing_method() idiom allows for much more natural code for creating XML documents. The chapter conclude with a handful of medicinal recipes for avoiding headaches in dealing with data representations (first of which, curiously, to "prefer Java for Big XML Problems").
The Java - Ruby "match" ends with a security "shoot off". You probably won't be shocked to learn that Java (represented by Spring Acegi framework) scores high marks for power and flexibility, while Ruby (represented by acts_as_authenticated and Authorization plug-ins) gets points for simplicity and using convention over configuration. The chapter explains the basic tenets of authentication and authorization and describes the ways to configure those services in typical Java and Rails web applications. Having introduced the basics of web application security, the authors move to the topic of modifying Ruby tests to work in a secure environment (surprisingly that proved to be a verbose undertaking requiring whole new 5 lines of code in test classes). With apologies to David Letterman, the chapter concludes with a discussion of "Top Ten Web Security Flaws" covering the ways to make your web site better protected agains malicious attacks.
The dictionary "translating" terms familiar to Java Developers in Ruby parlance concludes the book. In the PDF version of the book, I reviewed, the dictionary was surprisingly small (just over a dozen entries). Hopefully, it will be fattened in the published version of the book.
Bruce Tate in "Beyond Java" argued that Ruby is a worthy (and timely) successor to Java and that it would behoove Java developers to get familiar with the language. The "Rails for Java Developers" book makes this transition smoother than a typical introductory Ruby or Rails volume would. The appeal of the book to the intended audience is in its consistent use of analogies between Java and Ruby/Rails in exploring most of the aspects of the latter environment. The strength of the books is also its weakness: you are unlikely to become proficient in Ruby using this book alone. It will give you general appreciation of Ruby and Rails concepts, which can be then turned into more intimate language knowledge with the help of Ruby and Rails tutorials. If you are thinking of transitioning from Java to Ruby (or simply want to find out what all the fuss surrounding Ruby is about) I would heartily recommend this book.
| Relevance | |
|---|---|
| Readability | |
| Overall | |
Additional reading suggested by the book authors:
David Thomas, et al. Programming Ruby: The Pragmatic Programmers' Guide.
David Thomas and David Heinemeier Hansson. Agile Web Development with Rails.
Bruce Tate. From Java to Ruby: Things Every Manager Should Know.
A comparison of the Hibernate and ActiveRecord technologies from The Server Side:
http://www.theserverside.com/tt/articles/article.tss?l=RailsHibernate.