Dancer and Dancer2 both available on CPAN

As we say in French, Jamais deux sans trois, so for the third time on this blog, I’ll speak a little about Dancer2.

As explained earlier on this blog, we’ve decided to release Dancer2 under its own distribution, and at the same time, we decided to give Dancer a new maintainer (or should I use the Pumpkin term?)

Actually it’s not one, but two maintainers that now take care of Dancer releases: Yanick and Alberto! I’m glad to see that it took less than 4 days for a new release of Dancer to hit CPAN: Dancer 1.311!

Also, the last Dancer2 distribution (version 0.02) should be available on your favorite CPAN mirror.

I’ll also try to answer the most frequently asked questions since we released Dancer and Dancer2.

Should I upgrade my Dancer application to Dancer2?

If you’re happy with Dancer, and use many plugins/engines, then there is no reason to switch at this point in time. Don’t change something that fits your needs. That’s one of the rationale behind the release “split”.

You have the choice to upgrade, or not. It’s up to you. If you use many plugins/engines in your app, then it’s even a bit early for considering an upgrade.

So no reason to hurry the upgrade.

I’m going to write a new application, which Dancer should I use?

I’d really suggest to start right away with Dancer2. You’ll probably need a plugin or two that are missing, but our team is very active on porting all the ecosystem to Dancer2 (you can already see the first ports on metacpan).

Starting with Dancer2 will give more horsepower to your app, at the end of the day. Oh, and if you plan to use sessions, don’t even think about it, use Dancer2, it’s way better there!

Is Dancer2 production-ready?

It definitely is! We use it for a commercial product at Weborama, and it works like a charm. The app is powered by a couple of Starman servers and works as expected (using sessions, Redis, emails, and templates).

So yes, what you can use in Dancer2 is production ready. The real question is more the one about the ecosystem.

What are the benefits of switching to Dancer2?

No more app collisions, the power of Moo, less code in the framework (the footprint should be lighter), the performances are better and also, you have a strong OO API behind the scene if you need to dig behind the DSL.

Dancer2 enters CPAN

Upload by John Trainor

As mentioned earlier on this blog, the decision has been made to release Dancer2 under its own distribution on CPAN, in order to let users decide whether they want to upgrade or not.

After a couple of commits dedicated to polish a little the documentation and tailor the version 0.01 of the Dancer2 distribution, I’m glad to announce that it has been uploaded to CPAN.

The ecosystem will now be easy to port, expect lots of uploads in the Dancer2 namespace soon!

Dancer 1 and Dancer 2, what we’re going to do

Dancers
Dancers a foot ahead by Jonathan Borofsky

Fellow Perl hackers, you who like to “dance“, read the following carefully for I have some interesting news for you.

You probably know that we’ve frozen Dancer 1 development some time ago, when we decided to focus all the energy on Dancer 2. That was done with an idea in mind: get the most possible out of the D2 prototype.

We had also the idea that D2 will at some point be able to replace D1. Entirely. It was a mistake. Actually a mistake that will lead to something that I believe is rather very good for the Dancer community, let me explain.

Dancer 2 is a success on many fields: it’s entirely written with Moo, so it has a complete OO layer. The core encapsulates each app in a proper instance, ensuring no more app collisions will occur. All the non-deprecated keywords of the DSL provided by Dancer 1 are supported in Dancer 2. Some components are even better in D2 (look at the awesome session handling for instance) and the Moo layer behind the scene allows many great things for the future.
Plugins can be migrated quite easily to support D1 and D2 at the same time.

But there is one thing that won’t be possible: support engines in D1 and in D2 transparently. The reason is rather technical: in D1, an engine (logger, template, session) is a class that should be extended (in pure Perl 5 code). In D2, it’s a role that should be composed. Of course, the design is more rigid, and many things need to be changed for an engine to work under D2.

The question was: should we spend energy on trying to support both? Should we provide a wrapper to allow easy migration? The consensus is no. We’ll do something else.

There is out there a lot of real-life D1 applications. Most of them use engines that won’t work transparently under D2. Also the app-scoping can break things with some applications, if the app is decoupled in many packages.

For that reason, I’m going to release Dancer 2 in its own namespace, and that will bring a lot of energy in both projects:

  • Dancer 1 is at the same time unfrozen, development can continue there (as long as the features added are not something that would lead to a new Dancer 2!)
  • Dancer 2 is released on CPAN and its ecosystem can rise
  • Dancer 1 users are happy
  • Dancer 2 users are happy
  • Migrating an app becomes something under control.

So, be prepared to see Dancer2 on CPAN pretty soon :)

And by the way, we’ll choose a Dancer 1 maintainer, because I won’t have the time to handle both projects. Stay tuned!

The Perl Dancer Advent Calendar is 3 years old

If you follow the Perl ecosystem and more precisely Dancer’s, you probably know about our Advent Calendar.

