Evaluation: moving from Java to Ruby on Rails for the CenterNet rewrite
This document was written by me (Rick Bradley) as part of our IS Applications group’s process of (re)evaluating platforms for deployment of a large-scale healthcare application (“the CenterNet rewrite”—discussed on the Rails mailing list). This evaluation document was prepared in September of 2005 and is therefore already out of date technologically—a number of the perceived shortcomings of Ruby On Rails have been eliminated, alleviated, or mitigated. For instance, we found to our surprise that it was trivially simple to deploy Rails on Windows and to automate build and testing.
Later additions to the document will be in highlighted type. Feel free to redistribute this document freely in whole or in part.
The Ruby on Rails framework is an open-source web application development framework developed initially by David Heinemeier Hansson at 37signals in Chicago while working on the BaseCamp productivity application. The framework uses the popular Model-View-Controller paradigm for separation of concerns in application development. Ruby on Rails is written in the highly-dynamic open-source object-oriented Ruby programming language, developed in the early 1990’s in Japan.
There are a number of notable upsides to moving CenterNet development from our Java development stack to the Ruby on Rails framework:
- Vastly reduced code footprint: We have read our Fred Brooks and respect the fact that there has never been a “Silver Bullet”, and there is unlikely to ever be such. Rails is not a Silver Bullet. However, widely reported results place productivity increases over modern Java methodologies (e.g., J2EE, Struts, etc.) in the 6-fold to 10-fold range (with many of these claims coming from long-time Java luminaries). Preliminary tests by our Technical Lead put the code reduction for a normal module in our Java stack converted to Rails at roughly 20:1. Rails uses the dynamicity of Ruby to extreme advantage and produces 4GL-like effects without resorting to code generation techniques (which suffer from inflexibility post-generation). The reported productivity increases point as well to underreported problems in the industry: web development as a whole likely lags application development productivity significantly due to the relative youth of the paradigm (stateless, distributed, thin-client applications); and the Java development model for web applications is additionally verbose and needlessly complex. Arguably, Ruby derives much of its productivity benefits from its SmallTalk heritage, and many would view Rails’ productivity to be bounded from above by the productivity of SmallTalk. The Rails paradigm has inspired Rails-alike projects in nearly every modern web development language. Rails appears to remain more productive than even the most productive of these Rails-alikes, probably primarily due to Ruby’s suitability for speedy development in this one particular domain of web application development. In short, Rails leverages Ruby to bring web application development back closer to the productivity of productive non-web application development frameworks.
- zero configuration: Rails applications require a few lines of specification to identify each database connection you will use, as well as a line of configuration for each different type of routing you will use (typically 3-4 lines for an entire application). Both of these are necessary in any environment. By contrast, rather than the 20 or so lines required in a Rails application, typical medium-scale Java applications require thousands of lines of XML configuration, many of which are strongly-coupled across application layers.
- DRY principle: Simply put, “Don’t Repeat Yourself”. Rails embraces the DRY principle and strives to maintain orthogonality among concerns. This reduces coupling, which reduces maintenance cost (and increases maintenance and development productivity), and eliminates the “shotgun code smell” which pervades modern Java web development: when a change is made at one layer (for example, adding a column to a database table) changes propagate through code in other layers. A problem which had long been perceived as a shortcoming of the “model-view-controller (MVC)” architecture, shotgun code smell is exposed by Ruby on Rails to have instead been a problem with the language (Java) and frameworks in use to implement MVC.
- Rapid development methodology: Rails targets zero turnaround time development, where developer changes to the system are made instantly available for use and testing. Rails development eliminates the build cycle, the deploy cycle, and the container restart cycle. Java, at its best, only approaches zero turnaround time development, attempting to compile and deploy in the background with certain IDEs in certain environments. Ultimately, changes to configuration files such as those used by Struts end up causing container restarts which sap developer time.
- Single-stack application framework: Ruby on Rails includes all the components necessary to build complete web applications from the database forward (even including a pure-Ruby web server for those who wish to develop immediately without setting up a web server such as Apache or lighttpd), providing object-database linkage, a Model-View-Controller framework, unit and functional testing tools, out-of-the-box support for AJAX and stylesheets, support for multiple templating systems, multi-environment deployments, support for automated local and remote deployments (via the included Switchtower utility), inbound and outbound email support, web services support, etc. With Java, choices abound, and we have seen that there is actually too much choice: core architectural components in wide usage are being actively deprecated by their developers and well-considered choices made at one point in time are revealed to be dead-ends 6-12 months later. The Java web community is in a state of high flux, and the apparent direction that the community at large is taking appears to not bode well for the type of architecture we had envisioned.
- IDE automation not required: It is well-documented that much productivity in Java comes from the widespread use of tools to automate code writing and change. The “shotgun code smell” which permeates the Java web stacks is reigned in with editors such as Eclipse which support XDoclet annotations. The verbosity of Java Bean getter and setter methods (code which must be written to read and write every value accessible in a Java Bean object) is mitigated by editors which support hotkeys or other automation methods for creating those methods. Other tools (e.g. Middlegen) use known data to write code or verbose XML configuration files. Java is widely defended as “productive”, so long as the proper tools are in use to mitigate the impact of voluminous code and configuration data. The learning curve, however, for the use of these tools is high. Indeed, even the process of choosing which tools to use comes with a high research burden and high risk of abandonment (see above, under “Single-stack application framework”). It is this author’s belief that much of the research into annotations and Aspect-oriented programming is geared toward making the widely adopted Java language productive for developers and maintainers. In contrast, Ruby and Rails are terse and dynamic, support AOP-style separation of concerns (Rails also has AOP tools available, though not widely used), minimize configuration, and consequently are productive outside the use of code/config generators and IDE environments designed to minimize necessary (to Java) redundant typing. We have found Ruby to be extremely flexible in this regard, allowing us to quickly alter functionality without touching framework code.
- Dependency Injection (IoC): Dependency Injection (or Inversion of Control) is a pattern widely used in Java development to help streamline the process of connecting and/or replacing components and services inside an application. Java’s type system, as well as the abundance of components available (and, some would argue, the high degree of volatility in the availability of usable components) makes Dependency Injection a necessary technique. Dependency Injection is also useful in testing under Java’s typing system, where replacing components with stubs or mock objects can be cumbersome. There exist small Ruby libraries for implementing Dependency Injection, but Ruby’s dynamic nature and open typing makes Dependency Injection much less of a necessity than in the Java world.
- Open-source: Both Ruby and Rails are freely downloadable and redistributable open source products. While parts of our Java stack are open source (under licenses of varying flexibility), much of Java is encumbered by restricted licenses, despite Sun’s PR push to cast Java tools as “open source” software. A true open source language and framework provides an ultimate escape from both vendor lock-in and unpatched software defects: simply read the code and change things yourself.
- Database agnosticism: Rails supports a wide array of databases, including all the common production database platforms. Our high-level goal of maintaining database platform independence is supported by Rails. Later adopters wishing to customize CenterNet for use on other databases would not be hampered by our choice of Rails as a platform. We have had great success in developing, testing, and deploying Rails on multiple databases simultaneously—we are currently using PostgreSQL and Oracle.
- Web services support: Rails supports the most popular web services protocols, including XML-RPC, SOAP, and WSDL. Rails’ flexibility with regard to external APIs enables addition of further web services interfaces easily. The popular Rails weblogging software Typo serves as an open example of the ease with which new APIs can be added to Rails applications.
- Integrated unit and functional testing support: Our iterative development process for CenterNet relies heavily on the ability to build comprehensive automated tests. Testing in Rails is simple, well-documented, terse, and integrated into the Rails framework. Rails builds the necessary scaffolding for unit and functional tests automatically, and tracks test/code ratios automatically. Rails includes native support for mock object testing and database fixtures, streamlining out-of-container testing. Since Rails doesn’t require a heavy object container, the headaches of Java-style “in-container” testing are alleviated—allowing for faster http-level and in-browser testing. In contrast to Java, with its numerous heavy testing frameworks, where Java requires the absorption of entire 300-page texts for each layer of the testing hierarchy, everything one needs to know about Rails testing, which covers the same scope, can be learned from a couple of short chapters. The availability of ready testing has greatly eased our development and caught a large number of early defects which would have been difficult to otherwise exorcise.
- Production vs. Testing vs. Development: Rails enforces the concept of deployment environments. Rails comes stock with three environments: production, where caching and performance enhancements are enabled, code is assumed not to be under development, and developer information is not passed back to the end user; testing, where a volatile database is made available for the purpose of running test suites; and development, where performance enhancements are disabled, a development database is in use, developer tools and feedback are in force, and the emphasis is on agile development methodologies expecting zero turnaround time development. Selection of an environment is enabled through one master switch. Rails allows for any number of additional environments to be created, and setting up an environment is trivial (a new file with a few lines of configuration information). In contrast, while Java allows for distinguishing environments, tool support is lacking, and any configuration switch must necessarily touch numerous components in an application.
- MVC separation of concerns: Rails integrates the Model-View-Controller architecture in a lightweight manner. Separation of business logic from database logic and from user interface is handled cleanly, decreasing coupling and providing the benefits of orthogonality. The Java MVC architecture of choice, Struts—which is being deprecated by its author in favor of non-MVC “component” tools which are the current rage in the Java world—places heavy overhead on the developer creating the controller and action building blocks of the front-end, while the struts-config.xml XML configuration file is verbose, unwwieldy, untyped, and requires container reloads on changes, thwarting attempts at “zero turnaround time” development.
- Share-nothing horizontal scalability: While Rails benefits from increasing the horsepower of servers on which it runs, Rails is designed from a “share-nothing” mindset. Each Rails thread is self-contained horizontally (i.e., it shares nothing with other Rails threads), and vertically (i.e., it shares nothing with the web server or the database server). When deploying Rails for scalability it is typical to use lightweight high-speed server tools such as lighttpd and FastCGI to allow for cheap and easy horizontal scalability. Add more cheap commodity PC hardware and the application handles more load. Add memcached (essentially, a distributed memory cache on the local network) to some of those cheap systems and even the database tier is scaled cheaply and horizontally. Java also offers horizontal scalability—the baseline deployment being higher (Java + application server tends to have a heavy footprint), the configuration burden is typically higher than that for scaling Rails, and it is often harder to set up a Java framework in a “share nothing” manner.
- Memcached support: Rails provides integrated support for memcached, written by the developers at LiveJournal to allow them to scale their Perl+MySQL application to handle traffic loads on their 2.5M+ user base.
- Utilities: The Rails breakpointer allows developers to set a breakpoint in web application code, which is nothing revolutionary. What is impressive is that once this breakpoint is hit by the web application, the developer has a console available at that line of code where he can inspect and modify any and all Ruby constructs (including classes, methods, etc.), and then can send the application running from that point (tellingly, the breakpoint library’s source code is shorter than a typical Java Hibernate XML mapping file for a single database table). Additionally, there are tools for running short automation scripts at the model level, and even an interactive console for working with Rails models and model constructs. Java’s verbosity, typing, and compiled nature makes development of a comparable tool not only complex (if not impossible), but would make its use cumbersome.
- API stability: Rails is nearing its “1.0” release, which is not only psychologically important but acts as a milestone for API stability—major changes to the framework would be avoided in the 1.x series. After the publication of the Rails guidebook Agile Web Development with Rails, the Rails development team (including, most visibly, David Heinemeier Hansson) are on record with a commitment that they will not “break the book” on the road to 1.0. Essentially, the 1.0 APIs are here, with whatever modifications are necessary being backward compatible with those documented in The Book. Following the development of Rails since its first public release, this author notes that there have been very few incompatibilities introduced even from the earliest stages.
- Language stability: Ruby as a language is stable, with the language developers historically working hard to maintain backwards compatibility. Java, the language, has undergone significant changes with each point-release. The newest standard, Java 1.5 (or “Java5”) introduces annotations, generics, and other constructs which are significant language changes reportedly geared towards addressing shortcomings in the Java language. It is also worth noting that Ruby is of comparable age to Java (Ruby is about 2 years older).
- Project adoption of Ruby: The CenterNet rewrite project is already using Ruby for build automation dependency maintenance, dependency graph construction, and planning documentation. The CenterNet build will compile the Ruby interpretor (when necessary) to examine project dependencies and generate build, documentation, and planning artifacts. Additionally, Ruby has been used to prototype outcome charting for the old CenterNet system’s new Residential functionality. We have introduced Ruby on Rails to the rewrite project for rapid UI prototyping purposes, and it appears likely that it will be used in this role for the forseeable future.
- High-level adoption: There has been a repeated pattern of defection from Java to Ruby on Rails among the high-profile luminaries in the Java community. Typically, a high-level Java figure will encounter Rails, speak out against the claims of improvement over Java, learn more about Rails, spend some time developing with Rails, and then retract past opposition, and begin using Rails for new project development. There are numerous such accounts on the web, here are a couple of the more interesting ones, from David Geary and another (deep in the heart of a flame-war about one of David Geary’s earlier posts), from Bruce Tate. This defection pattern continues.
There are some important considerations to take into account regarding the adoption of Ruby on Rails at this stage in our project.
- EJB Remoting: Rails will not support EJB Remoting, a technology used to allow Java desktop applications to connect to server-side Java business objects. Note that EJB Remoting introduces non-trivial overhead, both during development and at run-time, and affects the granularity of the application’s API design as part of the necessary trade-off in achieving acceptable performance. While EJB Remoting would not guarantee a fluid and responsive Java-based desktop application lack of EJB Remoting support precludes such an application from utilizing the Rails back-end model objects. For remote access, Rails offers web services (SOAP/XML-RPC/WSDL) support, REST support, as well as DRb (“distributed Ruby”) support for CORBA-like Ruby object remoting, and Rinda namespacing for remote naming support (similar to JavaSpaces or Linda). JRuby, an early implementation of the Ruby language specification in Java, is not sufficiently advanced to run Rails under the JVM. At some future date JRuby may support running Rails applications, possibly providing an avenue for EJB Remoting around Rails model classes. In the near-term, use of Rails precludes tight integration with Java desktop applications.
- Commercial Support options: Commercial support options are vastly more limited in the Rails world than in (e.g.) the Java world. There are small vendors offering support for Rails, but nothing on the scale of JBoss, IBM, Oracle, etc. Open support (mailing lists, direct emails, IRC rooms, etc.) is typically quite friendly and useful, but cannot guarantee specific turn-around windows. Note that with hardware vendor support and database support that support in the Rails domain would be primarily for troubleshooting run-time application issues. Community support should be sufficiently comprehensive and timely for development-time Rails support.
- Youth: The Rails project is a young project—just over a year has passed since the first complete versions of Rails were released to the public. Rails is reportedly two releases away from the “1.0” version, an important psychological milestone. The Rails project lead has publicly stated a commitment not to deviate from the specifications published in “Agile Web Development with Rails”, the leading Rails guidebook. The development community around Rails is incredibly active, and the project has features and stability well beyond its years. This author’s personal opinion is that Rails provides a fit and finish much greater than most Java components available, with greater apparent likelihood of stability and coherent active future development.
- JBoss-style clustering: Rails does not use the JBoss application server model of application server clustering. While this author is not aware of any behaviors which would require this particular model of application server clustering, there remains a risk that Rails’ “share nothing” approach (coupled with the availability of clusterable synchronization systems such as memcached) would not support some required synchronization algorithm which larger servers such as JBoss support. Rails’ “share-nothing” model is geared towards horizontal scalability with a small footprint.
- Database restart: As we understand the current state of Rails database connection handling, it appears that a database restart would likely require refreshing database connections in the Rails application. This may imply an application server restart. It is not clear yet whether this is actually the case, nor whether this could be readily mitigated with a simple retry policy on DB connection failure. Note that connection pooling will be available as of the 1.0 Rails release (see Rails trac ticket #2162), which will likely eliminate this consideration. There is functionality in the trunk for Rails to automatically detect database connection drops and to automatically reconnect.
- Legacy database support: Active Record, the Rails object-relational mapper, is designed primarily to dramatically speed development on new database applications and works best when the schema is being developed concurrently with the application. This is a result of the “convention over configuration” mindset of Rails: when tables and relations in the database obey Rails-friendly conventions very little clarification takes place in the Ruby object model. As database constructs deviate significantly from the Rails conventions, more clarification declarations are required in the object layer. Active Record can probably handle nearly any database schema at a cost of increased clarification. Whereas Hibernate can handle anything, but imposes a high configuration, complexity and coupling cost on nearly all applications, Active Record can handle probably anything but only imposes high clarification costs on the most complex and unwieldy of database models.
- Two-phase commit: Rails does not (yet) support a two-phase commit, i.e., transactions across multiple databases. This is difficult to perform in Java as well, though not impossible (it should be noted that one of our paid Java consultants warned us against nested transactions, including two-phase commits, when using Java). In Rails you would need to write your own code to perform the feat, with Rails providing help with transaction primitives. We do not currently anticipate using a two-phase commit on this project.
- IDE environment: While there are a few IDE environments for Ruby and/or Rails, including FreeRIDE, Eclipse (with Ruby plugins), and others, Ruby/Rails IDE support lags behind that available in the Java world. Additionally, we spent non-trivial effort in bringing Eclipse online for use with our source-control repository (Subversion) and our Java stack (it could be argued, with less than perfect results). While Eclipse-Subversion integration would still function the same, Ruby tools in Eclipse or other IDEs would need to be investigated. While Eclipse provides refactoring support for Java, refactoring support for Ruby is known to be less pervasive—FreeRIDE probably has the best refactoring support at the moment, which is still labeled “experimental”. Some of our developers have had good success with ArachnoIDE, and it is worth noting that Komodo by ActiveState is actively being pushed for Ruby and Rails development. I’ve also heard recommendations for the jEdit Ruby Editor Plugin.
- Library support: While Ruby library support is extensive, this shortfall is often cited as a downside in Ruby. In contrast to Java, Perl, C++, and other popular environments, there are fewer code libraries available for use with Ruby. Currently we do not know of any specific needed libraries which cannot be found for Ruby already, but there is the possibility a future requirement will not meet an existing Ruby library. On the upside, as this witty SlashDot commenter noted, “Do you need [to extend] your languages with external C libraries? You will positively, absolutely [....] yourself three times when you try out Ruby/DL, which lets you extend Ruby with arbitrary C libraries at run time without any compiling or setup.”. The veracity of this claim is under active consideration at the time of this writing. With the exception of a clean IRC library to do continuous integration notices to an IRC channel we have thus far found no gaps in library coverage while using Ruby.
- Typing: Ruby is an untyped, dynamic OO language. A strong argument can be made that Ruby’s classes comprise a type system, but the practical distinctions are that (1) the Ruby interpretor will not catch certain errors that typed languages would catch earlier, and (2) less code needs to be written to express a construct in Ruby than in some typed languages (especially including Java). Note that Java is poorly-typed: the typing system is inconsistent and the language often forces casting and broadening of types during use. The predominant Java web development paradigm immediately dispenses with the most useful broad classes of typing, placing the preponderance of configuration in untyped XML files. While it would be nice to have type-informed tools to identify errors in Ruby programs, the state of affairs in the Java world is effectively equivalent—the most pervasive and insidious errors lie well outside the Java type-checker in the abundant configuration files in modern web applications. Readers have pointed out (rightly) that Ruby is not “untyped”. Consider that a typo. Ruby is typed for your favorite (non-”strongly”) value of . These days I’d probably go with “duck”.
- Confused i18n support: Currently, though Ruby was born in Japan, the internationalization (i18n) support, while present, is somewhat weak. There are multiple i18n approaches for use with Rails and it is not clear at the moment which of these is preferred. Ruby has had an off-on relationship with Unicode. Purportedly things are working properly but this author suspects it takes non-trivial effort to do i18n in Ruby still. Java, on the other hand, is quite strong in the area of i18n. Currently, i18n is not a motivating concern for the CenterNet rewrite project.
- Windows build automation: Ruby and Rails work across platforms, but in varying manners and with varying degrees of installation headache. Setup on OS/X using Locomotive is unbelievably simple to use. Setup on other Unix installations requires more work, primarily in getting the proper dependencies together, but the process is automatable and not overly complicated. Under Windows the process is relatively straightforward (see this page) and includes the use of a “single-click installer” for Ruby, but the process appears difficult to automate completely under Windows. This implies that we can use Windows for a developer platform but likely not for a server or continuous integration platform. We had already accepted that as a limitation of our Java build for different but similar reasons. While we are not deploying our primary continuous integration server on Windows (why waste all those cycles painting widgets?), after some experimentation it’s clear that it would actually be very simple to deploy continuous integration on Windows. Go figure. Also, there is a very simple windows Rails setup tool now available called Instant Rails.
- In-house experience/retraining: When this author was approached about this project, one of the constraints placed on platform and framework selection was the in-house availability of experienced Java programmers. We have 3 experienced Java developers on the team, and only one experienced Rails developer on the team (who will be playing a management role and hence would be unavailable for heavy development work). The technical lead is currently learning Rails for prototyping and has covered significant ground. The other two Java developers have expressed a strong interest in switching to Ruby on Rails instead of continuing development in Java. There would be downtime and a learning curve involved in learning both Ruby the language and Rails the framework. It is this author’s belief (as well as the technical lead’s belief) that the learning curve for Ruby and Rails is easier than the curve to learn the necessary productivity techniques for the Java stack to be workable. Our developers have come up to speed very rapidly, writing models, views, controllers, AJAX widgetry, and unit/functional tests with little difficulty. They are surprised at how little complexity there really is. The only topic which still remains “advanced” is modification of the functionality of the framework itself, which takes some work to get ones head around.
- Build conversion: The automated build system uses Java Ant tasks to build and deploy the current portions of the CenterNet application, as well as to run CruiseControl continuous integration. We would wish to change from Ant to Rake (the Ruby build tool) or even vanilla Make instead, as Ant’s integration with Ruby tasks is lousy, and Ant’s general configuration overhead is quite high, being an XML configuration-based tool with tasks for defined operations, restricted flexibility for conditional execution, a cumbersome “properties” model, etc. We would probably lose some power and portability at the outset but would expect to gain that back once our build had time to evolve. CruiseControl continuous integration would likely be switched at some early point to DamageControl (both are projects supported by CodeHaus, the open-source extension of Thoughtworks), a ruby-based continuous integration framework. It is not clear at this point in time how much effort that conversion would cost. We ended up using the simple continuous_builder plugin from Rails to do our continuous integration. It was quite trivial to set up and does exactly what we need. Also, it’s been brought to my attention that CodeHaus != Thoughtworks, even though there is apparently a lot of Thoughtworks pollen that blows through the CodeHaus—so, sorry for the confusion.
- Hiring: A common warning against the adoption of Ruby and/or Rails is that the Ruby job market is dwarfed by the job markets of more mainstream technologies such as Java, and, consequently that Ruby programmers are going to be scarce as well. There is merit to this warning, but it is also misleading. On the one hand, there are jobs available for Ruby and Rails (more so every day), and there are highly skilled developers working on the Rails platform. In a very real sense the early adopters of Rails are more likely to be highly qualified developers than the middle-of-the-road Java developer—they are also likely more entrepreneurial (for better or for worse) and may be more abreast of cutting-edge technologies (they may also be dilettantes or perhaps merely flighty fad-chasers). Regardless, our view on hiring has been that we are not seeking “Java guys” or “C++ programmers” but, rather, smart people who can adapt well to change and solve difficult problems intelligently. Our current developers have shown flexibility and no fear of moving to a “better” platform to get the job done. We wish to hire more like them. The fact of the matter is that these sort of good people are hard to find no matter where you look (Java world or non-Java world), but seem to this author more likely to be looking for work on a new and productive platform like Rails than a heavy and over-established platform like Java. In short, we’ve always been in search of smart people and the size of that population doesn’t change significantly from one day to the next. After a quick trip to RubyConf2005 we’ve found that there are quite a number of enthusiastic and talented developers looking for projects using Ruby and Rails. Over half the room at the conference raised hands to admit they were working with Java and wanting to work instead with Ruby. We will likely pursue hiring some of our new-found Ruby-enthusiast friends in the near future. I’ve personally found it’s much easier to find the “smart people” we’re looking for in the Ruby community since the community seems to be self-selecting the smart folks—that is, that the likelihood some random person I run into in the Ruby community is highly experienced, smart, and adaptable, is much greater than the likelihood of saying the same with people selected at random from, say, the Java community. Make of this one man’s opinion what you will.
- Code conversion: The bulk of our effort to this point in the CenterNet project has been spent in design work, data modeling, build automation, documentation, dependency analysis, tool building, and exploration. Of the coding which has been undertaken to date some portions can be kept under a platform switch, while other portions would be discarded. SQL scripts, conversion scripts, test data would all remain the same. Hibernate mapping files would be discarded, with very little effort required to duplicate their functionality in Active Record—at a great savings in mapping elimination, and significant decoupling. Java code generated from Hibernate mappings would be discarded, but replaced trivially in the same terse Active Record model objects which replaced the Hibernate mappings above. EJB code, which is small in quantity would be replaced with Ruby business objects which should be even more terse—the API design work would still be of value here. The Struts controller/action/view code would be discarded, with JSP templates being converted over to the more terse rhtml templates and partials (and layouts) that Rails uses. This would result in up-front loss of effort, sinking additional effort into realizing those views/controllers/actions in Rails. Bringing our Struts code up to full functionality using AJAX appears to this author to require at least as much effort as converting the view and controller implementation to Rails (ignoring retraining effort which is hard to quantify currently). The Rails view-controller code is more decoupled, more terse, and more reusable than its Struts equivalent.
- Reporting Library: Ruby doesn’t offer an off-the-shelf reporting tool (to our knowledge). While direct-from-database reporting is certain to be a requirement, it would be nice to have a Ruby package which could do reporting similar to off-the-shelf Java tools. There is nothing preventing us, however, from using off-the-shelf tools of any type to report direct from the database.