Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Alias (5735)

Alias
  (email not shown publicly)
http://ali.as/

Journal of Alias (5735)

Wednesday April 14, 2010
01:48 PM

Mojo vs Dancer Week 2 - Templates and Images

[ #40312 ]

Welcome back.

My apologies for the delay. I blame trying to keep up with the QA hackathon from half a world away, and another unavoidable event from which I could not escape.

I've also delayed another day because I'm a bit concerned that my review this week would paint Mojo in an unfair light, and I wanted to sleep on it.

As I get deeper into both, I'm finding that many things I don't like about one turns out to have a similar behaviour in the other. As a result, whichever one I review first would be the one that a stream of consciousness commentary will paint in a worse light.

And I've wanted to start each week with Mojo first, as the more established competitor. But I think this might be unfair given the emerging similarities.

So each week I will reverse the order I review them in, and this week I shall attempt to emulate finding my annoyances in Dancer first :)

This week, I had originally planned to look at configuration and database.

Like in many projects though, this turned out to be way too trivial because I'm basing the website on the CPANDB module, which is zero-configuration.

So in BOTH applications, I only had to add the following and I have my database layer finished :)

use CPANDB {
  # Don't check for updates more than once a day
  maxage => 86400,
};

Instead, I'm going to look at the second phase for most website projects as a newbie. Bootstrapping from helloworld.pl into an equivalent "proper" website with templates, images and CSS, but no actual content.

Dancer - Bootstrapping a website

Since my review last week, a couple of new releases of Dancer hit the CPAN claiming to fix installation on Win32. Just to prove it, I've done this week's testing on my conference presentation laptop instead of my desktop machine.

Dancer installed first time cleanly on the new machine. And the hello world script from last week runs correctly. So all good there.

After a more-complete-than-last-week read through the main Dancer search.cpan.org page one thing jumps out quite sharply about the Dancer API in general. And this is that it isn't object-oriented, which is something or a rare thing these days.

Or at least, it doesn't LOOK object-oriented. Judging from the distribution page there's plenty of classes and I'm sure the internals are all done largely in an OO fashion.

The main API that you get with "use Dancer" sports a similar kind of "Do What I Mean" command interface that reminds me a bit of the Module::Install command interface.

This means that the code to show the index template is going to look like this.

get '/' => sub {
    template 'index';
};

I'm not entirely sure what I think about this idea, despite the fact that I'm the maintainer of M:I and created it's Domain Specific Language inteface. This kind of thing usually raises red flags.

I can see this API strategy either descending into API chaos or becoming one of Dancer's best and most loved features. Or quite possibly both depending on the scale of the project.

For the moment, given Dancer is meant to be taking a micro-framework approach (which should be optimised more for small websites) I'm willing to suspend my disbelief and run with it until I can make a better judgement.

The documentation in general is oddly structured. For a command-oriented API like this I would expect to find documentation for each of the available commands. This section of the documentation does exist, but it doesn't contain a list of all the commands.

Instead, some of the commands are described down in sub-headings related to a logical area instead. And if you look at the table of contents on the search.cpan page the logical grouping doesn't appear very, well, logical.

There's some other indications the documentation has built up in bits and pieces rather than being addressed in a complete fashion. Some features are glossed over quickly, leaving me a bit stumped still. Other go into way more detail than is needed for a small website to the point of information overload.

The section on config files seems to suggest I should make three config files, a global config and then a pair of development/production config files that overlay the global. And these files go in different directories for some reason, unless I "put it all at the top of the program" (without saying how I embed this YAML in the program). A bit later on I realised they meant embed via the "set" command.

Overall, I think the documentation is reasonably thorough but just needs some love to clean it up into a more learning-friendly structure, with some sections shrunk down in the main Dancer page to just the most basic and common uses and references out to other pages for using more advanced features.

Stuck on something I wasn't sure about, I resorted to running the built in skeleton generator (mentioned prominently on the Dancer::Cookbook page) to at least get a better idea of what I was supposed to be doing.

