SHRT = Semi-Humorous Random Thought
Here's the deal: Cocoon is a very powerful publishing framework adapted
to do web applications, and Ruby on Rails is a very empowering web
application framework that can be adapted for a number of purposes.
There are two very different mindsets behind the two frameworks--and I
believe we can leverage the very potent lessons learned from Rails for
the Cocoon framework. The only real humorous aspect of this post is the
acronym I came up with above. In one summary statement:
CRACK: A highly adictive web framework that is very potent. Side
affects include loss of weight, faster completion, and eagerness for
more. Best selling point: seeing the reaction of saying your a "CRACK Ho".
In all seriousness, the biggest lesson from the Ruby on Rails project
that Cocoon can learn is the power of convention. One of the biggest
things that contributes to the high learning curve of Cocoon is the lack
of convention. Because there are so many ways of doing things, the user
has to learn all of them to determine what is going to be best for the
project the user is working on. I belive that this lack of convention
is even a bigger contributor than all the different XML standards that
we integrate. A long time ago Stefano gave the RT on the URL as a
contract--and rightly so. The Sitemap was born of that RT allowing
Cocoon to respect the external contract and the developer to organize
the filesystem any way they chose. The Rails solution to the problem is
the convention of the MVC architecture is also mapped in a logical way
to the files and class structure. Let me lay out the convention used:
Controller
----------
Rails has a definite mapping of the URL to a controller. The convention
is {context}/{controller}/{action}[/{id}] where {context} is the
location where the app is running, {controller} is the controller class
that responds to actions, {action} is the method on the controller class
that is called to process a request, and {id} is an optional piece that
identifies a specific record. The controller class is defined in the
app/controllers/ directory and has a naming convention of
{name}Controller. For example a "Login" controller would be named
"LoginController". Rails finds the controller based on the URL. Once
Rails has the controller it calls the method matching the action. One
of the side effects is that the URL does not have any extensions defined
(i.e. there is no .html or .pdf in the URL). The job of the controller
is to do any set up for the request before it allows the action to "fall
through" to the matching view.
Model
-----
The Rails model is one of the most powerful aspects of the whole
framework. I'm not going to go into the whole ActiveModel architecture
other than to say that the model lives in the app/models/ directory and
the class name is the singular form of the concept (i.e. LogEntry) and
the backing database table is the plural form (i.e. LogEntries). Using
convention to map class methods to tables and records is a very powerful
aspect that beats out anything else in the Java world. It would be a
project in and of itself to write a replacement for this piece--which is
not something I would recommend for CRACK.
View
----
The Rails view lives in app/views/{controller}/{action}. That's right,
there is a mapping of a set of views directly 1:1 to the controllers.
In the case of the LoginController there would be an app/views/login/
directory, and for each action ("index", "login" etc.) there would be a
view that corresponds. In the Ruby on Rails world these are .rhtml
files so they are analogous to XSP or JXL files. In fact I would argue
that it is closer to JXL than XSP. Once the method in the controller is
complete, provided the controller did not explicitly send a named page,
the view is selected from this directory. In the CRACK version matching
the /login/index URL, we would look for (in this order) a .jx file, a
.xml file, or a .xsp file that matches the name of the action "index".
More clearly, in that example CRACK would look for
app/views/login/index.jx first, and then substitute the other extensions
in case they are there. The Rails view framework also allows fragments
that can be embedded in other views, but this is good enough for now.
Now, imagine a Cocoon scenario where the user is faced with a blank
project. Where to begin... Using the power of convention, they start
writing a class named HelloController.java located in the
app/controllers/ directory. They add one method called index() to the
class. Then they open the browser to
http://localhost:8000/cocoon/hello--at which point Cocoon compiles the
HelloController.java class and responds by processing the index() method
(oh yeah, forgot to mention the convention of the index method being the
default for any controller). The user sees an error message saying that
the view app/views/hello/index.jx could not be found. They realize,
"Oh, that must be where we process the view". They add the index.jx
file in the proper location and retry the URL. Success! Relieved and
happy with the results they start adding more and more functionality
until they have a wonderfully powerful application.
Where CRACK is Better
---------------------
Ruby on Rails is highly HTML centric. That's ok because 80% of all web
applications are HTML centric. However, we can leverage a convention
that they started in a more powerful way. In addition to the normal
View conventions, Rails also has the concept of a layout. You can apply
the same layout to all the views in your application. Now, remember
that I said that Rails doesn't support extensions (.html, .png, etc.).
We can set up a set of layouts that are essentially the finishing
pipeline for the application. By specifying a generic page markup we
can provide default layouts, but the convention would work like this:
* The layout has a base name such as "site" which is how the layout
would be specified in the controller.
* The XSLT layout naming convention would be {name}2{ext}.xsl, and we
would automatically select the serializer mapped to the {ext} name.
- Example: login/index.html using the "site" layout would transform
the standard markup using the "site2html.xsl" file and use the "html"
serializer.
- This allows us to also render a "site2pdf.xsl" using the "pdf"
serializer for /article/show/3.pdf
Changes to Cocoon
-----------------
In order to support something like this, we don't have to make
fundamental changes to Cocoon. In fact, all we have to do is provide an
alternate Sitemap implementation that uses reflection to find the
controller class and build the pipeline based on the view source, the
layout location, etc. One of the things that would also help _emensely_
is to automatically generate a 404 return response if there is no
Controller/Action match. There are other things that will help in the
process, but I believe this is a much more usable way to get baptised
into Cocoon--and still leverage its power. Because we would be using
convention to wire together an application, we have the power to even
build in some normal conventions for being browser aware by default. If
the end client's browser is smart enough to handle client side styling
then we can let it happen--with no more effort required by the developer.
Oh, and one more thing: we default to UTF-8 as the default encoding all
the way through. There are issues with the ESQL logicsheet introducing
encoding errors, and a few more other locations. Just because much of
the commercial industry seems to be ignoring internationalization does
not mean we should follow they poor example.
What do you think? Rosy picture? BTW, I only used the name CRACK as an
eye catcher--I'm not expecting the final product to be named that.