It started 3 years ago thanks to the impulse of Franck Cuny and I’m very happy to see that the effort is still there, for the third year. This time, that’s David Precious who did all the difficult work of gathering energies and I think he managed to make things happen pretty well!

I’m also glad to see that the website performs almost twice as good as last year: 198% traffic growth according to Google Analytics if we compare with last year. Yesterday’s article was even the record with 668 visits while we did only 129 last year on the same day!

My first contribution to this year’s edition has been published today, you can check it out here, it’s a global overview of the state of Dancer 2. Although there is no release yet, the article explains a little trick that lets you build your first Dancer 2 app with minimal effort, using git submodule.

I’m very happy with this year’s edition because it’s a great opportunity for me to explain many things I’ve done during the year about Dancer 2. It was like a marathon done in the dark! So it’s very pleasant to be at the point of looking back, explaining what has been done, and demonstrating the thing.

All of my articles will be about Dancer 2, I hope you’ll like them!

Stay tuned.

Migrating your Dancer plugin to Dancer 2, the smooth way

Now that Dancer 2 has come a long way and is stable enough to run applications, it’s time to start focusing on migrating the ecosystem. By ecosystem, I mean all the plugins and engines (template, logger, session) that live on the CPAN.

But we want to be as smooth as possible with our fellow users and of course, with plugin developers. So we want a plugin to be able to run under Dancer 1 or 2, with as minimal code tweaks as possible in the plugin’s code. All this in order to allow a smooth transition process towards Dancer 2.

My last patches sent to both Dancer 1 and 2 allows plugin authors to adapt their code so that the plugin can be agnostic of the version of Dancer behind them.

I thought everything was in place to allow a plugin to run smoothly with Dancer 1 and 2, but David – who was working on porting Dancer::Plugin::Database to Dancer 2 – asked me about the hooks.

With Dancer 1, all the hooks are managed by a singleton so registering a hook and executing it is as easy as

Dancer::Factory::Hook->instance
  ->install_hooks("some_hook_for_my_plugin");

...

Dancer::Factory::Hook->instance
  ->execute_hooks("some_hook_for_my_plugin");

Yes it’s simple, but the reason why it’s simple is because all the hooks are shared among all the components of the application. Which is one of the design limitation we wanted to solve with Dancer 2.

In Dancer 2, it’s way much better, we use massively Moo and its roles system in order to do as much code-reuse as possible and allow a clean and extensible design.

In 2, a plugin is a role that consumes the DSL role (to extend it) which itself consumes the “Hookable” role (which provides hook features).

When an application uses a plugin, its DSL (of the application) gets extended by consuming the plugin’s DSL.

Also, in Dancer 2, we have some kind of a namespace for hooks in order to do automatic resolution of hooks ownership (I won’t go into details about that part, it’s out of the scope of this post). Anyway, keep in mind a hook has a “real name” and a “user name” in Dancer 2.

The “user name” (which is called an alias) is the one you’re used to see in Dancer 1, like “before_template”.

To declare its hooks, a plugin must implement a method named “supported_hooks” which should return the list of hooks (real names) that it claims to support.

The plugin is also able to define user names with the method “hook_aliases”.

That’s the DSL of the plugin that holds the hooks, not a singleton living in a shared space accessible for the whole process. Way much cleaner, but of course, a bit more complex for the developer.

Let’s take an example of a dummy plugin that sets its own hook, in Dancer 1:

package Dancer::Plugin::Something;
use Dancer::Plugin;

# claim the hook we support
Dancer::Factory::Hook->instance
  ->install_hooks("somehook");

...

register some_keyword => sub {
    my $self = shift;
    ...

    Dancer::Factory::Hook->instance
      ->execute_hooks("somehook");
};

...

Now, Without my last patch, a plugin author who wanted to implement that very same plugin in Dancer 2 would have had to do like so:

package Dancer::Plugin::Something;
use Dancer::Plugin;

# claim the hook we support
sub supported_hooks { "plugin.somehting.some_hook" }
sub hook_aliases    { "somehook" => "plugin.somehting.some_hook" }

register some_keyword => sub {
    my $self = shift;
    ...

    $self->execute_hooks('somehook');
};

...

As you can see, we are far from what is needed in Dancer 1. I let you imagine the code needed to maintain compatibility with both Dancer versions…

To solve this issue, I’ve added two new keywords in the Dancer::Plugin’s export table, register_hook and execute_hooks which encapsulate for you the nasty bits exposed above.

I’ve implemented them in both Dancer 1 and Dancer 2 so a plugin author can now do the following:

package Dancer::Plugin::Something;
use Dancer::Plugin;

# claim the hook we support
register_hook "somehook";

register some_keyword => sub {
    execute_hooks 'somehook';
};

...

And voila, it works with both version!

Thanks David for poking me about that!
Note:
The patch for Dancer 2 has been pushed to Github, the one for Dancer 1 as well, and a new release is expected soon to be pushed to CPAN.