C:\Users\Adam>dancer -a top100
+ top100
+ top100\views
+ top100\views\index.tt
+ top100\views\layouts
+ top100\views\layouts\main.tt
+ top100\environments
+ top100\environments\development.yml
+ top100\environments\production.yml
+ top100\config.yml
+ top100\app.psgi
+ top100\public
+ top100\public\css
+ top100\public\css\style.css
+ top100\public\css\error.css
+ top100\public\images
+ top100\public\404.html
+ top100\public\dispatch.fcgi
+ top100\public\dispatch.cgi
+ top100\public\500.html
+ top100\top100.pm
+ top100\top100.pl

For a few seconds this shocked me, because compared to the simplicity of helloworld.pl this is a lot more files.

At this point I hadn't even remotely considered the idea of site-customising my error pages, and there's 5 entirely different types of Perl application files in this list. I (newbie me) don't even know what PSGI is, let alone why I need one. And don't get why I have a dispatch.cgi in addition to my top100.pl script.

Frankly, I don't even really WANT to know what all these things are (yet?). But this did at least confirm where all the files should be living and the demo app did actually start and run properly. So in my case, it solved the problem I needed to solve.

But I certainly don't want to use it as the basis of my Top 100 site. It's just a bit overwhelming for my level of experience, and I don't want to have to go exploring and work out what all these different files do, so I know which ones are safe to delete.

I'm not ready yet, I have an index page to get showing first.

Templating was largely straight forward, mostly because the docs do everything to steer me towards Template Toolkit short of installing it for me (yes, you have to install Template Toolkit yourself to get the generated skeleton website working).

I suspect the reason for this is because their embedded default templates are not PARTICULARLY featured. The documentation sums up the feature set of the built in templates as the following.

<% var1 %>

No other features are described, making Template Toolkit the obvious choice. :)

I'm totally fine with this, but what I'm not entirely sure about is why on earth they have chosen to make Dancer's default tag style for Template Toolkit different to Template Toolkit's default tag style for Template Toolkit.

The only reason I could uncover from the documentation is that it makes TT compatible with their built in template engine. The one whose list of features is "variables".

The only other guess other than "we like it more that way" I can make are that it's done to be compatible with Sinatra, the Ruby toolkit I've never heard of but which I'm told was the inspiration for Dancer.

Switching it back to regular Template Toolkit tag style requires a slightly annoying block of config file entries I can easily imagine myself repeating in every Dancer program I will ever write.

To help you in gauging my annoyance level on this topic, allow me to show you now the complete working Dancer application at the end of this week.

#!/usr/bin/perl
 
use Dancer;
use Template;
use CPANDB {
    maxage => 3600 * 24 * 7,
};
 
# Configuration block
set template => 'template_toolkit';
set engines  => {
    template_toolkit => {
        start_tag => '[%',
        stop_tag  => '%]',
    },
};
 
# Route block
get '/' => sub {
    template 'index';
};
 
dance;

It's not a problem as such, but I'm sure it's one of those things that's going to niggle at me. If I wasn't trying to emulate a newbie, I'd probably switch over to the Template::Tiny plugin in the short term. Unfortunately, it's not particularly well known and so is probably out of bounds for this competition.

Given their strong preference for Template Toolkit, in their situation I'd probably have inlined the entire Template::Tiny package as the "house template" engine. Then you still have a direct upgrade path when people hit a feature T:Tiny didn't support but you get to keep the default tag style. But the current predates Template::Tiny, and so be it.

I also had a momentary confusion over whether I should call my template "index" or "index.tt" or "index.html" or "index.html.tt", but I put that mostly down to playing with Mojo's double-dotted templates (which I'll get to later). A quick look at the generated skeleton made it pretty clear what the naming is.

Adding the static files was very simple and easy to understand, following the convention of "if there's a "public" directory, everything in it is a static file".

However, I did hit a problem when I tried to add my logo image.

Weirdly, although my Dancer application was happily sending me css and my favicon.ico file, it didn't appear to support PNG images. Bemused, I placed my first (legitimate) visit to the #dancer channel to ask a What The Hell.

Dancer uses MIME::Types under the covers, and the bug only happens on Windows, and they confirmed they can replicate it. Beyond that there's no more information yet, but I've worked around the problem temporarily on my Dancer application by converting the PNG files to GIF.

