Skip to main content

Crossing borders: Web development strategies in dynamically typed languages

Beyond JSP

Bruce Tate (bruce.tate@j2life.com), President, RapidRed
Bruce Tate
Bruce Tate is a father, mountain biker, and kayaker in Austin, Texas. He's the author of three best-selling Java books, including the Jolt winner Better, Faster, Lighter Java. He recently released Beyond Java.. He spent 13 years at IBM and is now the founder of the RapidRed consultancy, where he specializes in lightweight development strategies and architectures based on Java technology and Ruby on Rails. 

Summary:  The Java™ community has used JavaServer Pages (JSP) technology through most of the last decade, but signs of rust are starting to show. Longstanding conventions inhibit Java programmers from using Java code within Web pages now, and extending even simple components is a chore. Frameworks that take Java Web development beyond JSP programming have emerged, but they fall short of dynamic languages' capabilities. This article shows you Ruby's Web page development strategy and touches on Seaside's radical approach.

View more content in this series

Date:  05 Jul 2006
Level:  Introductory
Activity:  3735 views

In the early years of Java Web development, Sun and Microsoft battled for control of the de facto standards for building dynamic Web pages. Sun introduced the Servlet API. With a servlet, you can leverage all of the Java language's capabilities to get a Web page up quickly. The ability to compile servlets and the availability of a free servlet container implementation (Apache Tomcat) made servlets tremendously popular. To compete, Microsoft introduced an API called Active Server Pages (ASP). The technology was approachable: You could ramp up quickly and create much more advanced Web pages, including ones with database backing or other kinds of dynamic content.

About this series

In the Crossing borders series, author Bruce Tate advances the notion that today's Java programmers are well served by learning other approaches and languages. The programming landscape has changed since Java technology was the obvious best choice for all development projects. Other frameworks are shaping the way Java frameworks are built, and the concepts you learn from other languages can inform your Java programming. The Python (or Ruby, or Smalltalk, or ... fill in the blank) code you write can change the way that you approach Java coding.

This series introduces you to programming concepts and techniques that are radically different from, but also directly applicable to, Java development. In some cases, you'll need to integrate the technology to take advantage of it. In others, you'll be able to apply the concepts directly. The individual tool isn't as important as the idea that other languages and frameworks can influence developers, frameworks, and even fundamental approaches in the Java community.

Enter JSP technology. JSP was designed to compete directly with ASP (as the name implies). With JSP, you can build a Web page using tags and drop Java code directly into that page. The JSP container compiles the JSP file into servlet form. The servlet engine can then execute that page just as it can any other servlet. Both JSP and ASP implement a template-based approach. Templating lets you build a simple Web page as you expect it to appear in the user's browser. You can then replace simple placeholder elements with values, components, or structures that become part of the page when the template engine processes them. Although the Java platform has many general-purpose template engines, JSP has accumulated dominant market share, in part by converting many ASP developers.

But some other languages handle Web development much better than either the Java language or ASP. A look at competing approaches in dynamic languages gives you more context to evaluate what's available on the Java platform. In this article, I discuss how code generation works in Ruby, and I delve into a more radical component-based approach in Seaside.

Ruby templates

Ruby templates rely on simple capabilities in the language to provide a simple but effective approach for Web page development. You can rapidly understand Ruby templates by grasping a few layered concepts, with each layer more powerful than the last.

The most basic part of a Ruby template is a String. A Ruby string is a first-class object. When you create a string in Ruby, you can surround it by either single or double quotes. Listing 1 shows examples of three different commands you can type in a Ruby interpreter to create strings:


Listing 1. Creating a Ruby string

irb(main):001:0> "This is a string.".class
=> String
irb(main):002:0> 'This is also a string.'.class
=> String
irb(main):003:0> String.new('This is yet another string.').class
=> String

Ruby does not process any data in a string if you wrap it in single quotes. If you wrap a string in double quotes, Ruby makes a substitution pass through the code. Listing 2 shows an example of using a newline character. With single quotes, Ruby leaves the newline alone. With double quotes, Ruby interprets the newline:


Listing 2. Single versus double quotes

