<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/dancer/</id>
  <link href="https://www.endpointdev.com/blog/tags/dancer/"/>
  <link href="https://www.endpointdev.com/blog/tags/dancer/" rel="self"/>
  <updated>2022-04-19T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Perl Web Frameworks</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/04/perl-web-frameworks/"/>
      <id>https://www.endpointdev.com/blog/2022/04/perl-web-frameworks/</id>
      <published>2022-04-19T00:00:00+00:00</published>
      <author>
        <name>Marco Pessotto</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/04/perl-web-frameworks/nature-wing-black-and-white-web-line-insect-1244977.webp&#34; alt=&#34;Spider webs and spiders&#34;&gt;&lt;/p&gt;
&lt;!-- Photo: https://pxhere.com/en/photo/1244977 CC0 Public Domain --&gt;
&lt;h3 id=&#34;cgi&#34;&gt;CGI&lt;/h3&gt;
&lt;p&gt;When I started programming, back in the day, CGI (the Common Gateway Interface) was still widely
used. Usually the Apache webserver would just execute a script or a
binary with some environment variables set and serve whatever the
executable sent to the standard output, while keeping the standard
error in the logs.&lt;/p&gt;
&lt;p&gt;This simple and straightforward mechanism can still
be used for small programs, but larger applications usually want to
save the start-up time and live longer than just a single request.&lt;/p&gt;
&lt;p&gt;At that time Perl was used far more often than now, and it had (and still
has) the &lt;a href=&#34;https://metacpan.org/pod/CGI&#34;&gt;CGI.pm&lt;/a&gt; module to help the
programmer to get the job done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;utf8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;strict&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;warnings&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CGI&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$q&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;CGI&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$q&lt;/span&gt;-&amp;gt;header;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$name&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Marco&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$q&lt;/span&gt;-&amp;gt;p(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello $name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And it will output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./cgi.pl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/html; charset=ISO-8859-1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;p&amp;gt;Hello Marco&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here the script mixes logic and formatting and the encoding it
produces by default tells us that this comes from another age. But
if you want something which is seldom used and gets executed on demand
without persisting in the machine’s memory, this is still an option.&lt;/p&gt;
&lt;p&gt;Please note that there are frameworks which can work in CGI mode, so
there is no reason to use CGI.pm, beside having to maintain legacy
programs.&lt;/p&gt;
&lt;h3 id=&#34;mojolicious&#34;&gt;Mojolicious&lt;/h3&gt;
&lt;p&gt;Fast-forward to 2022.&lt;/p&gt;
&lt;p&gt;Nowadays Perl is just another language among dozens of them. But it
still gets the job done and lets you write nice, maintainable code like
any other modern language.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://mojolicious.org/&#34;&gt;Mojolicious&lt;/a&gt; is currently the top choice if
you want to do web development in Perl. It is an amazing framework,
with a large and active community, and appears to have collected the
best concepts that other web frameworks from other languages have to
offer.&lt;/p&gt;
&lt;p&gt;Let’s hack an app in a couple of minutes in a single file, like during
the CGI days:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;utf8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;strict&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;warnings&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mojolicious::Lite&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;) = &lt;span style=&#34;color:#369&#34;&gt;@_&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;stash(name =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Marco&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;render(template =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;index&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;app&lt;/span&gt;-&amp;gt;start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;__DATA__&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;@@&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;index&lt;/span&gt;.html.ep
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello &amp;lt;&lt;span style=&#34;color:#369&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here the structure is a bit different.&lt;/p&gt;
&lt;p&gt;First, there’s a Domain Specific Language (DSL) to give you some sugar.
This is the “Lite” version, while in a well-structured Mojolicious app one
prefers to write class methods. We declare that the root (&lt;code&gt;/&lt;/code&gt;) URL path of the
application is going to execute some code. It populates the “stash”
with some variables, and finally renders a template which can access
the stashed variables. If you execute the script, you get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./mojo.pl cgi 2&amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Status: 200 OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date: Fri, 08 Apr 2022 12:33:52 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/html;charset=UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello Marco&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The logging to the standard error stream is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:33:52.92508] [163133] [debug] [82ae3iV2] GET &amp;#34;/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:33:52.92532] [163133] [debug] [82ae3iV2] Routing to a callback
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:33:52.92565] [163133] [debug] [82ae3iV2] Rendering template &amp;#34;index.html.ep&amp;#34; from DATA section
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:33:52.92610] [163133] [debug] [82ae3iV2] 200 OK (0.001021s, 979.432/s)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is basically what a modern framework is supposed to do.&lt;/p&gt;
&lt;p&gt;The nice thing in this example is that we created a single-file
prototype and launched it as a CGI. But we can also launch it as
daemon and visit the given address with a browser, which is how you
should normally deploy it, usually behind a reverse proxy like
&lt;a href=&#34;https://nginx.org/en/&#34;&gt;nginx&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./mojo.pl daemon
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:48:42.01827] [163409] [info] Listening at &amp;#34;http://*:3000&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Web application available at http://127.0.0.1:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:48:48.53687] [163409] [debug] [CwM6zoUQ] GET &amp;#34;/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:48:48.53715] [163409] [debug] [CwM6zoUQ] Routing to a callback
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:48:48.53752] [163409] [debug] [CwM6zoUQ] Rendering template &amp;#34;index.html.ep&amp;#34; from DATA section
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2022-04-08 14:48:48.53808] [163409] [debug] [CwM6zoUQ] 200 OK (0.001209s, 827.130/s)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want you can even launch it with HTTPS as well (please note the
syntax to pass the certificates).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./mojo.pl daemon -l &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;https://[::]:8080?cert=./ssl/fullchain.pem&amp;amp;key=./ssl/privkey.pem&amp;#39;&lt;/span&gt; -m production&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For a small application listening on a high port this is already
enough and the whole deployment problem goes away.&lt;/p&gt;
&lt;p&gt;Speaking about deployment, Mojolicious has basically no dependencies
other than the core modules and comes with a lot of goodies, for example
a &lt;a href=&#34;https://docs.mojolicious.org/Mojo/UserAgent&#34;&gt;non blocking user-agent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recently a legacy application needed to make some API calls. To speed up
the process, we wanted to make the requests in parallel. And here’s
the gist of the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Async&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# ... more modules here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mojo::UserAgent&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mojo::Promise&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# .... other methods here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;example&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$email&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;test@example.com&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$ua&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mojo::UserAgent&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;foreach&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$list&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;get_lists) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$promise&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$ua&lt;/span&gt;-&amp;gt;post_p(&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_url(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/api/v2/endpoint/$list-&amp;gt;{code}&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  json =&amp;gt; { email =&amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$email&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          -&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$tx&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$res&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$tx&lt;/span&gt;-&amp;gt;result;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$res&lt;/span&gt;-&amp;gt;code =~ &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;m/^2/&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_update_db(&lt;span style=&#34;color:#369&#34;&gt;$data&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$tx&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;req&lt;/span&gt;-&amp;gt;url . &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; . &lt;span style=&#34;color:#369&#34;&gt;$res&lt;/span&gt;-&amp;gt;code;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#038&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@promises&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$promise&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$return&lt;/span&gt; = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Mojo::Promise&lt;/span&gt;-&amp;gt;all(&lt;span style=&#34;color:#369&#34;&gt;@promises&lt;/span&gt;)-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; { &lt;span style=&#34;color:#369&#34;&gt;$return&lt;/span&gt; = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; }, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; { &lt;span style=&#34;color:#369&#34;&gt;$return&lt;/span&gt; = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;})-&amp;gt;&lt;span style=&#34;color:#038&#34;&gt;wait&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So a bunch of requests are run in parallel and then synced before
returning. Does it remind you of JavaScript? Of course. A lot of
common paradigms taken from other languages and frameworks were
implemented here, and you can find the best of them in this nice
package.&lt;/p&gt;
&lt;p&gt;But the point here is that it doesn’t need dozens of new modules
installed or upgraded. It’s just a single module in pure Perl that you
can even install in your application tree. This is a huge advantage if
you’re dealing with a legacy application which uses an old Perl tree
and you want to play safe.&lt;/p&gt;
&lt;p&gt;So, if you’re starting from scratch, go with Mojolicious. It lets you
prototype fast and doesn’t let you down later.&lt;/p&gt;
&lt;p&gt;However, starting from scratch is not always an option. Actually, it’s
a rare opportunity. There’s a whole world of legacy applications and
they generate real money every day. It’s simply not possible or even
desirable to throw away something that works for something that would
do the same thing but in a “cooler” way. In ten years, the way we’re
coding will look old anyway.&lt;/p&gt;
&lt;h3 id=&#34;interchange&#34;&gt;Interchange&lt;/h3&gt;
&lt;p&gt;Wait. Isn’t &lt;a href=&#34;https://www.interchangecommerce.org&#34;&gt;Interchange&lt;/a&gt; an old
e-commerce framework? Yes, it’s not exactly a generic web framework,
on the contrary, it’s a specialized one, but it’s still a framework and
you can still do things in a maintainable fashion. The key is using
the so-called action maps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ActionMap jump &amp;lt;&amp;lt;EOR
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sub {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # get the path parameters
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    my ($action, @args) = split(/\//, shift);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # get the query/body parameters
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    my $param = $CGI-&amp;gt;{param};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # redirect to another page
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $Tag-&amp;gt;deliver({ location =&amp;gt; $final });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # or serve JSON
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $Tag-&amp;gt;deliver({ type =&amp;gt; &amp;#39;application/json&amp;#39;, body =&amp;gt; $json_string });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # or serve a file
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $Tag-&amp;gt;deliver({ type =&amp;gt; &amp;#39;text/plain&amp;#39;, body =&amp;gt; $bigfile });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # or populate the &amp;#34;stash&amp;#34; and serve a template page
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $Tag-&amp;gt;tmp(stash_variable =&amp;gt; &amp;#34;Marco&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $CGI-&amp;gt;{mv_nextpage} = &amp;#34;test.html&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EOR&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;pages/test.html&lt;/code&gt; you would put this template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;Hello [scratch stash_variable]&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, I can’t show you a simple script which demonstrates this and
you’ll have to take my word for it since we can’t go through the
installation process here for a demo.&lt;/p&gt;
&lt;p&gt;Interchange is old, and it shows its
years, but it is actively maintained. It lacks many of Mojo’s
goodies, &lt;em&gt;but&lt;/em&gt; you can still do things in a reasonable way.&lt;/p&gt;
&lt;p&gt;In the example the code will execute
when a path starting with &lt;code&gt;/jump/&lt;/code&gt; is requested. The whole path is
passed to the routine, so you can split at &lt;code&gt;/&lt;/code&gt;, apply your logic, and
finally either set &lt;code&gt;$CGI-&amp;gt;{mv_nextpage}&lt;/code&gt; to a file in the &lt;code&gt;pages&lt;/code&gt;
directory or output the response body directly with &lt;code&gt;deliver&lt;/code&gt;. This
way you can easily build, as a classical example, an API.&lt;/p&gt;
&lt;p&gt;It’s a bit of a poor man’s
&lt;a href=&#34;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller&#34;&gt;MVC&lt;/a&gt;
but it works. That’s basically the core of what a framework like
&lt;a href=&#34;https://metacpan.org/pod/Dancer2&#34;&gt;Dancer&lt;/a&gt; does.&lt;/p&gt;
&lt;h3 id=&#34;dancer-1--2&#34;&gt;Dancer (1 &amp;amp; 2)&lt;/h3&gt;
&lt;p&gt;Dancer is basically Ruby’s
&lt;a href=&#34;https://github.com/sinatra/sinatra&#34;&gt;Sinatra&lt;/a&gt; ported to Perl. As
already mentioned, ideas developed in other languages and frameworks
are often ported to Perl, and this is no exception.&lt;/p&gt;
&lt;p&gt;Let’s see it in an action:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;strict&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;warnings&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Dancer2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$name&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Marco&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello $name\n&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;start;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Start the script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Dancer2 v0.400000 server 22969 listening on http://0.0.0.0:3000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Try it with &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -D - http://0.0.0.0:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HTTP/1.0 200 OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date: Mon, 11 Apr 2022 07:22:18 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server: Perl Dancer2 0.400000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server: Perl Dancer2 0.400000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/html; charset=UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello Marco&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If in the script you say &lt;code&gt;use Dancer;&lt;/code&gt; instead of &lt;code&gt;use Dancer2&lt;/code&gt;, you get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -D - http://0.0.0.0:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HTTP/1.0 200 OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server: Perl Dancer 1.3513
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;X-Powered-By: Perl Dancer 1.3513
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello Marco&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dancer’s core doesn’t do much more than routing. And you’ll also
notice that the syntax is very similar to Mojolicious::Lite. So to
get something done you need to start installing plugins which will
provide the needed glue to interact with a database, work with your
template system of choice, and more.&lt;/p&gt;
&lt;p&gt;Today you would wonder why you should use Dancer and not Mojolicious,
but when Dancer was at the peak of its popularity the games were still
open. There were plenty of plugins being written and published on CPAN.&lt;/p&gt;
&lt;p&gt;Around 2013 Dancer’s development team decided to rewrite it to make
it better. The problem was that plugins and templates needed to be
adapted as well. I’m under the impression that the energy got divided
and the momentum was lost. Now there are two codebases and two
plugin namespaces which do basically the same thing, because for
the end user there is not much difference.&lt;/p&gt;
&lt;h3 id=&#34;catalyst&#34;&gt;Catalyst&lt;/h3&gt;
&lt;p&gt;So what was attracting people to Dancer? When Dancer came out, Perl
had a great MVC framework, which is still around,
&lt;a href=&#34;http://catalyst.perl.org/&#34;&gt;Catalyst&lt;/a&gt;. (And note that the main
Mojolicious developer was on the Catalyst team.)&lt;/p&gt;
&lt;p&gt;Now, the problem is that to get started with Catalyst, even if it has
plenty of documentation, you need to be already acquainted with a lot
of concepts and technologies. For example, the
&lt;a href=&#34;https://metacpan.org/dist/Catalyst-Manual/view/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod&#34;&gt;tutorial&lt;/a&gt;
starts to talk about
&lt;a href=&#34;http://www.template-toolkit.org/&#34;&gt;Template Toolkit&lt;/a&gt; and
the &lt;a href=&#34;https://metacpan.org/pod/DBIx::Class&#34;&gt;DBIx::Class&lt;/a&gt; ORM very early.&lt;/p&gt;
&lt;p&gt;These two modules are great and powerful and they deserve to be
studied, but for someone new to modern web development, or even to
Perl, it feels (and actually is) overwhelming.&lt;/p&gt;
&lt;p&gt;So, why would you choose Catalyst today? Catalyst has the stability
which Mojo, at least at the beginning, lacked, while
backward compatibility is a priority for Catalyst. The other way to look
at this is that Catalyst doesn’t see much current
&lt;a href=&#34;https://metacpan.org/dist/Catalyst-Runtime/changes&#34;&gt;development&lt;/a&gt;, but
someone could see this as a feature.&lt;/p&gt;
&lt;p&gt;Even if Catalyst predates all the hyper-modern features that Mojo has,
it’s still a modern framework, and a good one. I can’t show you a self
contained script (you need a tree of files), but I’d like to show you
what makes it very nice and powerful:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Controller::Root&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Moose&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;namespace::autoclean&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt; { extends &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Catalyst::Controller&amp;#39;&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# start the chain with /foo/XX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;foo&lt;/span&gt; :Chained(&amp;#39;/&amp;#39;) CaptureArgs(1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$arg&lt;/span&gt;) = &lt;span style=&#34;color:#369&#34;&gt;@_&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;stash(name =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;$arg&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# /foo/XX/bar/YY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;bar&lt;/span&gt; :Chained(&amp;#39;foo&amp;#39;) Args(1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$arg&lt;/span&gt;) = &lt;span style=&#34;color:#369&#34;&gt;@_&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;detach(&lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;view(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;JSON&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# /foo/XX/another/YY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;another&lt;/span&gt; :Chained(&amp;#39;foo&amp;#39;) Args(1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$arg&lt;/span&gt;) = &lt;span style=&#34;color:#369&#34;&gt;@_&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;detach(&lt;span style=&#34;color:#369&#34;&gt;$c&lt;/span&gt;-&amp;gt;view(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;HTML&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, if you hit &lt;code&gt;/foo/marco/bar/test&lt;/code&gt; the second path fragment will be
processed by the first method (&lt;code&gt;CaptureArgs(1)&lt;/code&gt;) and saved in the
stash. Then the second &lt;code&gt;bar&lt;/code&gt; method will be chained to it and the
&lt;code&gt;name&lt;/code&gt; will be available in the stash. The last method will be hit
with &lt;code&gt;/foo/marco/another/test2&lt;/code&gt;. (Incidentally, please note that
Mojolicious has
&lt;a href=&#34;https://docs.mojolicious.org/Mojolicious/Guides/Routing#Nested-routes&#34;&gt;nested&lt;/a&gt;
routes as well.)&lt;/p&gt;
&lt;p&gt;Now, I think it’s clear that in this way you can build deep hierarchies
of paths with reusable components. This works really great with the
DBIx::Class ORM, where you can
chain queries as well. As you can imagine, this is far from a simple
setup. On the contrary, this is an advanced setup for people who
already know their way around web frameworks.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;So, to sum up this excursion in the amazing land of Perl web
frameworks: If you build something from scratch, go with Mojolicious.
It’s your best bet. If nothing else, it’s super-easy to install, with
basically no dependencies.&lt;/p&gt;
&lt;p&gt;However, there’s no need to make a religion
out of it. Rewriting code without a clear gain is a waste of time and
money. A good developer should still be able to write maintainable
code with the existing tools.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>2015 Perl Dancer Conference videos</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/12/2015-perl-dancer-conference-videos/"/>
      <id>https://www.endpointdev.com/blog/2015/12/2015-perl-dancer-conference-videos/</id>
      <published>2015-12-30T00:00:00+00:00</published>
      <author>
        <name>Sam Batschelet</name>
      </author>
      <content type="html">
        &lt;p&gt;The 2015 &lt;a href=&#34;https://www.perl.dance&#34;&gt;Perl Dancer Conference&lt;/a&gt; has recently released the presentation videos. This year the conference was hosted in beautiful Vienna, Austria. Josh Lavin and I were both honored to attend the conference as well as give talks. Earlier, Josh wrote summaries of the conference:&lt;/p&gt;
&lt;h3 id=&#34;conference-recap&#34;&gt;Conference Recap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report/&#34;&gt;Training Days&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/&#34;&gt;Conference Days&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conference-presentations&#34;&gt;Conference Presentations&lt;/h3&gt;
&lt;h4 id=&#34;spacecamps-the-final-frontier&#34;&gt;SpaceCamps “The Final Frontier”&lt;/h4&gt;
&lt;p&gt;I gave a talk exploring new technologies for End Point’s own &lt;a href=&#34;http://devcamps.org&#34;&gt;DevCamps&lt;/a&gt; development tool. During the presentation I detailed my research into containers and what a cloud-based development environment might look like.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=IYKs8FF8--Y&#34;&gt;SpaceCamps Presentation Video&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;angularjs--dancer-for-modern-web-development&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development&lt;/h4&gt;
&lt;p&gt;Josh detailed his experience migrating legacy applications utilizing Dancer, AngularJS, and modern Perl techniques. Josh highlighted the challenges he faced during the process, as well as lessons he learned along the way.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=m7q6QbSHrkA&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development Presentation Video&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;lightning-talks&#34;&gt;Lightning Talks&lt;/h3&gt;
&lt;p&gt;Josh and I both gave short “lightning talks.” Josh’s was on &lt;a href=&#34;https://youtu.be/-eg21qxxIAA?t=12m47s&#34;&gt;Writing Unit Tests for a Legacy App (Interchange 5)&lt;/a&gt;, and mine was on &lt;a href=&#34;https://youtu.be/-eg21qxxIAA?t=19m11s&#34;&gt;Plack &amp;amp; Interchange 5.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To review the rest of the presentations please checkout the &lt;a href=&#34;https://www.youtube.com/channel/UCWtnsx6yRuHvO2e-xX2Yyng&#34;&gt;Perl Dancer Conference YouTube channel&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;The Perl Dancer community continues to flourish and the conference this year hosted a record 5 core &lt;a href=&#34;http://perldancer.org&#34;&gt;Dancer&lt;/a&gt; developers. Dancer is about to release the finalized version of its long awaited plugin infrastructure for &lt;a href=&#34;https://github.com/PerlDancer/Dancer2&#34;&gt;Dancer2&lt;/a&gt;. A lot of work on this was completed during the conference. Being an organizer of the conference, it brings me great joy to see this success. This news along with the release of Perl 6, I am certain 2016 will be a wonderful year for not only Dancer but the entire &lt;a href=&#34;https://www.perl.org/&#34;&gt;Perl&lt;/a&gt; community.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>AngularJS &amp; Dancer for Modern Web Development</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/10/angularjs-dancer-for-modern-web/"/>
      <id>https://www.endpointdev.com/blog/2015/10/angularjs-dancer-for-modern-web/</id>
      <published>2015-10-30T00:00:00+00:00</published>
      <author>
        <name>Josh Lavin</name>
      </author>
      <content type="html">
        &lt;p&gt;At the &lt;a href=&#34;http://perl.dance&#34;&gt;Perl Dancer Conference 2015&lt;/a&gt;, I gave a talk on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/11-angularjs-%26-dancer-for-modern-web-development&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development&lt;/a&gt;&lt;/em&gt;. This is a write-up of the talk in blog post form.&lt;/p&gt;
&lt;h3 id=&#34;legacy-apps&#34;&gt;Legacy Apps&lt;/h3&gt;
&lt;p&gt;It’s a fact of life as a software developer that a lot of us have to work with legacy software. There are many older platforms out there, still being actively used today, and still supporting valid businesses. Thus, legacy apps are unavoidable for many developers. Eventually, older apps are migrated to new platforms. Or they die a slow death. Or else the last developer maintaining the app dies.&lt;/p&gt;
&lt;h3 id=&#34;oh-to-migrate&#34;&gt;Oh, to migrate&lt;/h3&gt;
&lt;p&gt;It would be wonderful if I could migrate every legacy app I work on to something like &lt;a href=&#34;http://perldancer.org/&#34;&gt;Perl Dancer&lt;/a&gt;. This isn’t always practical, but a developer can dream, right?&lt;/p&gt;
&lt;p&gt;Of course, every circumstance is different. At the very least, it is helpful to consider ways that old apps can be migrated. Using new technologies can speed development, give you new features, and breathe new life into a project, often attracting new developers.&lt;/p&gt;
&lt;p&gt;As I considered how to prepare my app for migration, here are a few things I came up with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Break out of the Legacy App Paradigm
&lt;ul&gt;
&lt;li&gt;Consider that there are better ways to do things than the way they’ve always been done&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use Modern Perl
&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&#34;http://www.modernperlbooks.com/books/modern_perl_2014/07-object-oriented-perl.html&#34;&gt;object-oriented Perl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&#34;https://metacpan.org/pod/Test::Stream&#34;&gt;tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&#34;https://metacpan.org/&#34;&gt;CPAN&lt;/a&gt; modules and don’t reinvent the wheel&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Organize business logic
&lt;ul&gt;
&lt;li&gt;Try to avoid placing logic in front-end code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;you-are-in-a-legacy-codebase&#34;&gt;You are in a legacy codebase&lt;/h3&gt;
&lt;p&gt;I explored how to start using testing, but I soon realized that this requires methods or subroutines. This was the sad realization that up till now, my life as a Perl programmer had been spent doing scripting. My code wasn’t testable, and looked like a relic with business logic strewn about.&lt;/p&gt;
&lt;h3 id=&#34;change&#34;&gt;Change&lt;/h3&gt;
&lt;p&gt;I set out to change my ways. I started exploring &lt;a href=&#34;http://perldoc.perl.org/perlootut.html&#34;&gt;object-oriented Perl&lt;/a&gt; using &lt;a href=&#34;https://metacpan.org/pod/Moo&#34;&gt;Moo&lt;/a&gt;, since Dancer2 uses Moo. I started trying to write unit tests, and started to use classes and methods in my code.&lt;/p&gt;
&lt;p&gt;Essentially, I began breaking down problems into smaller problems. This, after all, is how the best methods are written: short and simple, that do &lt;a href=&#34;https://en.wikipedia.org/wiki/Single_responsibility_principle&#34;&gt;just one thing&lt;/a&gt;. I found that writing code this way was fun.&lt;/p&gt;
&lt;h3 id=&#34;crash&#34;&gt;Crash&lt;/h3&gt;
&lt;p&gt;I quickly realized that I wasn’t able to run tests in my Legacy App, as it couldn’t be called from the command line (at least not out of the box, and not without weird hacks). Thus, if my modules depended on Legacy App code, I wouldn’t be able to call them from tests, because I couldn’t run these tests from the shell.&lt;/p&gt;
&lt;p&gt;This led me to a further refinement: &lt;em&gt;abstract away all Legacy App-specific code from my modules&lt;/em&gt;. Or, at least all the modules I could (I would still need a few modules to rely on the Legacy App, or else I wouldn’t be using it it all). This was a good idea, it turned out, as it follows the principle of &lt;a href=&#34;https://en.wikipedia.org/wiki/Separation_of_concerns&#34;&gt;Separation of Concerns&lt;/a&gt;, and the idea of &lt;em&gt;Web App + App&lt;/em&gt;, which was mentioned frequently at the conference.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Now&lt;/em&gt; I was able to run tests on my modules!&lt;/p&gt;
&lt;h3 id=&#34;move-already&#34;&gt;Move already&lt;/h3&gt;
&lt;p&gt;This whole process of “getting ready to migrate” soon began to look like &lt;a href=&#34;http://catb.org/jargon/html/Y/yak-shaving.html&#34;&gt;yak shaving&lt;/a&gt;. I realized that I should have moved to Dancer earlier, instead of trying to do weird hacks to get the Legacy App doing things as Dancer would do them.&lt;/p&gt;
&lt;p&gt;However, it was a start, a step in the right direction. Lesson for me, tip for you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And&lt;/em&gt;, the result was that my back-end code was all the more ready for working with Dancer. I would just need to change a few things, and presto! (More on this below.)&lt;/p&gt;
&lt;h3 id=&#34;front-end&#34;&gt;Front-End&lt;/h3&gt;
&lt;p&gt;With the back-end looking tidier, I now turned to focus on the front-end. There was a lot of business logic in my front-end code that needed to be cleaned up.&lt;/p&gt;
&lt;p&gt;Here is an example of my Legacy App front-end code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_TOP_@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt;&amp;gt;[scratch page_title]&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[perl]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   my $has_course;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   for (grep {$_-&amp;gt;{mv_ib} eq &amp;#39;course&amp;#39;} @$Items) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      $has_course++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   return $has_course ? &amp;#39;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;You have a course!&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;&amp;#39; : &amp;#39;&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[/perl]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;Buy [if cgi items]more[else]now[/else][/if]&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_BOTTOM_@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the Legacy App allowed the embedding of all sorts of code into the HTML page. I had Legacy App tags (in the brackets), plus something called “embedded perl”, plus regular HTML. Add all this together and you get &lt;em&gt;Tag Soup&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This kind of structure won’t look nice if you attempt to view it on your own machine in a web browser, absent from the Legacy App interpreting it. But let’s face it, this code doesn’t look nice anywhere.&lt;/p&gt;
&lt;h3 id=&#34;separation-of-concerns&#34;&gt;Separation of Concerns&lt;/h3&gt;
&lt;p&gt;I thought about how to apply the principle of &lt;em&gt;Separation of Concerns&lt;/em&gt; to my front-end code. One thing I landed on, which isn’t a new idea by any means, is the use of “HTML + placeholders”, whereby I would use some placeholders in my HTML, to be later replaced and filled in with data. Here is my first attempt at that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_TOP_@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[my-tag-attr-list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    page_title=&amp;#34;[scratch page_title]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    has_course=&amp;#34;[perl] ... [/perl]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    buy_phrase=&amp;#34;Buy [if cgi items]more[else]now[/else][/if]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt;&amp;gt;{PAGE_TITLE}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {HAS_COURSE?}&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;You have a course!&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;{/HAS_COURSE?}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;{BUY_PHRASE}&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[/my-tag-attr-list]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_BOTTOM_@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What I have here uses the Legacy App’s built-in placeholder system. It attempts to set up all the code in the initial “my-tag-attr-list”, then the HTML uses placeholders (in braces) which get replaced upon the page being rendered. (The question-mark in the one placeholder is a conditional.)&lt;/p&gt;
&lt;p&gt;This worked OK. However, the logic was &lt;em&gt;still&lt;/em&gt; baked into the HTML page. I wondered how I could be more ready for Dancer? (Again, I should have just gone ahead and migrated.) I considered using &lt;a href=&#34;http://p3rl.org/Template::Toolkit&#34;&gt;Template::Toolkit&lt;/a&gt;, since it is used in Dancer, but it would be hard to add to my Legacy App.&lt;/p&gt;
&lt;h3 id=&#34;enter-angularjs-or-your-favorite-javascript-framework&#34;&gt;Enter AngularJS (or your favorite JavaScript framework)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://angularjs.org/&#34;&gt;AngularJS&lt;/a&gt; is a JavaScript framework for front-end code. It displays data on your page, which it receives from your back-end via &lt;a href=&#34;http://json.org/&#34;&gt;JSON&lt;/a&gt; feeds. This effectively allows you to separate your front-end from your back-end. It’s almost as if your front-end is consuming an API. (Novel idea!)&lt;/p&gt;
&lt;p&gt;After implementing AngularJS, my Legacy App page looked like this (not showing JavaScript):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_TOP_@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-bind&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;page.title&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-if&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;items.course&amp;#34;&lt;/span&gt;&amp;gt;You have a course!&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-show&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;items&amp;#34;&lt;/span&gt;&amp;gt;Buy more&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-hide&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;items&amp;#34;&lt;/span&gt;&amp;gt;Buy now&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@_BOTTOM_@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now all my Legacy App is doing for the front-end is basically “includes” to get the header/footer (the TOP and BOTTOM tags). The rest is HTML code with ng- attributes. These are what AngularJS uses to “do” things.&lt;/p&gt;
&lt;p&gt;This is much cleaner than before. I am still using the Legacy App back-end, but all it has to do is “routing” to call the right module and deliver JSON (and do authentication).&lt;/p&gt;
&lt;p&gt;Here’s a quick example of how the JavaScript might look:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-app&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;MyApp&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;angular.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  angular.module / factory / controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $scope.items = ...;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is very simplified, but via its modules/factories/controllers, the AngularJS code handles how the JSON feeds are displayed in the page. It pulls in the JSON and can massage it for use by the ng- attributes, etc.&lt;/p&gt;
&lt;p&gt;I don’t have to use AngularJS to do this—​I could use a Template::Toolkit template delivered by Dancer, or any number of other templating systems. However, I like this method, because it doesn’t require a Perl developer to use. Rather, any competent JavaScript developer can take this and run with it.&lt;/p&gt;
&lt;h3 id=&#34;migration&#34;&gt;Migration&lt;/h3&gt;
&lt;p&gt;Now the migration of my entire app to Dancer is much easier. I gave it a whirl with a handful of routes and modules, to test the waters. It went great.&lt;/p&gt;
&lt;p&gt;For my modules that were the “App” (not the “Web App” and dependent on the Legacy App), very few changes were necessary. Here is an example of my original module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Feedback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$app&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;( ... );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;list&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$app&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Need code&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$rows&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$app&lt;/span&gt;-&amp;gt;dbh(&lt;span style=&#34;color:#369&#34;&gt;$feedback_table&lt;/span&gt;)-&amp;gt;...;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$rows&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You’ll see that I am using a class called MyApp. I did this to get a custom die and a database handle. This isn’t really the proper way to do this (I’m learning), but it worked at the time.&lt;/p&gt;
&lt;p&gt;Now, after converting that module for use with Dancer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Feedback&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Moo&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;with &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::&lt;/span&gt;HasDatabase;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;list&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Need code&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$rows&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;dbh&lt;/span&gt;-&amp;gt;...;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$rows&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My custom die has been replaced with a Perl die. Also, I am now using a &lt;a href=&#34;https://metacpan.org/pod/Moo::Role&#34;&gt;Moo::Role&lt;/a&gt; for my database handle. And that’s all I changed!&lt;/p&gt;
&lt;h4 id=&#34;before&#34;&gt;Before&lt;/h4&gt;
&lt;p&gt;The biggest improvements were in things that I “stole” from Dancer. (Naturally, Dancer would do things better than I.) This is my Legacy App’s route for displaying and accepting feedback entries. It does not show any authentication checks. It handles feeding back an array of entries for an item (“list”), a single entry (GET), and saving an entry (POST):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;_route_feedback&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; (&lt;span style=&#34;color:#038&#34;&gt;undef&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$sub_action&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt;) = &lt;span style=&#34;color:#038&#34;&gt;split&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;route;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt; ||= &lt;span style=&#34;color:#369&#34;&gt;$sub_action&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_status(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;400 Bad Request&amp;#39;&lt;/span&gt;);   &lt;span style=&#34;color:#888&#34;&gt;# start with 400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Feedback&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$sub_action&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        when (&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedbacks&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;list(&lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_tmp( to_json(&lt;span style=&#34;color:#369&#34;&gt;$feedbacks&lt;/span&gt;) );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_path(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;special/json&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_content_type(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;application/json; charset=UTF-8&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_status(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;200 OK&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedbacks&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        default {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;method) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                when (&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$row&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;get(&lt;span style=&#34;color:#369&#34;&gt;$code&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_route_error;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_tmp( to_json(&lt;span style=&#34;color:#369&#34;&gt;$row&lt;/span&gt;) );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_path(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;special/json&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_content_type(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;application/json; charset=UTF-8&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_status(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;200 OK&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$row&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                when (&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$params&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;body_parameters
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_route_error;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$params&lt;/span&gt; = from_json(&lt;span style=&#34;color:#369&#34;&gt;$params&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$result&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;save(&lt;span style=&#34;color:#369&#34;&gt;$params&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_status(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;200 OK&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$result&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_path(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;special/json&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#369&#34;&gt;$self&lt;/span&gt;-&amp;gt;_set_content_type(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;application/json; charset=UTF-8&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;after&#34;&gt;After&lt;/h4&gt;
&lt;p&gt;Here are those same routes in Dancer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prefix &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/feedback&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Feedback&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/list/:id&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;list( param &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;id&amp;#39;&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/:code&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;get( param &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$feedback&lt;/span&gt;-&amp;gt;save( &lt;span style=&#34;color:#038&#34;&gt;scalar&lt;/span&gt; params );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dancer gives me a lot for free. It is a &lt;em&gt;lot&lt;/em&gt; simpler. There’s still no authentication shown here, but everything else is done. (And I can use an &lt;a href=&#34;http://p3rl.org/Dancer2::Plugin::Auth::Extensible&#34;&gt;authentication plugin&lt;/a&gt; to make even that easy.)&lt;/p&gt;
&lt;h3 id=&#34;tmtowtdi&#34;&gt;TMTOWTDI&lt;/h3&gt;
&lt;p&gt;For the front-end, we have options on how to use Dancer. We could have Dancer deliver the HTML files that contain AngularJS. Or, we could have the web server deliver them, as there is nothing special about them that says Dancer must deliver them. In fact, this is especially easy if our AngularJS code is a &lt;a href=&#34;https://en.wikipedia.org/wiki/Single-page_application&#34;&gt;Single Page App&lt;/a&gt;, which is a single static HTML file with AngularJS “routes”. If we did this, and needed to handle authentication, we could look at using &lt;a href=&#34;http://jwt.io/&#34;&gt;JSON Web Tokens&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;now-starring-dancer&#34;&gt;Now starring Dancer&lt;/h3&gt;
&lt;p&gt;In hindsight, I probably should have moved to Dancer right away. The Legacy App was a pain to work with, as I built my own Routing module for it, and I also built my own Auth checking module. Dancer makes all this simpler.&lt;/p&gt;
&lt;p&gt;In the process, though, I learned something&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;dancer-is-better&#34;&gt;Dancer is better?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;I learned you can use tools improperly&lt;/em&gt;. You can do Dancer “wrong”. You can write tag soup in anything, even the best modern tools.&lt;/p&gt;
&lt;p&gt;You can stuff all your business logic into Template::Toolkit tags. You can stuff logic into Dancer routes. You can do AngularJS “wrong” (I probably do).&lt;/p&gt;
&lt;h3 id=&#34;dancer-is-better-1&#34;&gt;Dancer is better:&lt;/h3&gt;
&lt;p&gt;Dancer is better when (thanks to &lt;a href=&#34;https://twitter.com/shadowcat_mst&#34;&gt;Matt S Trout&lt;/a&gt; for these):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Routes contain code specific to the Web.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routes call non-Dancer modules&lt;/strong&gt; (where business logic lives; again, &lt;em&gt;Web App + App&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The route returns the data in the appropriate format.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These make it easy to test. You are effectively talking to your back-end code as if it’s an API. &lt;em&gt;Because it is.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The point is: start improving somewhere. Maybe you cannot write tests in everything, but you can try to write smart code.&lt;/p&gt;
&lt;h3 id=&#34;lessons-learned&#34;&gt;Lessons learned&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Separate concerns&lt;/li&gt;
&lt;li&gt;Keep it testable&lt;/li&gt;
&lt;li&gt;Just start somewhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The end. Or maybe the beginning&amp;hellip;&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Perl Dancer Conference 2015 Report—​Conference Days</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/10/perl-dancer-conference-2015-report_30/"/>
      <id>https://www.endpointdev.com/blog/2015/10/perl-dancer-conference-2015-report_30/</id>
      <published>2015-10-30T00:00:00+00:00</published>
      <author>
        <name>Josh Lavin</name>
      </author>
      <content type="html">
        &lt;p&gt;In my &lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report/&#34;&gt;last post&lt;/a&gt;, I shared about the Training Days from the &lt;a href=&#34;https://www.perl.dance/&#34;&gt;Perl Dancer&lt;/a&gt; 2015 conference, in Vienna, Austria. This post will cover the two days of the conference itself.&lt;/p&gt;
&lt;p&gt;While there were &lt;em&gt;several&lt;/em&gt; wonderful talks, &lt;a href=&#34;https://www.perl.dance/users/21&#34;&gt;Gert van der Spoel&lt;/a&gt; did a great job of writing recaps of all of them (&lt;a href=&#34;https://www.perl.dance/wiki/node/2015%20Day%201%20Summary&#34;&gt;Day 1&lt;/a&gt;, &lt;a href=&#34;https://www.perl.dance/wiki/node/2015%20Day%202%20Summary&#34;&gt;Day 2&lt;/a&gt;), so here I’ll cover the ones that stood out most to me.&lt;/p&gt;
&lt;h3 id=&#34;day-one&#34;&gt;Day One&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center; float:right&#34;&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-0-big.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-0.jpeg&#34;/&gt;&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;small&gt;&lt;a href=&#34;https://twitter.com/sukria/status/657098210989776896&#34;&gt;Dancer Conference, by Alexis Sukrieh&lt;/a&gt; (used with permission)&lt;/small&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/PerlSawyer&#34;&gt;Sawyer X&lt;/a&gt; spoke on the &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/17-state-of-dancer&#34;&gt;State of Dancer&lt;/a&gt;&lt;/em&gt;. One thing mentioned, which came up again later in the conference, was: &lt;strong&gt;Make the effort, move to Dancer 2! Dancer 1 is frozen.&lt;/strong&gt; There have been some recent changes to Dancer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Middlewares for static files, so these are handled outside of Dancer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;New &lt;a href=&#34;http://p3rl.org/Hash::MultiValue&#34;&gt;Hash::MultiValue&lt;/a&gt; parameter keywords (route_parameters, query_parameters, body_parameters; covered in my &lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report/&#34;&gt;earlier post&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://metacpan.org/pod/Dancer2::Manual#Delayed-responses-Async-Streaming&#34;&gt;Delayed responses&lt;/a&gt; (asynchronous) with delayed keyword:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Runs on the server after the request has finished.&lt;/li&gt;
&lt;li&gt;Streaming is also asynchronous, feeding the user chunks of data at a time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Items coming soon to Dancer may include: Web Sockets (supported in &lt;a href=&#34;http://p3rl.org/Plack&#34;&gt;Plack&lt;/a&gt;), per-route &lt;a href=&#34;https://metacpan.org/pod/Dancer2::Manual#Serializers1&#34;&gt;serialization&lt;/a&gt; (currently enabling a serializer such as JSON affects the entire app—​later on, &lt;a href=&#34;https://twitter.com/veryrusty&#34;&gt;Russell&lt;/a&gt; &lt;a href=&#34;http://p3rl.org/Dancer2::Plugin::SendAs&#34;&gt;released a module&lt;/a&gt; for this, which may make it back into the core), Dancer2::XS, and &lt;a href=&#34;https://github.com/PerlDancer/perl-lint-policy-dancer2&#34;&gt;critic/linter policies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/domm_favors_irc&#34;&gt;Thomas Klausner&lt;/a&gt; shared about &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/18-oauth2%2C-resty-apis%2C-microservices&#34;&gt;OAuth &amp;amp; Microservices&lt;/a&gt;&lt;/em&gt;. Microservices are a good tool to manage complexity, but you might want to aim for “monolith first”, &lt;a href=&#34;http://martinfowler.com/bliki/MonolithFirst.html&#34;&gt;according to Martin Fowler&lt;/a&gt;, and only later break up your app into microservices. In the old days, we had “fat” back-ends, which did everything and delivered the results to a browser. Now, we have “fat” front-ends, which take info from a back-end and massage it for display. One advantage of the microservice way of thinking is that mobile devices (or even third parties) can access the same APIs as your front-end website.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://oauth.net/&#34;&gt;OAuth&lt;/a&gt; allows a user to login at your site, using their credentials from another site (such as Facebook or Google), so they don’t need a password for your site itself. This typically happens via JavaScript and cookies. However, to make your back-end “stateless”, you could use &lt;a href=&#34;https://jwt.io/&#34;&gt;JSON Web Tokens&lt;/a&gt; (JWT). Thomas showed some examples of all this in action, using the &lt;a href=&#34;http://p3rl.org/OX&#34;&gt;OX Perl module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One thing I found interesting that Thomas mentioned: &lt;em&gt;Plack middleware is the correct place to implement most of the generic part of a web app. The framework is the wrong part.&lt;/em&gt; I think this mindset goes along with Sawyer’s comments about &lt;em&gt;Web App + App&lt;/em&gt; in the Training Days.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/0xMickey&#34;&gt;Mickey Nasriachi&lt;/a&gt; &lt;a href=&#34;https://www.perl.dance/talks/25-ponapi%3A-eliminate-the-bikesheding&#34;&gt;shared&lt;/a&gt; his development on &lt;a href=&#34;https://github.com/mickeyn/ponapi&#34;&gt;PONAPI&lt;/a&gt;, which implements the &lt;a href=&#34;http://jsonapi.org/&#34;&gt;JSON API&lt;/a&gt; specification in Perl. The JSON API spec is a standard for creating APIs. It essentially absolves you from having to make decisions about how you should structure your API.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center; float:right&#34;&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-1-big.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-1.jpeg&#34;/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;
&lt;small&gt;Panorama from the south tower of St. Stephen’s cathedral, by this author&lt;/small&gt;&lt;/div&gt;
&lt;p&gt;Gert presented on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/9-social-logins-for-e-commerce-sites&#34;&gt;Social Logins &amp;amp; eCommerce&lt;/a&gt;&lt;/em&gt;. This built on the earlier OAuth talk by Thomas. Here are some of the pros/cons to social login which Gert presented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pros—​customer:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Alleviates “password fatigue”&lt;/li&gt;
&lt;li&gt;Convenience&lt;/li&gt;
&lt;li&gt;Brand familiarity (with the social login provider)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pros—​eCommerce website:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Expected customer retention&lt;/li&gt;
&lt;li&gt;Expected increase in sales&lt;/li&gt;
&lt;li&gt;Better target customers&lt;/li&gt;
&lt;li&gt;“Plug &amp;amp; Play” (if you pay)—​some services exist to make it simple to integrate social logins, where you just integrate with them, and then you are effectively integrated with whatever social login providers they support. These include Janrain and LoginRadius&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons—​customer:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Privacy concerns (sharing their social identity with your site)&lt;/li&gt;
&lt;li&gt;Security concerns (if their social account is hacked, so are all their accounts where they have used their social login)&lt;/li&gt;
&lt;li&gt;Confusion (especially on how to leave a site)&lt;/li&gt;
&lt;li&gt;Usefulness (no address details are provided by the social provider in the standard scope, so the customer still has to enter extra details on your site)&lt;/li&gt;
&lt;li&gt;Social account hostages (if you’ve used your social account to login elsewhere, you are reluctant to shut down your social account)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons—​eCommerce website:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Legal implications&lt;/li&gt;
&lt;li&gt;Implementation hurdles&lt;/li&gt;
&lt;li&gt;Usefulness&lt;/li&gt;
&lt;li&gt;Provider problem is your problem (e.g., if the social login provider goes down, all your customers who use it to login are unable to login to your site)&lt;/li&gt;
&lt;li&gt;Brand association (maybe you don’t want your site associated with certain social sites)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons—​social provider:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Šimun Kodžoman spoke on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/22-dancer-%2B-meteor-%3D-mobile-app&#34;&gt;Dancer + Meteor = mobile app&lt;/a&gt;&lt;/em&gt;. &lt;a href=&#34;https://www.meteor.com/&#34;&gt;Meteor&lt;/a&gt; is a JavaScript framework for both server-side and client-side. It seems one of the most interesting aspects is you can use Meteor with the Android or iOS SDK to auto-generate a true mobile app, which has many more advantages than a simple HTML “app” created with &lt;a href=&#34;http://phonegap.com/&#34;&gt;PhoneGap&lt;/a&gt;. Šimun is using Dancer as a back-end for Meteor, because the server-side Meteor aspect is still new and unstable, and is also dependent on &lt;a href=&#34;https://www.mongodb.org/&#34;&gt;MongoDB&lt;/a&gt;, which cannot be used for everything.&lt;/p&gt;
&lt;p&gt;End Point’s own Sam Batschelet shared his work on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/4-space-camp---the-final-frontier&#34;&gt;Space Camp&lt;/a&gt;&lt;/em&gt;, a new container-based setup for development environments. This pulls together several pieces, including &lt;a href=&#34;https://coreos.com/&#34;&gt;CoreOS&lt;/a&gt;, &lt;a href=&#34;http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html&#34;&gt;systemd-nspawn&lt;/a&gt;, and &lt;a href=&#34;https://coreos.com/etcd/&#34;&gt;etcd&lt;/a&gt; to provide a futuristic version of &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;day-two&#34;&gt;Day Two&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center; float:right&#34;&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-2-big.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/image-2.jpeg&#34;/&gt;&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;&lt;small&gt;&lt;a href=&#34;https://twitter.com/sbatschelet/status/657493819135541248&#34;&gt;Conference goers, by Sam&lt;/a&gt;&lt;br/&gt;(used with permission)&lt;/small&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/pullingshots&#34;&gt;Andrew Baerg&lt;/a&gt; spoke on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/20-taming-a-thousand-pound-gorilla&#34;&gt;Taming the 1000-lb Gorilla&lt;/a&gt;&lt;/em&gt; that is &lt;a href=&#34;https://www.interchangecommerce.org/&#34;&gt;Interchange 5&lt;/a&gt;. He shared how they have endeavored to manage their Interchange development in more modern ways, such as using unit tests and &lt;a href=&#34;http://p3rl.org/DBIx::Class&#34;&gt;DBIC&lt;/a&gt;. One item I found especially interesting was the use of &lt;a href=&#34;http://p3rl.org/DBIx::Class::Fixtures&#34;&gt;DBIx::Class::Fixtures&lt;/a&gt; to allow saving bits of information from a database to keep with a test. This is helpful when you have a bug from some database entry which you want to fix and ensure stays fixed, as databases can change over time, and without a “fixture” your test would not be able to run.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/veryrusty&#34;&gt;Russell Jenkins&lt;/a&gt; shared &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/24-howto-contributeto-dancer2&#34;&gt;HowTo Contribute to Dancer 2&lt;/a&gt;&lt;/em&gt;. He went over the use of &lt;a href=&#34;https://git-scm.com/&#34;&gt;Git&lt;/a&gt;, including such helpful commands and tips as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;git status &amp;ndash;short &amp;ndash;branch&lt;/li&gt;
&lt;li&gt;Write good commit messages: one line summary, less than 50 characters; longer description, wrapped to 72 characters; refer to and/or close issues&lt;/li&gt;
&lt;li&gt;Work in a branch (you shall not commit to master)&lt;/li&gt;
&lt;li&gt;“But I committed to master” &amp;ndash;&amp;gt; branch and reset&lt;/li&gt;
&lt;li&gt;git log &amp;ndash;oneline &amp;ndash;since=2.weeks&lt;/li&gt;
&lt;li&gt;git add &amp;ndash;fixup &lt;SHA1 hash&gt;&lt;/li&gt;
&lt;li&gt;The use of branches named with “feature/whatever” or “bugfix/whatever” can be helpful (this is Russell’s convention)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are several &lt;a href=&#34;https://github.com/PerlDancer/Dancer2/issues?q=is%3Aopen+is%3Aissue+label%3A%22Beginner+Suitable%22&#34;&gt;Dancer 2 issues tagged “beginner suitable”&lt;/a&gt;, so it is easy for nearly anyone to contribute. The &lt;a href=&#34;http://perldancer.org/&#34;&gt;Dancer website&lt;/a&gt; is &lt;a href=&#34;https://github.com/PerlDancer/perldancer-website&#34;&gt;also on GitHub&lt;/a&gt;. You can even make simple edits directly in GitHub!&lt;/p&gt;
&lt;p&gt;It was great to have the author of Dancer, &lt;a href=&#34;https://twitter.com/sukria&#34;&gt;Alexis Sukrieh&lt;/a&gt;, in attendance. He shared his original vision for Dancer, which filled a gap in the Perl ecosystem back in 2009. The goal for Dancer was to create a DSL (&lt;a href=&#34;https://en.wikipedia.org/wiki/Domain-specific_language&#34;&gt;Domain-specific language&lt;/a&gt;) to provide a very simple way to develop web applications. The DSL provides “&lt;a href=&#34;https://metacpan.org/pod/Dancer2::Manual#DSL-KEYWORDS&#34;&gt;keywords&lt;/a&gt;” for use in the Dancer app, which are specific to Dancer (basically extra functionality for Perl). One of the core aspects of keeping it simple was to avoid the use of $self (a standby of object-oriented Perl, one of the things that you just “have to do”, typically).&lt;/p&gt;
&lt;p&gt;Alexis mentioned that &lt;strong&gt;Dancer 1 is frozen—​Dancer 2 full-speed ahead!&lt;/strong&gt; He also shared some of his learnings along the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fill a gap (define clearly the problem, present your solution)&lt;/li&gt;
&lt;li&gt;Stick to your vision&lt;/li&gt;
&lt;li&gt;Code is not enough (opensource needs attention; marketing matters)&lt;/li&gt;
&lt;li&gt;Meet in person (collaboration is hard; online collaboration is very hard)&lt;/li&gt;
&lt;li&gt;Kill the ego—​you are not your code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While at the conference, Alexis even wrote a Dancer2 plugin, &lt;a href=&#34;https://metacpan.org/pod/Dancer2::Plugin::ProbabilityRoute&#34;&gt;Dancer2::Plugin::ProbabilityRoute&lt;/a&gt;, which allows you to do &lt;a href=&#34;https://en.wikipedia.org/wiki/A/B_testing&#34;&gt;A/B Testing&lt;/a&gt; in your Dancer app. (Another similar plugin is &lt;a href=&#34;https://metacpan.org/pod/Dancer2::Plugin::Sixpack&#34;&gt;Dancer2::Plugin::Sixpack&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Also check out &lt;a href=&#34;https://web.archive.org/web/20151108214937/http://blog.sukria.net/2015/10/22/perl-dancer-2015-report/&#34;&gt;Alexis’ recap&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, I was privileged to speak as well, on &lt;em&gt;&lt;a href=&#34;https://www.perl.dance/talks/11-angularjs-%26-dancer-for-modern-web-development&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development&lt;/a&gt;&lt;/em&gt;. Since this post is already pretty long, I’ll save the details for &lt;a href=&#34;/blog/2015/10/angularjs-dancer-for-modern-web/&#34;&gt;another post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;In summary, the Perl Dancer conference was a great time of learning and building community. If I had to wrap it all up in one insight, it would be: &lt;strong&gt;Web App + App&lt;/strong&gt;—​that is, your &lt;strong&gt;application should be a compilation of: Plack middleware, Web App (Dancer), and App (Perl classes and methods)&lt;/strong&gt;.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Perl Dancer Conference 2015 Report — Training Days</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/10/perl-dancer-conference-2015-report/"/>
      <id>https://www.endpointdev.com/blog/2015/10/perl-dancer-conference-2015-report/</id>
      <published>2015-10-28T00:00:00+00:00</published>
      <author>
        <name>Josh Lavin</name>
      </author>
      <content type="html">
        &lt;p&gt;I just returned from the &lt;a href=&#34;https://www.perl.dance/&#34;&gt;Perl Dancer Conference&lt;/a&gt;, held in Vienna, Austria. It was a jam-packed schedule of two days of training and two conference days, with five of the nine Dancer core developers in attendance.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float:right; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report/image-0-big.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34; title=&#34;Vienna&#34;&gt;&lt;img alt=&#34;[image of Vienna]&#34; border=&#34;0&#34; src=&#34;/blog/2015/10/perl-dancer-conference-2015-report/image-0.jpeg&#34;/&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;small&gt;Kohlmarkt street, Wien, by this author&lt;/small&gt;&lt;/div&gt;
&lt;p&gt;If you aren’t familiar with &lt;a href=&#34;http://www.perldancer.org/&#34;&gt;Perl Dancer&lt;/a&gt;, it is a modern framework for Perl for building web applications. Dancer1 originated as a port of Ruby’s Sinatra project, but has officially been replaced with a rewrite called Dancer2, based on &lt;a href=&#34;https://metacpan.org/pod/Moo&#34;&gt;Moo&lt;/a&gt;, with Dancer1 being frozen and only receiving security fixes. The Interchange 5 e-commerce package is gradually being replaced by Dancer plugins.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 1&lt;/strong&gt; began with a training on Dancer2 by &lt;a href=&#34;https://twitter.com/PerlSawyer&#34;&gt;Sawyer X&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/0xMickey&#34;&gt;Mickey Nasriachi&lt;/a&gt;, two Dancer core devs. During the training, the attendees worked on adding functionality to a &lt;a href=&#34;https://github.com/xsawyerx/dancer-training-vienna&#34;&gt;sample Dancer app&lt;/a&gt;. Some of my takeaways from the training:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Think of your app as a Dancer Web App &lt;em&gt;plus&lt;/em&gt; an App. These should ideally be two separate things, where the Dancer web app provides the URL routes for interaction with your App.&lt;/li&gt;
&lt;li&gt;The lib directory contains all of your application. The recommendation for large productions is to separate your app into separate namespaces and classes. Some folks use a routes directory just for routing code, with lib reserved for the App itself.&lt;/li&gt;
&lt;li&gt;It is recommended to add an empty .dancer file to your app’s directory, which indicates that this is a Dancer app (other Perl frameworks do similarly).&lt;/li&gt;
&lt;li&gt;When running your Dancer app in development, you can use plackup -R lib bin/app.psgi which will restart the app automatically whenever something changes in lib.&lt;/li&gt;
&lt;li&gt;Dancer handles all the standard HTTP verbs, except note that we must use del, not &lt;em&gt;delete&lt;/em&gt;, as &lt;em&gt;delete&lt;/em&gt; conflicts with the Perl keyword.&lt;/li&gt;
&lt;li&gt;There are new keywords for retrieving parameters in your routes. Whereas before we only had param or params, it is now recommended to use:
&lt;ul&gt;
&lt;li&gt;route_parameters,&lt;/li&gt;
&lt;li&gt;query_parameters, or&lt;/li&gt;
&lt;li&gt;body_parameters&lt;/li&gt;
&lt;li&gt;all of which can be used with -&amp;gt;get(&amp;lsquo;foo&amp;rsquo;) which is always a single scalar, or -&amp;gt;get_all(&amp;lsquo;foo&amp;rsquo;) which is always a list.&lt;/li&gt;
&lt;li&gt;These allow you to specify which area you want to retrieve parameters from, instead of being unsure which param you are getting, if identical names are used in multiple areas.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 2&lt;/strong&gt; was &lt;a href=&#34;https://metacpan.org/pod/DBIx::Class&#34;&gt;DBIx::Class&lt;/a&gt; training, led by &lt;a href=&#34;https://twitter.com/PerlRacke&#34;&gt;Stefan Hornburg&lt;/a&gt; and Peter Mottram, with assistance from &lt;a href=&#34;https://twitter.com/ribasushi&#34;&gt;Peter Rabbitson&lt;/a&gt;, the DBIx::Class maintainer.&lt;/p&gt;
&lt;p&gt;DBIx::Class (a.k.a. DBIC) is an &lt;a href=&#34;https://en.wikipedia.org/wiki/Object-relational_mapping&#34;&gt;Object Relational Mapper&lt;/a&gt; for Perl. It exists to provide a standard, object-oriented way to deal with SQL queries. I am new to DBIC, and it was a lot to take in, but at least one advantage I could see was helping a project be able to change database back-ends, without having to rewrite code (cue PostgreSQL vs MySQL arguments).&lt;/p&gt;
&lt;p&gt;I took copious notes, but it seems that the true learning takes place only as one begins to implement and experiment. Without going into too much detail, some of my notes included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Existing projects can use dbicdump to quickly get a DBIC schema from an existing database, which can be modified afterwards. For a new project, it is recommended to write the schema first.&lt;/li&gt;
&lt;li&gt;DBIC allows you to place business logic in your application (not your web application), so it is easier to test (once again, the recurring theme of &lt;em&gt;Web App + App&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;ResultSet&lt;/em&gt; is a representation of a query before it happens. On any ResultSet you can call -&amp;gt;as_query to find the actual SQL that is to be executed.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://p3rl.org/DBIx::Class::Schema::Config&#34;&gt;DBIx::Class::Schema::Config&lt;/a&gt; provides credential management for DBIC, and allows you to move your DSN/username/password out of your code, which is especially helpful if you use Git or a public GitHub.&lt;/li&gt;
&lt;li&gt;DBIC is all about relationships (belongs_to, has_many, might_have, and has_one). many_to_many is not a relationship per se but a convenience.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://p3rl.org/DBIx::Class::Candy&#34;&gt;DBIx::Class::Candy&lt;/a&gt; provides prettier, more modern metadata, but cannot currently be generated by dbicdump.&lt;/li&gt;
&lt;li&gt;For deployment or migration, two helpful tools are &lt;a href=&#34;http://sqitch.org/&#34;&gt;Sqitch&lt;/a&gt; and &lt;a href=&#34;http://p3rl.org/DBIx::Class::DeploymentHandler&#34;&gt;DBIx::Class::DeploymentHandler&lt;/a&gt;. Sqitch is better for raw SQL, while DeploymentHandler is for DBIC-managed databases. These provide easy ways to migrate, deploy, upgrade, or downgrade a database.&lt;/li&gt;
&lt;li&gt;Finally, &lt;a href=&#34;http://www.rapidapp.info/&#34;&gt;RapidApp&lt;/a&gt; can read a database file or DBIC schema and provide a nice web interface for interacting with a database. As long as you define your columns properly, RapidApp can generate image fields, rich-text editors, date-pickers, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The training days were truly like drinking from a firehose, with so much good information. I am looking forward to putting this into practice!&lt;/p&gt;
&lt;p&gt;Stay tuned for my &lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/&#34;&gt;next blog post&lt;/a&gt; on the Conference Days.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Documenting web services with Perl POD and AJAX</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/06/documenting-web-services-with-perl-pod/"/>
      <id>https://www.endpointdev.com/blog/2015/06/documenting-web-services-with-perl-pod/</id>
      <published>2015-06-26T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;Perl POD is a handy, convenient, but low-tech approach to embedded documentation. Consider a web service in &lt;a href=&#34;http://www.perldancer.org&#34;&gt;Dancer&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#038&#34;&gt;time&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;scalar&lt;/span&gt;(&lt;span style=&#34;color:#038&#34;&gt;localtime&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Disclaimer: my actual use-case of this technique was even more legacy: I was documenting &lt;a href=&#34;http://interchange.rtfm.info/icdocs/config/ActionMap.html&#34;&gt;Interchange Actionmaps&lt;/a&gt; that returned images, JSON, etc.)&lt;/p&gt;
&lt;p&gt;Your application might have several, or even dozens of these, with various parameters, returning data in JSON or TXT or CSV or who-knows-what.
I chose to document these in Perl &lt;a href=&#34;http://perldoc.perl.org/perlpod.html&#34;&gt;POD (Plain Old Documentation)&lt;/a&gt; format, e.g.,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=pod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=head1 time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Retrieves the current time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=over 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=item Parameters
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;None.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=item Example
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=begin html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;script src=&amp;#34;/js/example-time.js&amp;#34; type=&amp;#34;text/javascript&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=end html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=back
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=cut&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This block gets inserted right in-line with the web service code, so it’s immediately obvious to anyone maintaining it (and thus has the best chance of being maintained if and when the code changes!). Now I can generate an HTML page directly from my Perl code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pod2html MyPackage.pm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Your output looks something like this (excerpted for clarity):&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3 id=&#34;time&#34;&gt;&lt;a href=&#34;&#34;&gt;time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Retrieves the current time
&lt;strong&gt;&lt;a href=&#34;&#34;&gt;Parameters&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;&#34;&gt;Example&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Where the magic comes in is the JavaScript code that allows an in-line example, live and accurate, within the documentation page. You’ll actually get something more like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3 id=&#34;time-1&#34;&gt;&lt;a href=&#34;&#34;&gt;time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Retrieves the current time
&lt;strong&gt;&lt;a href=&#34;&#34;&gt;Parameters&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;&#34;&gt;Example&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;input type=&#34;submit&#34; value=&#34;Get data&#34;&gt;
&lt;input type=&#34;button&#34; value=&#34;Hide result&#34; name=&#34;hide&#34;&gt;
&lt;p&gt;(results appear here)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Note that the code I have below is not factored by choice; I could move a lot of it out to a common routine, but for clarity I’m leaving it all in-line. I am breaking up the script into a few chunks for discussion, but you can and should construct it all into one file (in my example, “js/example-time.js”).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* example-time.js */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$(&lt;span style=&#34;color:#038&#34;&gt;document&lt;/span&gt;).ready(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;script[src$=&amp;#34;/example-time.js&amp;#34;]&amp;#39;&lt;/span&gt;).after(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;form action=&amp;#39;\&amp;#34;/time\&amp;#34;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Note 1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;input data\&amp;#34;=&amp;#34;&amp;#34; type=&amp;#39;\&amp;#34;submit\&amp;#34;&amp;#39; value=&amp;#39;\&amp;#34;Get&amp;#39;/&amp;gt;&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;input name=&amp;#34;&lt;/span&gt;hide&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; none\&amp;#34;=&amp;#34;&amp;#34; result\&amp;#34;=&amp;#34;&amp;#34; style=&amp;#39;\&amp;#34;display:&amp;#39; type=&amp;#39;\&amp;#34;button\&amp;#34;&amp;#39; value=&amp;#39;\&amp;#34;Hide&amp;#39;/&amp;gt;&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;/form&amp;gt;&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;div id=&amp;#39;\&amp;#34;time-result\&amp;#34;&amp;#39;&amp;gt;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note 1: This being a painfully simple example of a web service, there are no additional inputs. If you have some, you would add them to the HTML being assembled into the &lt;form&gt; tag, and then using jQuery, add them below to the url parameter, or into the data structure as required by your particular web service.&lt;/p&gt;
&lt;p&gt;This step just inserts a simple &lt;form&gt; into the document. I chose to embed the form into the JavaScript code, rather than the POD, because it reduces the clutter and separates the example from the web service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; $form = $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;form[action=&amp;#34;/time&amp;#34;]&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    $form.submit(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      $.ajax(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;url&amp;#39;&lt;/span&gt;: $form.attr(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;action&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#888&#34;&gt;/* Note 1 also */&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataType&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;async&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(data){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#time-result&amp;#39;&lt;/span&gt;).html($(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;pre;//&amp;gt;&amp;#39;&lt;/span&gt;).html(data))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     .addClass(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;json&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             },&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we have a submit handler that performs a very simple AJAX submit using the form’s information, and upon success, inserts the results into a result &lt;div&gt; as a pre-formatted block. I added a “json” class which just tweaks the font and other typographic presentation a bit; you can provide your own if you wish.&lt;/p&gt;
&lt;p&gt;I’m aware that there are various jQuery &lt;a href=&#34;http://malsup.com/jquery/form/&#34;&gt;plug-ins&lt;/a&gt; that will handle AJAX-ifying a form, but I couldn’t get the exact behavior I wanted on my first tries, so I bailed out and just constructed this approach.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#time-result&amp;#39;&lt;/span&gt;).html(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Error retrieving data!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     .removeClass(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;json&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(That stray-looking comment above is just a work-around for the syntax highlighter.)&lt;/p&gt;
&lt;p&gt;Error handling goes here. If you have something more comprehensive, such as examining the result for error codes or messages, this is where you’d put it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 $form.find(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;input[name=&amp;#34;hide&amp;#34;]&amp;#39;&lt;/span&gt;).show();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }).find(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;input[type=&amp;#34;button&amp;#34;]&amp;#39;&lt;/span&gt;).click(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#time-result&amp;#39;&lt;/span&gt;).html(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And just a bit of UI kindness: we have a “hide” button to make the example go away. Some of my actual examples ran to dozens of lines of JSON output, so I wanted a way to clean up after the example.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Filling in header elements with Dancer and Template::Flute</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/02/filling-in-header-elements-with-dancer/"/>
      <id>https://www.endpointdev.com/blog/2015/02/filling-in-header-elements-with-dancer/</id>
      <published>2015-02-05T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;Inserting content into &lt;a href=&#34;http://perldancer.org/&#34;&gt;Dancer&lt;/a&gt; output files involves using a templating system. One such is &lt;a href=&#34;http://search.cpan.org/~hornburg/Template-Flute-0.0160/lib/Template/Flute.pm&#34;&gt;Template::Flute&lt;/a&gt;. In its simplest possible explanation, it takes a Perl hash, an XML file, and an HTML template, and produces a finished HTML page.&lt;/p&gt;
&lt;p&gt;For a project involving Dancer and Template::Flute, I needed a way to prepare each web page with its own set of JavaScript and CSS files. One way is to construct separate layout files for each different combination of .js and .css, but I figured there had to be a better way.&lt;/p&gt;
&lt;p&gt;Here’s what I came up with: I use one layout for all my typical pages, and within the header, I have:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/css/additional.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/javascripts/additional.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The trick here is, there’s no such files “additional.css” and “additional.js”. Instead, those are placeholders for the actual CSS and JS files I want to link into each HTML file.&lt;/p&gt;
&lt;p&gt;My Perl object has these fields (in addition to the other content):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$context&lt;/span&gt;-&amp;gt;{additional_styles}    = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/css/checkout.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/css/colorbox.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$context&lt;/span&gt;-&amp;gt;{additional_scripts}   = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/javascripts/sprintf.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/javascripts/toCurrency.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/javascripts/jquery.colorbox-min.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/javascripts/checkout.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;while my XML file looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;specification&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;list&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;iterator=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_styles&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;param&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;field=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;target=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;href&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/list&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;list&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;iterator=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_scripts&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;param&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;field=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;target=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/list&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/specification&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So we have all the elements, but unless you have used all this before, you may not realize how we get the output. (Skip to the punchline if that’s not true.)&lt;/p&gt;
&lt;p&gt;The XML file is a connector that tells Template::Flute how to mix the Perl hash into the HTML template. Usually you connect things via class names, so in the case of:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/css/additional.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;the class name in the HTML and the name field in the XML connect, while the iterator field in the XML and the hash key in the Perl hashref do as well. The case of a&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;list&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;means that the hash value must be an arrayref of hashrefs, i.e.,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; =&amp;gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		{ url =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		...,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Important note: if the hash value is undefined, you’ll get a run-time error when you try to expand the HTML template, and if you have an empty arrayref, the result of the expansion is an empty string (which is just what you want).&lt;/p&gt;
&lt;p&gt;And so, through the magic of Template::Flute, what the browser sees is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/css/checkout.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/css/colorbox.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_style&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/css/admin/admin.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;/&amp;gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/javascripts/sprintf.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/javascripts/toCurrency.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/javascripts/jquery.colorbox-min.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;additional_script&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/javascripts/checkout.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Cleaner redirection in Perl Dancer</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/01/cleaner-redirection-in-perl-dancer/"/>
      <id>https://www.endpointdev.com/blog/2015/01/cleaner-redirection-in-perl-dancer/</id>
      <published>2015-01-21T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;Recently I worked on a project using the Perl web application framework &lt;a href=&#34;http://www.perldancer.org&#34;&gt;Dancer&lt;/a&gt; that had multiple paths to order a product:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /product =&amp;gt; /cart =&amp;gt; /checkout =&amp;gt; /receipt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s the standard approach. Then there was a “phone order” approach:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /create_order =&amp;gt; /checkout =&amp;gt; /receipt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A “phone order” is one taken down (usually by phone), where the user who is logged in is not the same as the user who “owns” the order. Thus, one user is ordering on behalf of another: the order must be recorded as part of the second user’s order history, the various shipping and billing information must come from that user’s stored information, and even the product pricing has to be calculated as though that customer were doing the ordering rather than the logged-in user.&lt;/p&gt;
&lt;p&gt;As a consequence, the phone order page flow actually ended up as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; get /create_order =&amp;gt; post /create_order =&amp;gt; /checkout&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The submission of the /create_order page was processed in an environment that knew about this “proxy” ordering arrangement, thus could do some particularly special-case processing, and then the idea was to pass off to the /checkout page, which would finalize the order including payment information.&lt;/p&gt;
&lt;p&gt;All well and good, but when it came time to implement this, I was faced with a minor inconvenience and a bad choice:&lt;/p&gt;
&lt;p&gt;Since /checkout was itself a POSTed page, I needed to reach that page with a set of form parameters in hand. So my original plan was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/create_order&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ... &lt;span style=&#34;color:#888&#34;&gt;# do my special-case processing, and then:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   forward &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/checkout&amp;#39;&lt;/span&gt;, { param1 =&amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$value1&lt;/span&gt;, ... };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While this works, the problem is that “forward” as a Dancer directive doesn’t interact with the browser: it just interrupts your path handling of “/create_order” and resumes at “/checkout”. So the browser, innocent of these shenanigans, remains on “/create_order”. It would be so much cleaner (darn my OCD!) if the browser ended up at “/checkout”.&lt;/p&gt;
&lt;p&gt;That means you need to redirect the request, though. I.e.,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/create_order&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ... &lt;span style=&#34;color:#888&#34;&gt;# do my special-case processing, and then:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   redirect &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/checkout&amp;#39;&lt;/span&gt;;  &lt;span style=&#34;color:#888&#34;&gt;# hmm, something&amp;#39;s missing here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hmm, redirect doesn’t support a parameter hash. Oh, well, no problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   redirect url_for(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/checkout&amp;#39;&lt;/span&gt;, { param1 =&amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$value1&lt;/span&gt;, ... });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That gets the job done, but at a price: now instead of a nice, clean URL at my final destination, I get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   .../checkout?param1=value1&amp;amp;param2=...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, still not right. Some research and mailing-list inquiries led me to:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://programmers.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect&#34;&gt;
Why doesn’t HTTP have POST redirect?
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Short version: you can’t get there from here. Redirection is supposed to be “idempotent”, meaning you can repeat them without harm. That’s why when you refresh the page after a form submission, browsers will ask for permission to re-submit the form rather than just silently refreshing the page.&lt;/p&gt;
&lt;p&gt;So what’s the option? Well, I can think of two approaches here:&lt;/p&gt;
&lt;p&gt;One: instead of redirecting with parameters, store the parameters in the session:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/create_order&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ... &lt;span style=&#34;color:#888&#34;&gt;# do my special-case processing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   session &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;create_order_for_checkout&amp;#39;&lt;/span&gt; =&amp;gt; { param1 =&amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$value1&lt;/span&gt;, ... };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   redirect &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/checkout&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/checkout&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$params&lt;/span&gt; = (session &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;create_order_for_checkout&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     || params();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Two: do away with the post handler for ‘/create_order’ altogether, and move the processing inside the post handler for ‘/checkout’. The merits of that depend on how complex the /create_order handler is.&lt;/p&gt;
&lt;p&gt;I’m leaning toward the first approach, definitely.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Ecommerce Innovation 2013</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/10/ecommerce-innovation-2013/"/>
      <id>https://www.endpointdev.com/blog/2013/10/ecommerce-innovation-2013/</id>
      <published>2013-10-16T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;Mark Johnson and I went to the &lt;a href=&#34;http://www.ecommerce-innovation.com/&#34;&gt;Ecommerce Innovation 2013&lt;/a&gt; conference in beautiful Hancock, NY. The event was hosted by Sam Batschelet of &lt;a href=&#34;http://www.westbranchresort.com/&#34;&gt;West Branch Resort&lt;/a&gt;. The conference was spread out over three days and was very well planned. We had plenty of time in between talks to mingle with the other people. All of the talks were very insightful and informative. I found the mixture of technology and marketing talks beneficial. I have already discussed some things with my clients that I learned.&lt;/p&gt;
&lt;h3 id=&#34;a-brief-overview-of-the-talks&#34;&gt;A brief overview of the talks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Jure Kodzoman of &lt;a href=&#34;http://www.informa.si/&#34;&gt;Informa&lt;/a&gt; had two different subjects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;His first talk was about Template::Flute which is a Perl based template system which is the default template for Interchange 6. It utilizes the use of html classes to figure out where to parse in the data returned from your Perl code. Overall it seems pretty straight forward to use.&lt;/li&gt;
&lt;li&gt;His second talk was about the current state of the new Interchange 6 demo store.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ana Kozole of Informa had a talk named “Remarketing with Banners” that was really informative.The base of this is to have the ability to show specific banners to visitors on different websites.  She discussed different remarketing techniques including creating specific lists based on different criteria like all visitors, people who got to the checkout page but didn’t checkout or people who used a coupon code etc. You can also use remarketing lists for search ads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luka Klemenc of Informa gave two talks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He discussed some a CRM system that they had developed in house and some of the pros and cons.&lt;/li&gt;
&lt;li&gt;Luka gave us short talk about the ways to know whether or not your newsletter is effective.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Josh Lavin of &lt;a href=&#34;http://www.perusion.com&#34;&gt;Perusion&lt;/a&gt; talked about a new template for Interchange 5 called Strap which is based on &lt;a href=&#34;http://getbootstrap.com/2.3.2/&#34;&gt;Bootstrap&lt;/a&gt; version 2.3.2. With this new template they have created a bunch of page and url changes to make the stock Interchange much more SEO friendly. This also makes a few underlying changes like assuming the username to login would be your email address and creating a multiple page checkout.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mike Heins of Perusion gave us a brief history of Interchange and compared it to modern day frameworks like Dancer. He also gave us a brief overview of PCI compliance and how Interchange holds up. He introduced us to the features of the Perusion Payment Server which is a remote credit card processing system that helps with PCI compliance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stefan Hornburg of &lt;a href=&#34;http://www.linuxia.de/&#34;&gt;LinuXia Systems&lt;/a&gt; discussed two different topics with us.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gave us an overview of where the Interchange 6 project currently is and where it’s going. He gave us some code samples of the way we can do simple things like add an item to the cart, fetch the subtotal of the cart and talk to the database.&lt;/li&gt;
&lt;li&gt;Stefan walked us through an integration he did for OpenERP with Interchange 5 using RPC::XML.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;/team/mark-johnson/&#34;&gt;Mark Johnson&lt;/a&gt; gave us a review of the modifications to Interchange 5 to allow web servers like &lt;a href=&#34;http://www.nginx.com&#34;&gt;nginx&lt;/a&gt; or &lt;a href=&#34;http://www.apache.org&#34;&gt;Apache&lt;/a&gt; to cache entire pages. He discussed how we modified Interchange 5 for a customer to help with a DDoS attack. He laid out all of the new usertags and directives you will need to set to get pages to be cachable including some “gotchas” like not sending cookie information if you want this page to be cached. We hope that this feature will be included in the Interchange 5.8.1 release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sam Batschelet gave a talk about &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt; and the reasons why it is so great. He discussed things like using Perlbrew and Carton in camps to help get around the fact that most Linux operating systems ship with a pretty old version of Perl. He also expanded on a few features that we hope to get released soon.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last big item on the schedule was a 2 hour round table discussion about the database schema for Interchange 6. It was a very good discussion with many different opinions for adjustments. Most of us based our suggestions on past experience with clients. I do not think we are finished making adjustments to it but we are on the right path to a very flexible setup.&lt;/p&gt;
&lt;p&gt;Overall I thought the conference was a great success. It was great to meet in person some people I had only seen on a mailing list before and pass around ideas for the future. I cannot wait to see what cool new things we will have to discuss next year!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>First Dance: a Gentle Introduction to Dancer.pm for Web Services</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/10/first-dance-gentle-introduction-to/"/>
      <id>https://www.endpointdev.com/blog/2013/10/first-dance-gentle-introduction-to/</id>
      <published>2013-10-07T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;I’ve been dabbling in Dancer (&lt;a href=&#34;http://search.cpan.org/~yanick/Dancer-1.3118/lib/Dancer.pm&#34;&gt;Version One&lt;/a&gt;, not so much &lt;a href=&#34;https://web.archive.org/web/20131119231012/http://search.cpan.org/~sukria/Dancer2-0.10/lib/Dancer2.pm&#34;&gt;Version Two&lt;/a&gt;). Our first opportunity to create a production-worthy Dancer application just rolled out with encouraging results, so I thought I would outline some things we tried, and things we learned.  Don’t worry if you don’t know a thing about Dancer; I’ll educate you a little as we go along.&lt;/p&gt;
&lt;p&gt;First, some background. This application was a re-host and rewrite of an existing application written in JavaScript and plain old CGI Perl scripts, returning either HTML or fairly simple JSON objects. Even the database it connected to was ancient DBM files. Those files were created by extracting data from the main website’s database, so that part was easy to replace—​we just had to use the extraction queries (mostly) to connect directly.&lt;/p&gt;
&lt;p&gt;We chose Dancer as the platform for this effort because of its purely Perl footprint, and its relatively easy deployment.&lt;/p&gt;
&lt;p&gt;Since I didn’t really want to rewrite the front-end JavaScript code, I left that mostly as-is and concentrated on replacing the CGI scripts. The first step was to move all their code into a non-Dancer Perl module, which communicated with the outside world entirely in the form of hashrefs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;do_something_great&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$opt&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$output&lt;/span&gt; = {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# do something great!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$output&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, as a stop-gap measure, I replaced the innards of all the CGI scripts to turn CGI arguments into a hashref and call my new processing stuff. Note that so far, no actual Dancer code has been involved. This was intentional; since my Dancer expertise was still a bit thin, I wanted to have as few app-caused problems as possible, when I started Dancing.&lt;/p&gt;
&lt;p&gt;But now we should stop for a moment and learn just enough about Dancer to be less dangerous.&lt;/p&gt;
&lt;p&gt;Dancer (details at the first link in this article) is a web application framework: in essence, it’s a way to convert URLs into data. You feed in a URL, you get back a web page, a structure, maybe a side effect or three. In order to connect your application to a browser, you need a series of &lt;em&gt;routes&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::Routes&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Dancer&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/index.html&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;hello, world&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dancer sets up some easy-to-grasp syntax that lets you associate a clump of Perl code (an anonymous sub, in the example above) with a URL and a method. Here, a GET of “/index.html” runs the code, and sends the output back to the browser.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;post &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/myapp/do_this.html&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    do_this(&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;param&lt;/span&gt;-&amp;gt;{foo});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;q{It&amp;#39;s done.}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Likewise, we can specify more complex URLs (such as “/myapp/do_this.html?foo=bar”), with POST methods, and access the CGI parameters via the param() function. It just returns a hashref, which we can address as shown.&lt;/p&gt;
&lt;p&gt;Dancer provides quite a bit of support infrastructure: config files, database connections, plug-ins for templating HTML or other output, etc. Since this article is a Gentle Introduction, I refer you to the link cited above if you want to delve deeper.&lt;/p&gt;
&lt;p&gt;Now it was pretty simple to make gradual progress: I’d eliminate one CGI script at a time, replacing it with a Dancer route (stored separately from my main processing module, so that the processing could continue to be ignorant of Dancer). Most of the routes were very simple, since the paths they had to recognize were simple and straightforward, with simple CGI parameter lists. E.g.,&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/notes.html&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$context&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::&lt;/span&gt;get_notes({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dbh    =&amp;gt; database(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        order  =&amp;gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;params&lt;/span&gt;-&amp;gt;{order},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        raw    =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    template &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;notes&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$context&lt;/span&gt;, { layout =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;plain&amp;#39;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This example is one of the routes that produces HTML. The “template” built-in is just a layer wrapped around your preferred templating system (such as Template::Toolkit); it looks for a template file called “notes”, using a set of values specified by “$context”, and wraps the result in a “layout” file called “plain”.&lt;/p&gt;
&lt;p&gt;(At the risk of grossly oversimplifying: your “template” can be thought of as all of your output HTML document within the &lt;body&gt; tag, while the “layout” is everything else, with a spot in the middle for your template’s output.)&lt;/p&gt;
&lt;p&gt;By contrast, one simple route that is designed to return JSON to the JavaScript side:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/orders.html&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$orders&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyApp::&lt;/span&gt;get_orders({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dbh    =&amp;gt; database(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        date   =&amp;gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;params&lt;/span&gt;-&amp;gt;{date},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; to_json(&lt;span style=&#34;color:#369&#34;&gt;$orders&lt;/span&gt; || [], { pretty =&amp;gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;params&lt;/span&gt;-&amp;gt;{pretty} &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;//&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We had to make some adjustments to our Apache configuration to make this all work.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RewriteRule    ^/D/myapp/(.*) http://$SOME_ADDR:5001/$1 [P]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see here, we decided to set up the Dancer app as a service on a particular port, and we settled on a particular prefix for our webservice requests to distinguish them from other traffic. All the requests in the JavaScript were adjusted to this new style.&lt;/p&gt;
&lt;p&gt;Our main Dancer application has the usual one-liner construction*:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dance;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;*Okay, totally not true. For this application, there was a ton of file-parsing and environment-loading to do first, but it was all just a big work-around for some very specific things needed in the app, and not really anything to do with Dancer per se.&lt;/p&gt;
&lt;p&gt;Now, we added one more layer to this: &lt;a href=&#34;http://search.cpan.org/~miyagawa/Starman-0.4008/script/starman&#34;&gt;Starman&lt;/a&gt;. This provided us with a way to simply wrap our Dancer application with the necessary extra bits to turn it into a “service”. That way it starts and stops with a command line interface, logs to a particular path, doesn’t just quit if a user session is ended, etc.&lt;/p&gt;
&lt;p&gt;I don’t have enough background to describe it more than that; hopefully, we’ll have a follow-on post here about Starman from one of my colleagues with more “chops”, soon.  One thing we learned at the cost of some sanity was: * Don’t put an “exit” statement in your Dancer script if you plan to use Starman*. We never learned why this messed it up, but I assume it’s got something to do with Starman absorbing your code into itself and turning it into a Perl subroutine.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>eCommerce Innovation Conference 2013</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/09/ecommerce-innovation-conference-2013/"/>
      <id>https://www.endpointdev.com/blog/2013/09/ecommerce-innovation-conference-2013/</id>
      <published>2013-09-20T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;The &lt;a href=&#34;http://www.ecommerce-innovation.com/&#34;&gt;eCommerce Innovation Conference 2013&lt;/a&gt; is a new conference being held in Hancock, New York, between October 8th and 11th. The conference aims to discuss everything ecommerce with a focus on &lt;a href=&#34;http://www.perl.org/&#34;&gt;Perl&lt;/a&gt;-based solutions including &lt;a href=&#34;http://perldancer.org/&#34;&gt;Dancer&lt;/a&gt; and &lt;a href=&#34;http://www.icdevgroup.org/&#34;&gt;Interchange&lt;/a&gt;. It isn’t geared directly to any one specific type of person unlike most conferences. The current speakers list include in-house ecommerce software developers, consultants, sales managers, project managers, and marketing experts. The talk topics range from customer relationship management to template engines for Perl.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;/team/mark-johnson/&#34;&gt;Mark Johnson&lt;/a&gt; and I are both going to be speaking at the conference. Also there will be Mike Heins, creator of Interchange, and Stefan Hornburg, longtime Interchange development group “team captain”.&lt;/p&gt;
&lt;p&gt;Mark is going to be discussing full page caching in Interchange 5. This is becoming a more frequent request from our larger customers. They want to be able to do full page caching to allow the web browser and a caching proxy server alone to handle most requests leaving Interchange and the database open to handle more shopping-based requests like add to cart or checkout. This is a commonly-used architecture in many application servers, and my colleague David Christensen has several new features already in use by customers to make full-page caching easier, which are expected to go into Interchange 5.8.1 soon.&lt;/p&gt;
&lt;p&gt;I will be doing a talk on &lt;a href=&#34;http://www.icdevgroup.org/slides/eic2013/multi-site-setup/talk.html#&#34;&gt;multi-site setup in Interchange 5&lt;/a&gt;. This is a request we have received frequently over the years. Companies may either already have some kind of wholesale website or just want to have multiple websites use the same database and programming but allow for different website designs. They normally need to control what website a product will show up on and possibly adjust the price accordingly. I’ll discuss the different methods we have used to accomplish this at End Point.&lt;/p&gt;
&lt;p&gt;I see on the schedule that Sam Batschelet will be &lt;a href=&#34;http://www.icdevgroup.org/slides/eic2013/Camps.pdf&#34;&gt;speaking about the camps system&lt;/a&gt; and some new capabilities he’s added for &lt;a href=&#34;http://perlbrew.pl/&#34;&gt;perlbrew&lt;/a&gt; and &lt;a href=&#34;https://github.com/miyagawa/carton&#34;&gt;Carton&lt;/a&gt;, among other things. We are also using camps some places with perlbrew and &lt;a href=&#34;https://github.com/tokuhirom/plenv&#34;&gt;plenv&lt;/a&gt;, so it will be interesting to compare notes. I hope we’ll see some discussion and/or contribution to the &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;open source DevCamps&lt;/a&gt; project soon!&lt;/p&gt;
&lt;p&gt;It promises to be a very nice conference with lots of diverse information!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Challenges in testing Dancer 2.0 apps</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/07/challenges-in-testing-dancer-20-apps/"/>
      <id>https://www.endpointdev.com/blog/2013/07/challenges-in-testing-dancer-20-apps/</id>
      <published>2013-07-09T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;I’ve been dabbling in Dancer, and I managed to put together a moderately complex re-hosting of a web application with Dancer 1.0, including a preliminary package of unit tests via Test::More.&lt;/p&gt;
&lt;p&gt;Spoiler alert: I don’t yet have a solution, but I thought maybe this blog post would organize my thoughts to where someone else might peek in and spot my problem.&lt;/p&gt;
&lt;p&gt;A bit of introduction follows for those who may not have been down this path before.&lt;/p&gt;
&lt;p&gt;Testing a web application can take one of two general approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Test the underlying code by calling it directly, one program to another, with no web server involved. This is pretty straightforward, although you may have to rig up some replacements for the environment (such as if your code expects CGI parameters, or reacts to things in the web server environment such as cookies, remote IP address, etc.). In any case, you have to recognize that you are now testing the code logic, not the actual interaction of your code as a subsystem in the web server.&lt;/li&gt;
&lt;li&gt;Test the web application in its “native environment”, by issuing requests to its associated web server and examining the responses (as web pages, JSON, what-have-you). This is much preferred, as it will catch all sorts of subtle bugs, if you haven’t exactly reproduced the environment (for instance, “correctly” spelling HTTP_REFERRER in your rigged-up environment, whereas the misspelled HTTP_REFERER is actually in use).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The module &lt;a href=&#34;https://metacpan.org/pod/Dancer2::Test&#34;&gt;Dancer2::Test&lt;/a&gt; provides a small set of routines for supporting this second approach. For instance, you can verify that your routes are set up correctly via “route_exists”:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;route_exists [ GET =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/index.html&amp;#39;&lt;/span&gt; ], &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;We can get the home page&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This behaves like the various test-helper routines in &lt;a href=&#34;http://search.cpan.org/~exodist/Test-Simple-1.302136/lib/Test/More.pm&#34;&gt;Test::More&lt;/a&gt;. If the test succeeds (in this case, a route is defined that matches the path), great; if not, an error message is reported using the string parameter.&lt;/p&gt;
&lt;p&gt;You can also verify that the correct page has been delivered without errors:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$response&lt;/span&gt; = dancer_response GET =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/something&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;is &lt;span style=&#34;color:#369&#34;&gt;$response&lt;/span&gt;-&amp;gt;{status}, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/something returns OK&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;like &lt;span style=&#34;color:#369&#34;&gt;$response&lt;/span&gt;-&amp;gt;{content}, &lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;qr{Something from the /something page}&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;dancer_response is the preferred way to go about this, because it captures status, headers, and content in one operation, saving you time but also avoiding the potential for disturbing the state of your application by subsequent requests.&lt;/p&gt;
&lt;p&gt;Now, this article’s title starts with “Challenge”, so I should let the other shoe drop. The Dancer2::Test setup doesn’t seem to have a way to preserve “state” on the server between requests. So if your application supports, for instance, a “login” page and a “modify my account” page, you don’t really have a way to test the latter page, as you can’t remain logged in.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Custom helper subs in Dancer templates</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/03/custom-helper-subs-in-dancer-templates/"/>
      <id>https://www.endpointdev.com/blog/2013/03/custom-helper-subs-in-dancer-templates/</id>
      <published>2013-03-30T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;I recently was writing some code using the &lt;a href=&#34;http://perldancer.org/&#34;&gt;Dancer&lt;/a&gt; Perl web framework, and had a set of HTML links in the template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;a&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;Home&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;a&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/contact&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;Contact&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[etc.]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since it’s possible this app could be relocated to a different path, say, /something/deeper instead of merely /, I wanted to use Dancer’s handy &lt;a href=&#34;https://metacpan.org/module/Dancer#uri_for&#34;&gt;uri_for&lt;/a&gt;() routine to get the full URL, which would include any path relocation. (This concept will be familiar to &lt;a href=&#34;http://www.icdevgroup.org/&#34;&gt;Interchange 5&lt;/a&gt; users from its [area] and [page] tags.)&lt;/p&gt;
&lt;p&gt;The uri_for function isn’t available in templates. The easiest way to cope would be to just use it in my route sub where it works fine, and store the results in the template tokens as strings. But then for any new URL needed I would have to update the route sub and the template, and this feels like a quintessential template concern.&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&#34;http://quispiam.com/adding-custom-helper-methods-to-dancer-templates/&#34;&gt;this blog post&lt;/a&gt; explaining how to add custom functions to be used in templates, and it worked great. Now my template can look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;a&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;% uri_for(&amp;#39;/&amp;#39;) %&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;Home&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;a&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;% uri_for(&amp;#39;contact&amp;#39;) %&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;Contact&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[etc.]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the URLs are output fully qualified:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http://localhost:3000/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http://localhost:3000/contact&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which is not always what I’d want, but in this case is.&lt;/p&gt;
&lt;p&gt;The only final concern is that I am using Dancer version 1.3111 and I got this warning upon using the before_template setup mentioned in the blog:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Dancer::before_template has been deprecated since version 1.3080. use hooks!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;But use hook &amp;#39;before_template&amp;#39; =&amp;gt; sub {} now instead.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So I updated my code, and the final result looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hook &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;before_template&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sub&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$tokens&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;$tokens&lt;/span&gt;-&amp;gt;{uri_for} = \&amp;amp;uri_for;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that made both Dancer and me happy.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