And given the speed with which they chased down the previous Windows problems, I'm hopefully that by next week the problem will have gone away.

The final issue I forsee in any future life with Dancer is the way in which the templates and the static files combine together.

Although I'm capable of writing HTML by hand, I don't like to. I've been a constant Dreamweaver user version 1.0, because you gain all the benefits of seeing your page design as you work on it but without any risk of damaging templates.

(Historical Note: Dreamweaver's "Round Trip HTML" parsing ability was the primary source of inspiration for PPI's "Round Trip Perl" parsing)

By having all the static files in /public and all the templates in /views but serving everything from root, you can't really open a template in a GUI HTML editor and have the static files be consumed by the templates.

This problem is compounded by Dancer's "layout" feature, which is sort of like an inside-out INCLUDE block. I can see the attraction for things like "skinning" websites or having lite/print rendering, but it would also make it even harder to edit content using anything other than raw HTML.

I know a lot of Perl people don't like the GUI crowd, but the newbie web crowd is really going to live and die by GUI tools (which explains the popularity of PHP really).

Overall, the process was relatively straight forward with the exception of the PNG problem and a general feel that the documentation/tools dump you in the deep end a bit too quickly and need polishing.

Mojo - Bootstrapping a website

Having looked a little deeper into both Mojo and Dancer, one thing that strikes me is the level of similarity between the two. I'm assuming that there's a fair bit of feature and convention theft going on between the two, and thus presumably Ruby Sinatra as well.

In particular, Mojo also uses a separate /public and /templates directories and the documentation prominently mentions layout support. So the problem of templates that can't be edited in a WYSIWYG fashion also applies to Mojo.

In fact, having seen both doing this I can't help but wonder if this is part of the cause of the simplicity and/or stagnation I see on both websites.

When all site modifications have to be done in the raw, it makes it harder for casual contributors to provide ad-hoc content or look-and-feel improvements to the site.

The main Mojolicious::Lite isn't bad but it's rather short on written commentary and chock full of examples, with no separation into topics of sub-heading.

It comes across as a sort of giant SYNOPSIS, and I would have appreciated a bit more information beyond example code.

The curious file naming of templates in Mojo comes in for specific attention here. Template files use an interesting double-extension mechanism. Templates are referred to by their base name in code, and then the extensions indicate content type and template format respectively.

The most awesome thing that emerges from this is the idea that Mojo can use the same identical code to support multiple different content type requests. From the Mojo mega-SYNOPSIS docs.

# /detection.html
# /detection.txt
get '/detection' => sub {
    my $self = shift;
    $self->render('detected');
};
 
__DATA__
 
@@ detected.html.ep
<!doctype html><html>
    <head><title>Detected!</title></head>
    <body>HTML was detected.</body>
</html>
 
@@ detected.txt.ep
TXT was detected.

The flexible option of either embedded or standalone template files is also very cool for allowing complete websites in live in a single file.

As a bonus challenge to push out this potentially legendary flexibility, I decided to try and get Mojo installed and working on my Google Nexus One phone. The Android Scripting Environment comes with a trivially easy ability to add Perl support (5.10.1 no less), and all I had to do was drop the lib directory from the Mojo distribution onto the phone via USB, along with the Mojo helloworld.pl file.

Unfortunately, it failed the test although arguably not through any fault of it's own. The Mojo deep internals make use of the core module Encode.pm and unfortunately Android Perl does NOT come with Encode.pm in it, and making the Encode dependency optional isn't really an option for them due to the depth at which it is needed.

But back to templates.

And here's where I get negative about Mojo. While the in-house templating in Dancer is an afterthought they sweep under the rug in preference to Template Toolkit (which is almost, oddly, a positive) Mojo backs it's in-house templating 100% so it stays zero-dependency.

And the Mojo template style is really really messy. It's essentially an "embedded Perl" tag-flipping system which sees your templates HTML mixed deeply with Perl fragments.

Template features are provided via a fairly powerful Perl API in those fragments, which at least makes the best of things.

Now while I'm absolutely against mixing code and content, I do recognise that this approach might be useful in small contexts (it tends to be something that fails mostly at scale).