irb(main):004:0> puts 'Use \n to specify a new line in Ruby.'
Use \n to specify a new line in Ruby.
=> nil
irb(main):005:0> puts "A \\n causes a line break \n like this."
A \n will cause a line break 
 like this.
=> nil

With the second puts statement (puts stands for put string), Ruby processes two substitutions. A single \ followed by a character represents special characters not on the keyboard, such as \n for newline. A \ preceding a character with special significance, such as backslash itself, escapes the character as it does in the Java language. So, Listing 2 processes both the \\ and \n substitutions.

A more interesting substitution command is #{any_expression}. If you use double quotes around a String that contains such a command, Ruby returns the string, replacing the #{any_expression} with the value of any_expression. Listing 3 shows an example:


Listing 3. Simple variable substitutions

irb(main):006:0> name = "Elvis"
=> "Elvis"
irb(main):007:0> puts "Your name is #{name}"
Your name is Elvis
=> nil

You already have most of what you need for a primitive template. One final trick completes simple template processing. You can delay binding by using a #{} substitution in a string with single quotes. Later, you can bind the template to variables whenever you like, by wrapping the template in double quotes and calling the eval() method, as in Listing 4:


Listing 4. Delaying binding

irb(main):008:0> template = 'Your name is #{name}'
=> "Your name is \#{name}"
irb(main):009:0> name = gets
Elvis
=> "Elvis\n"
irb(main):011:0> puts eval('"' + template + '"')
Your name is Elvis
=> nil

Notice that template exists before the code initializes name. You could easily use this simple template strategy to process very simple Web pages, but usually you'd need more. The ability to include simple coding structures, such as looping for tables with dynamic data, forms the backbone of most dynamic Web pages.

Embedding code with eRuby

The typical approach to embedding Ruby code into an HTML page, including the approach used in Rails, is a filter called eRuby. Several implementations exist, including a Ruby-based implementation called ERb and a faster, C-based implementation called eruby (see Resources). Either would work as Web server plug-in, but you'd typically use ERb for conveniently processing local files and eruby when you need more speed, such as with your production Web server. The eRuby filter processes a text file, leaving everything intact with three exceptions:

  • Text between <% and %> is Ruby code. eRuby executes it as is.
  • Text between <%= and %> is a Ruby expression. eRuby executes it and replaces the whole expression with the value returned by the expression.
  • Everything on a line beginning with a single % is executed as Ruby code.

For example, consider Listing 5, a file called test.rhtml. (The .rhtml extension is the convention for files containing HTML, marked up for eRuby.) Listing 5 uses both Ruby code and expressions. Notice the text in the body of the do loop:


Listing 5. A simple rhtml file

<% 4.times do |i|%>
  <h1>This code is inside the loop.</h1>
  <p>This line is pass number <%= i %> through the loop.</p>
<% end %>

To execute the code, you simply run it through ERb, as in Listing 6:


Listing 6. Processing a file with ERb

  > erb test.rhtml

   <h1>This code is inside the loop.</h1>
   <p>This line is pass number 0 through the loop.</p>

   <h1>This code is inside the loop.</h1>
   <p>This line is pass number 1 through the loop.</p>

   <h1>This code is inside the loop.</h1>
   <p>This line is pass number 2 through the loop.</p>

   <h1>This code is inside the loop.</h1>
   <p>This line is pass number 3 through the loop.</p>


Invoking the template

Ruby is one of a set of languages for doing LAMP-based Web development. LAMP stands for:

  • Linux
  • Apache
  • MySQL
  • An open source P-language: Python, Perl, or PHP. (Ruby is an honorary P-language; just ignore the kickstand.)

With LAMP, you typically serve a Web application through simple operating-system scripts, using a framework such as the Common Gateway Interface (CGI).

eRuby effectively raises the level of typical CGI-based programming. As you might expect, you can plug ERb (or the C-based eruby equivalent), right into the Apache HTTP server and invoke Web pages. You then have the Ruby equivalent of a Java servlet. But new frameworks often invoke ERb as a Ruby library. If you want to create a Ruby template from within an API, you could use a modified version of Listing 5, shown in Listing 7:


Listing 7. Running ERb templates within a Ruby application

require 'erb'

template = ERB.new <<-EOF
<% 4.times do |i|%>
  <h1>This code is inside the loop.</h1>
  <p>This line is pass number <%= i %> through the loop.</p>
<% end %>
EOF

puts template.result

By executing the templates in this way, you expose the full power of the Ruby programming language to your templates. You can then enable seamless refactoring between code in your templates and the code in the remainder of your application. For example, you could create a helper that builds simple tables based on the contents of a hash map, as in Listing 8:


Listing 8. Extracting a helper

require 'erb'

def table_helper(map)
  body = map.collect do |item|
    "<tr><td>#{item[0]}</td>
     <td>$#{item[1]}</td></tr>\n" 
  end
  return("<table>\n#{body}</table>")
end  

map = {
       "Peaches" => "1.95", 
       "Apples" => ".95"
      }

template = ERB.new <<-EOF
<p>Here's our price list</p>
<%= table_helper(map) %>

EOF

puts template.result


Listing 8 shows a helper that creates a table, given a hash map. The example then declares a hash map and a template and then uses the two together. (You would typically include this template in a separate file; I included the template in-line just to keep the listing simple.) Notice that you're naturally extending the capabilities of the template system, based on the capabilities of the Ruby programming language. This example combines the ERb-style substitutions with the primitive Ruby string substitutions provided with simple strings. Ruby on Rails combines these substitution styles in several compelling ways:

  • Rails partials enable small subforms for better reuse and organization.
  • Rails layouts enable reuse of common elements for all pages, including headers, menu bars, and copyright information.
  • Rails helpers, similar to the helper you see in Listing 8, make it easy to simplify and reuse portions of views.

In fact, the Rails design offers an easy way for users to contribute libraries that use JavaScript to render complex features, such as Ajax elements, tree controls, or pop-up menus. The Rails community provides helpers that go far beyond the basic capabilities of Rails itself.


The Seaside strategy

Seaside, a framework for developing Web applications in Smalltalk, is an example of an HTML-rendering strategy that doesn't use traditional templating. Today, Web designers place a greater emphasis on styling through a strategy called Cascading Style Sheets (CSS) (see Resources). With CSS, you can build all styling information, including rendering location, color, background, and font, in a template-friendly language. Seaside leans heavily on CSS for styling but does not use templating at all to render basic components.

In Seaside, each component knows how to render itself. At its most basic level, a component simply prints the basic HTML tags and any dynamic content necessary to render the component. For example, Listing 9 defines the renderContentOn method to create a simple Seaside counter:


Listing 9. A simple Seaside component

renderContentOn: t1 
   t1 heading: count.
   t1
      anchorWithAction: [self increase]
      text: '++'.
   t1 space.
   t1
      anchorWithAction: [self decrease]
      text: '--'

In Listing 9, t1 heading: count. renders a heading with the content in the instance variable count, which contains the value of a simple counter. Then, the code renders a link, called an anchor in Seaside terminology, containing the text '++' and invoking the increase method. Finally, the code renders a similar link for a decrease method. Figure 1 shows a Web page containing the counter that Listing 9 renders:


Figure 1. A simple Seaside component
figure

Components with more complexity can ask subcomponents to render themselves. With this approach, Seaside can produce remarkably sophisticated components with minimal effort. For example, a table could render a collection of rows that could in turn render a collection of cells. Listing 10 shows an example of a complex component:


Listing 10. A more complex Seaside component

renderContentOn: t1 
   counters
      do: [:t2 | t1 render: t2]
      separatedBy: [t1 horizontalRule]

The code in Listing 10, which renders an array of counters, iterates through a collection of containers, calling the render method on each one, and separating each counter with a horizontal rule. You can see the result in Figure 2:


Figure 2. An array of Seaside counters
figure

Seaside's model doesn't use templates but makes it possible to build extraordinarily powerful Web pages with complex interactions by relying on each individual object to render itself. Seaside relies on stylesheets to maintain a good relationship between designers and programmers. Layering, layouts, backtracking, and styling are all trivial in Seaside.