But what really makes me cringe is this.

<% Inline Perl %>
<%= Perl expression, replaced with result %>
<%== Perl expression, replaced with XML escaped result %>
<%# Comment, useful for debugging %>
% Perl line
%= Perl expression line, replaced with result
%== Perl expression line, replaced with XML escaped result
%# Comment line, useful for debugging

That's right, there are EIGHT different tag types. Four different ordinary tags alone would push some complexity budgets, but the real crime is the idea of duplicating those four into another four that are enhanced by significant whitespace!

These are further complicated by an optional closing modifier as seen in the following.

<%= All whitespace characters around this expression will be trimmed =%>

This introduces another disturbing idea, that of symmetrical escaping where each side means something different to the other.

And it gets even scarier once you add block capturing.

<%{ my $block = %>
    <% my $name = shift; =%>
    Hello <%= $name %>.
<%}%>
<%= $block->('Sebastian') %>
<%= $block->('Sara') %>
 
%{ my $block =
% my $name = shift;
Hello <%= $name %>.
%}
%= $block->('Baerbel')
%= $block->('Wolfgang')

And for good measure, it seems to "enhance" HTML with Unix-style line continuations!

This is <%= 23 * 3 %> a\
single line

The sum total of all these features is to be utterly hostile to editing templates in anything other than raw text, and I have genuine fears that if I unleashed a mental list of people on these templates they would very rapidly decent into sigil soup and line noise.

If I do go with Mojo at the end of this process, it will absolutely be with the provision that under no circumstances will I allow myself to look at the full template documentation, to prevent tempting myself into using some of the features described above.

And the really sad part is I'm really not sure I actually NEED any of the features. I'm fairly certain most of the complexity could be dropped without major ill effects.

The other sad thing about all this is that once you get past the horrendous tag style, IF you can get past it, the APIs provided to the Perl code chunks have some fairly neat conveniences in them.

Each route/handler allows a name to be associated with it, which identifies the route for things like the url_for tag functions, but which also serves as a template name for the handler if that is all that is provided.

This gives Mojo far far more concise code compared to Dancer for the simple site so far. Here is the following complete Mojo code for the boostrap site.

#!/usr/bin/perl
 
use Mojolicious::Lite;
use CPANDB {
    maxage => 3600 * 24 * 7,
};
 
get '/' => 'index';
 
shagadelic;

Indeed, at this scale it actually IS kind of "shagadelic". But of course I don't expect the meme to hold once I've added several hundred lines of actual website functionality.

Week 2 Results

Best Skeleton Generator - Mojo

Mojo's skeleton generator offers two option, heavy and lite. This, plus the fact I found Dancer's skeleton generator to be overwhelming, give it to Mojo.

Notably though, I didn't actually end up using either of them. In both cases, it started introducing concepts I didn't really want to have to deal with so early.

Best Application Layout - No Winner

Not only are the file layouts for both frameworks pretty much identical, but both basically prevent you using GUI HTML editors. Which really sucks, so I'm not even awarding a draw. Just a FAIL.

Best Templating - Not Mojo

Even though their internal templates appear to be so thin as to be non-existant, all their documentation quickly pushes you towards Template Toolkit. As the most popular templating system (by CPAN dependency count at least) this should be familiar territory for many many people.

But I really don't want to award it to them for positive actions. This one is decided on comparative negatives.

The annoyances/gotchas of having to add the magical "act like normal TT" invocation and not making Template a proper dep when even their own site generator uses it, simply don't compare to the utter zanyness and Dreamweaver-hostility of Mojo's tag format.

So I'm awarding this one AGAINST Mojo, instead of to Dancer. Both had their own respective dissapointments.

Overall Leader after Week 2 - Mojo

Why? The thing is, even though I've been forced to read about it, I haven't actually had to really do anything in my templates yet. So there's no tangible real pain from the Mojo templating system yet. What code is there is still really really tight.

So with a balanced score this week of zero vs zero, and Dancer's dishonourable mention for the PNG bug (if only because nobody ever noticed it), Mojo remains in the lead.

Next week, I try to set up the front page to actually work and try to get a generated Top 100 list added to the site via templating.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • So we didn't lose, Mojo lost - but we didn't win, so Mojo won. I'm confused.

    Should be noted that it seemed like you were more inclined to use "set" in your code when you could have just changed the configuration file (as is shown in the docs):

    template: "template_toolkit"
    engines:
        template_toolkit:
            start_tag: '[%'
            stop_tag:  '%]'

    (taken directly from the POD)

    P.S.

    We're actually working on creating a CPAN distribution-like directories.

    • Mojo is winning on the cumulative result over all weeks so far, but did not pull ahead.

      As you'll see from the code checkout, my application does not have a config file.

      This also isn't really the kind of thing you'd want in a config file, it's an inherent part of the application. You aren't going to change it on one particular machine compared to another machine.

      • Mojo is winning on the cumulative result over all weeks so far, but did not pull ahead.

        Positive and negative comparisons are a matter of semantic. Every "win" is a "loss for the opponent". Suckless can say "we write good programs", instead they decided to say "We write programs that don't suck as much as the others."

        However, even though you disliked a certain feature of Mojo, and disliked it more than you liked the way it is in Dancer - you still awarded no points to Dancer. Kinda sucked, but oh well, maybe we can change the name of Dancer to "Not Mojo". :)

        This also isn't really the kind of thing you'd want in a config file, it's an inherent part of the application. You aren't going to change it on one particular machine compared to another machine.

        Configuration files aren't just thin

        • Code in your configuration is still code, now it's just in a different language and mixed into your real configuration data in a place that is further away from the other code, making it harder to maintain.

          I don't want to put anything into a config file that I wouldn't expect a non-Perl programmer sysadmin to potentially change.

          • I don't want to put anything into a config file that I wouldn't expect a non-Perl programmer sysadmin to potentially change.

            You've got a point there. Fair enough. :)

  • IMHO etc.
    There are views/ with an index and a "main" layout - I can guess what they're about.
    Three config files, I can guess how that's supposed to work - must be a dev/test/live switch somewhere
    Public dir with css and images - sounds OK. The 404/500 are clearly error pages. Might not want them, but at least I know how to do them now.
    The top100.p[lm] are clearly my main app files.
    All that's left are the app.psgi and dispatch files. I don't know what they're for, but I'm a newbie, so I don't know l
  • One of the core features of web frameworks is dispatching - i.e. connecting the http address with a subroutine. This can be done in a few main ways:
    1. DSL with anonymous subs - this what you described above and it is the most common in recent web frameworks. The problem I can see with that code is - how it plays with the standard OO techniques like inheritance and some more advanced ones like Moose Roles. Even if this can be made to play along I am sure there will be lot's of corner cases making it diffic
    • There's also the "put it all in a central dispatch file" (a la Django's URLconf [djangobook.com], or even MojoX::Routes [cpan.org])

      The disadvantage is that you can't just drop a controller class into a file to be automatically picked up by the app, you have to modify the dispatch file too.

      But this turns to an advantage when you wish to selectively enable parts of you app (again, Django's admin feature comes to mind).

  • I'm not sure what your rules are for installing extensions for the framework, but there's a TT renderer for Mojo:

    http://search.cpan.org/~abh/MojoX-Renderer-TT-0.31/lib/MojoX/Renderer/TT.pm [cpan.org]

    (Install it, add the lines from the synopsis to your startup() method and name your templates foo.html.tt).

    With Mojolicious::Lite I think it'd be something like

                  use MojoX::Renderer::TT;
                  my $tt = MojoX::Renderer::TT->build(

    --

    -- ask bjoern hansen [askbjoernhansen.com], !try; do();

  • I would have put the template configuration in the config.yml configuration file. Or you could just use the default <% and %> start end tags in your templates. It wouldn't be the end of the world. I know that it is a matter of style and personal preference, but with a little white space formatting the dancer version could have been written more concisely like so:

    #!/usr/bin/perl
    use Dancer;
    use Template;
    use CPANDB { maxage => 3600 * 24 * 7 };

    # Route block
    get '/' => sub { template 'index' };

    dance

  • Any chance of week 3 of the comparison coming?