Beyond JSP

In an excellent article he wrote six years ago, Jason Hunter spells out JSP's shortcomings (see Resources). I'm paraphrasing:

  • JSP is more difficult than it needs to be.
  • Looping is difficult.
  • Error messages are unfriendly.
  • It's too hard to strike a good balance between the programmer and designer.

Over the years, Java programmers have come up with practices and frameworks that address these limitations. The JavaServer Pages Standard Tag Library (JSTL), a custom-tag system for JSP programming, seeks to make it easier to break code out of JSP files and put it into shared libraries. But that tag system is more complex than it needs to be. It's too tempting to insert Java code directly into Web pages, so Java Web page developers resist the temptation by avoiding all code like the plague. Several frameworks built on top of JSP technology strive to simplify it. Newer frameworks have tried to improve the Java Web development experience. For example, JavaServer Faces (JSF) endeavored to reinvent Struts -- but it initially mandated JSP (against the advice of some experts).

In the past few years, some innovative frameworks that don't depend on JSP have begun to emerge. By relying on a simpler templating philosophy (and one much closer to pure HTML), RIFE, Wicket, Spring Web MVC, Tapestry, and several others all claim to provide a much simpler strategy for integrating components (see Resources). They all let a Web designer use native design tools rather than tools customized for JSP programming. This direction is healthy for the Java language. Still, other languages such as Ruby handle Web development much better than Java technology.

One possible strategy that combines the richness of Java's enterprise capabilities with the simplicity of a dynamic language is to use an embedded virtual machine. According to JRuby lead Thomas E. Enebo, developers are already working on a servlet letting in-line Ruby code allow Ruby-style Web pages. In many ways, this approach would give you the advantages of both worlds.

I hope you've gained an appreciation of some ways other languages render Web pages. Next time, I'll look into different ways to approach common problems using functional languages.


Resources

Learn

  • Beyond Java (Bruce Tate, O'Reilly, 2005): The author's book about the rise and plateau of the Java language and the technologies that could challenge the Java platform in some niches.

  • "The Problems with JSP" (Jason Hunter, Servlets.com, January 2000): A time-honored article about the problems of JSP technology.

  • Ruby: An excellent language for expressing templates.

  • Seaside: This framework allows you to develop sophisticated Web applications in Smalltalk.

  • Cascading Style Sheets (CSS): A mechanism for adding style elements such as fonts, colors, and spacing to Web documents, is developed by the World Wide Web Consortium.

  • ERb: A Ruby class for processing CGI scripts, can also be used from within Ruby applications to translate Ruby templates.

  • eruby: An eRuby implementation written in C.

  • From Java To Ruby: Things Your Manager Should Know (Pragmatic Bookshelf, 2006): The author's book about when and where it makes sense to make a switch from Java programming to Ruby on Rails, and how to make it.

  • Programming Ruby (Pragmatic Bookshelf, 2005): A popular book on programming Ruby.

  • RIFE, Wicket, Spring Web MVC, Jakarta Tapestry: Java Web development frameworks that use a templating strategy.

  • JRuby: JRuby is a 1.8.2 compatible Ruby interpreter written in 100% pure Java.

  • The Java technology zone: Hundreds of articles about every aspect of Java programming.

Get products and technologies

  • Ruby: Get Ruby from the project Web site.

  • Ruby on Rails: Download the open source Ruby on Rails Web framework.

  • Seaside: Download the radically different Smalltalk Web framework.

About the author

Bruce Tate

Bruce Tate is a father, mountain biker, and kayaker in Austin, Texas. He's the author of three best-selling Java books, including the Jolt winner Better, Faster, Lighter Java. He recently released Beyond Java.. He spent 13 years at IBM and is now the founder of the RapidRed consultancy, where he specializes in lightweight development strategies and architectures based on Java technology and Ruby on Rails. 

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Web development
ArticleID=144929
ArticleTitle=Crossing borders: Web development strategies in dynamically typed languages
publish-date=07052006
author1-email=bruce.tate@j2life.com
author1-email-cc=bruce.tate@j2life.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers