<?xml version="1.0"?>
<rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007" xmlns:atom="http://www.w3.org/2005/Atom">
   <channel>
      <title>Tech Advent Calendars</title>
      <description>Combination of popular tech advent calendars</description>
      <link>http://pipes.yahoo.com/pipes/pipe.info?_id=c9a42b2f23c108a801e1afa9ce7df012</link>
      <atom:link rel="next" href="http://pipes.yahoo.com/pipes/pipe.run?_id=c9a42b2f23c108a801e1afa9ce7df012&amp;_render=rss&amp;page=2"/>
      <pubDate>Thu, 01 Oct 2015 21:00:15 +0000</pubDate>
      <generator>http://pipes.yahoo.com/pipes/</generator>
      <item>
         <title>[perl] So here it is Merry Christmas</title>
         <link>http://perladvent.org/2014/2014-12-25.html</link>
         <description>&lt;div class='pod'&gt;&lt;p&gt;Another year of Perl Advent had drawn to a close, and what a year it&amp;#39;s been. I hope you&amp;#39;ve enjoyed reading all the articles as much as I have.&lt;/p&gt;

&lt;h3 id=&quot;Everybodys-having-fun&quot;&gt;Everybody&amp;#39;s having fun&lt;/h3&gt;

&lt;p&gt;Of course, just because Advent is over for another year, doesn&amp;#39;t mean the gift of Perl modules has to end. As I write this there are one hundred and forty one thousand seven hundred and forty nine modules on the CPAN and each year we only get to publish twenty four advent articles. So where can you read about the rest of these modules and other exciting things happening in Perl?&lt;/p&gt;



&lt;ul&gt;
  &lt;li&gt;You can search for Perl modules at &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/&quot;&gt;metacpan&lt;/a&gt;
  where you can also see a list of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/recent&quot;&gt;recently
  published modules&lt;/li&gt;&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cpanratings.perl.org/&quot;&gt;CPAN Ratings&lt;/a&gt; offers a ratings
  and reviews of Perl modules.  It's like a democatic advent calendar each day
  of the year!&lt;/li&gt;
  &lt;li&gt;The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://perlweekly.com/&quot;&gt;Perl Weekly&lt;/a&gt; provides one small
  succinct email a week with a summary of the interesting things happing in Perl
  that week, including new modules, interesting articles and upcoming events.&lt;/li&gt;
  &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blogs.perl.org/&quot;&gt;blogs.perl.org&lt;/a&gt; hosts a vast number of
  Perl blogs if you're looking for more articles to read throughout the year.  The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://ironman.enlightenedperl.org/&quot;&gt;
  Perl Ironman Challenge&lt;/a&gt; links to a lot more blogs as part of the &lt;em&gt;updating
  your Perl blog weekly&lt;/em&gt; challenge&lt;/li&gt;
  &lt;li&gt;You're reading the original programming article for advent advent calendar,
  but if you like the format there's a whole collection of them available dedicated
  to other aspects of Perl (e.g. &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.catalystframework.org/calendar/2014&quot;&gt;Catalyst&lt;/a&gt;,
  &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://advent.perldancer.org/2014&quot;&gt;Dancer&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://perl6advent.wordpress.com/2014/&quot;&gt;Perl 6&lt;/a&gt;,
  &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://advent.perl.kr/2014/&quot;&gt;Seoul.pm&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://shadow.cat/blog/matt-s-trout/&quot;&gt;MSTPAN&lt;/a&gt;, and
  &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blogs.perl.org/users/perlancar/2014/12/perlancars-2014-advent-calendar.html&quot;&gt;perlancer&lt;/a&gt;.)  Other
  languages have also adopted the format and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.lenjaffe.com/AdventPlanet/2014/&quot;&gt;Advent Planet&lt;/a&gt;
  has a meta calendar that links to each entry for that day for over twenty
  calendars&lt;/li&gt;
  &lt;li&gt;Of course, if you want more Perl Advent articles, there's always the
  previous &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://perladvent.org/archives.html&quot;&gt;fourteen years of advent
  calendar&lt;/a&gt; to go through.  Happy reading!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Perl Advent Calendar wouldn&amp;#39;t be possible without the hard work of all the article authors. This year we owe thanks to Alex Balhatchet, Augustina Ragwitz, Dave Cross, Graham Ollis, John SJ Anderson, Legolas Greenleaf, Marcus Ramberg, Mark Allen, Mark Fowler, Neil Bowers, Nova Patch, Olaf Alders, Paul &amp;quot;LeoNerd&amp;quot; Evans and Ricardo Signes. These people not only devoted untold time writing and formatting their articles, but put up with me repeatedly hassling them with my self imposed deadlines and bugging them with copy corrections. Thank you for putting up with me.&lt;/p&gt;

&lt;p&gt;Thanks also to everyone who submitted corrections, helped organize, setup hosting, debugged software issues, and otherwise did the unglamorous things that made the advent calendar happen.&lt;/p&gt;

&lt;h3 id=&quot;Look-to-the-future-now&quot;&gt;Look to the future now&lt;/h3&gt;

&lt;p&gt;As a Perl programmer reading the calendar chances are you have an article in you for publishing next year even if you don&amp;#39;t know what it is yet. I encourage you to subscribe to the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://mail.pm.org/mailman/listinfo/perladvent&quot;&gt;mailing list&lt;/a&gt; where we organize all of this and simply drop us an email saying you&amp;#39;d be interested in writing (you&amp;#39;ll get a follow up email from me in about eight months when we start working out scheduling for 2015.)&lt;/p&gt;

&lt;h3 id=&quot;Its-only-just-begun&quot;&gt;It&amp;#39;s only just begun&lt;/h3&gt;

&lt;p&gt;Perl does a lot for you. It keeps you entertained, it makes your life easier, and chances are it keeps you employed. In this season of giving you might consider making a small donation to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://donate.perlfoundation.org/donate.html&quot;&gt;The Perl Foundation&lt;/a&gt; who do important work, including sponsoring developers to work full time on improving the core of Perl.&lt;/p&gt;

&lt;h3 id=&quot;Its-Christmas&quot;&gt;It&amp;#39;s Christmas!&lt;/h3&gt;

&lt;p&gt;Merry Christmas, one and all.&lt;/p&gt;

&lt;/div&gt;&lt;/a&gt;</description>
         <author>Mark Fowler</author>
         <guid isPermaLink="false">http://perladvent.org/2014/2014-12-25.html</guid>
         <pubDate>Thu, 25 Dec 2014 05:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[java] Merry Christmas everyone!</title>
         <link>http://feedproxy.google.com/~r/JavaAdventCalendar/~3/YHT6vuqbpz8/merry-christmas-everyone.html</link>
         <description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align:left;&quot;&gt;This is the first year of the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.javaadvent.com&quot;&gt;Java Advent Project&lt;/a&gt; and I am really grateful to all the people that got involved, published articles, twitted, shared, +1ed, shared etc. etc. &lt;br/&gt;It was an unbelievable journey and all the glory needs to go to the people that took some time from their loved ones to give us their wisdom. As they say, the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.javaadvent.com/2014/12&quot;&gt;Class of 2014&lt;/a&gt; of Java Advent is comprised of (in the order of publishing date): &lt;ul&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://hype-free.blogspot.com/&quot;&gt;Attila-Mihály Balázs&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.transylvania-jug.org/&quot;&gt;Transylvania JUG&lt;/a&gt; member&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/profile/view?id=82429506&quot;&gt;Florin Bunau&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.petrikainulainen.net/&quot;&gt;Petri Kainulainen&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/shelajev&quot;&gt;Oleg Shelajev&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://zeroturnaround.com&quot;&gt;ZeroTurnaround&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;The perfect &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://plumbr.eu/&quot;&gt;plumbr&lt;/a&gt; for your web application, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/iNikem&quot;&gt;Nikita Salnikov-Tarnovski&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;If you want to hear out your developers, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://trishagee.github.io/&quot;&gt;Trisha Gee&lt;/a&gt;, can help you do it properly&lt;/li&gt;   &lt;li&gt;If you like to measure the performance in nanoseconds &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://stackoverflow.com/users/57695/peter-lawrey&quot;&gt;Peter Lawrey&lt;/a&gt; (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://stackoverflow.com/users/57695/peter-lawrey&quot;&gt;stackoverflow&lt;/a&gt;) and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://openhft.net/&quot;&gt;OpenHFT&lt;/a&gt;can help you with it!&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blog.eisele.net/&quot;&gt;Markus Eisele&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blog.eisele.net/&quot;&gt;Eisele.net&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=2481158163384033132&quot;&gt;Rene Jansen&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.linkedin.com/in/mitemitreski&quot;&gt;Mite Mitreski&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blog.mitemitreski.com/&quot;&gt;mitemitreski.com&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blog.schauderhaft.de/&quot;&gt;Jens Schauder&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jooq.org/&quot;&gt;jOOQ&lt;/a&gt;s papa - Lukas Eder(&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://ch.linkedin.com/in/lukaseder&quot;&gt;linkedin&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/lukaseder&quot;&gt;twitter&lt;/a&gt;)&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://plus.google.com/110574453398024123194&quot;&gt;Mani Sarkar&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/pub/marcin-grzejszczak/19/651/155&quot;&gt;Marcin Grzejszczak&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://toomuchcoding.blogspot.ro/&quot;&gt;Too much coding&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=2481158163384033132&quot;&gt;Rudiger Moller&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uk.linkedin.com/in/martijnverburg&quot;&gt;Martijn Verburg&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jclarity.com/&quot;&gt;jClarity&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/profile/view?id=12080828&quot;&gt;Alexander Turner&lt;/a&gt; from &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://nerds-central.blogspot.com/&quot;&gt;Nerds Central&lt;/a&gt;&lt;/li&gt;     &lt;li&gt;And yours truly &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/profile/view?id=21470605&quot;&gt;Olimpiu POP&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;   &lt;br/&gt;Thank you girls and guys for making it happen yet once more. And sorry for stressing and pushing you out. Also, last but not least thanks to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.voxxed.com/&quot;&gt;Voxxed&lt;/a&gt; editors &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/profile/view?id=69144451&amp;authType=NAME_SEARCH&amp;authToken=T1GE&amp;locale=en_US&amp;srchid=214706051419364268205&amp;srchindex=1&amp;srchtotal=17&amp;trk=vsrp_people_res_name&amp;trkInfo=VSRPsearchId%3A214706051419364268205%2CVSRPtargetId%3A69144451%2CVSRPcmpt%3Aprimary&quot;&gt;Lucy Carey&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.linkedin.com/in/mitemitreski&quot;&gt;Mite Mitreski&lt;/a&gt;.  &lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=YHT6vuqbpz8:5ojrSgvMKhY:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=YHT6vuqbpz8:5ojrSgvMKhY:4cEx4HpKnUU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?i=YHT6vuqbpz8:5ojrSgvMKhY:4cEx4HpKnUU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=YHT6vuqbpz8:5ojrSgvMKhY:YwkR-u9nhCs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=YwkR-u9nhCs&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=YHT6vuqbpz8:5ojrSgvMKhY:qj6IDK7rITs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=qj6IDK7rITs&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/JavaAdventCalendar/~4/YHT6vuqbpz8&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Olimpiu Pop</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-2481158163384033132.post-3764847274804782430</guid>
         <pubDate>Thu, 25 Dec 2014 03:04:00 +0000</pubDate>
      </item>
      <item>
         <title>[sysadvent] Day 25 - Windows has Configuration Management?!?</title>
         <link>http://feedproxy.google.com/~r/sysadvent/~3/p7sWRCtdrqs/day-25-windows-has-configuration.html</link>
         <description>&lt;p&gt;Written by: Steven Murawski (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/stevenmurawski&quot;&gt;@stevenmurawski&lt;/a&gt;)&lt;br&gt;
Edited by: William Shipway (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/@shipw&quot;&gt;@shipw&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Windows Server administration has long been the domain of &amp;#8220;admins&amp;#8221; mousing their way through a number of Microsoft and third party management UIs (and I was one of them for a while). There have always been a stalwart few who, by hook or by crook, found a way to automate the almost unautomateable. But this group remained on the fringes of Windows administration. They were labeled as heretics and shunned, until someone needed to do something not easily accomplished by a swipe of the mouse. &lt;/p&gt;

&lt;p&gt;The sea winds have shifted and over the past seven or eight years, Microsoft released PowerShell and began focusing on providing a first class experience to the tool makers and automation-minded. The earlier group of tool makers and automators gained traction and began to develop a larger following, as more Microsoft and third party products added support for PowerShell. That intrepid group of early automators formed the core of the PowerShell community and began welcoming new converts - whether they were true believers or forced into acceptance by the lack of some capability in their comfortable management UIs. Now, most Windows Server administrators have delved into the command line and have begun to succumb to the siren call of automation.&lt;/p&gt;

&lt;p&gt;Just as the PowerShell community&amp;#8217;s evangelism was reaching a fevered pitch, Microsoft added another management tool - Desired State Configuration. The tool-makers and automators were stunned. Cries of &amp;#8220;what about my deployment scripts?&amp;#8221; and &amp;#8220;but, I already built my VM templates!&amp;#8221; echoed through the halls. Early adopters of PowerShell v3 lamented &amp;#8220;isn&amp;#8217;t this what workflows were for?&amp;#8221;. Some had already begun to explore the dark arts of configuration management using tools like Chef and Puppet to bring order to their infrastructure management. With the help of those in the community who blazed a trail in implementing configuration management on Windows, those cries of dismay began to turn into rabid curiosity and even envy. The administrators began to read books like the Phoenix Project and hear stories from companies like Stack Exchange, Etsy, Facebook, and Amazon about this cult of DevOps. They wanted access to this new realm of possibilities, where production deployments don&amp;#8217;t mean a week of late nights in the office and requests for new servers don&amp;#8217;t go to the bottom of the pile to sit for a month to &amp;#8220;percolate&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Read on, dear reader to understand the full story of Desired State Configuration and its place in the new DevOps world where Windows Server administrators find themselves.&lt;/p&gt;

&lt;h3&gt;An Introduction to Desired State Configuration&lt;/h3&gt;

&lt;p&gt;With the release of Windows Server 2012 R2 and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.microsoft.com/en-us/download/details.aspx?id=40855&quot;&gt;Windows Management Framework 4&lt;/a&gt;, Microsoft &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blogs.msdn.com/b/powershell/archive/2013/11/01/configuration-in-a-devops-world-windows-powershell-desired-state-configuration.aspx&quot;&gt;introduced Desired State Configuration&lt;/a&gt; (DSC). DSC consists of three main components: the Local Configuration Manager, a configuration Domain Specific Language (DSL), and resources (with a pattern for building more). DSC is available on Windows Server 2012 R2 and Windows 8.1 64 bit out of the box and can be installed on Windows Server 2012, Windows Server 2008 R2, and Windows 7 64 bit with Windows Management Framework 4. There is an evolving ecosystem around Desired State Configuration, including support for a number of systems management and deployment projects. To me, one of the most important benefits of the introduction of Desired State Configuration is the awakening of the Windows administration community to configuration management concepts.&lt;/p&gt;

&lt;h3&gt;A Platform Play&lt;/h3&gt;

&lt;p&gt;The inclusion of Desired State Configuration may seem like a slap in the face to existing configuration management vendors, but that is not the case. Desired State Configuration is a platform level capability similar to PerfMon or Event Tracing for Windows. DSC is not intended to wholesale replace other configuration management platforms, but to be a base which other platforms can build on in a consistent manner.&lt;/p&gt;

&lt;h4&gt;The Evolution of DSC&lt;/h4&gt;

&lt;p&gt;One of the major knocks against administering Windows servers in the past has been the horrendous story around automation. Command-line tools were either lacking coverage or just plain missing. The shell was in a sorry state. &lt;/p&gt;

&lt;p&gt;Then, shortly before Windows Server 2008 shipped, PowerShell came about. Initially, PowerShell had relatively poor native coverage for managing Windows, but it worked with .NET, WMI, and COM, so it could do just about anything you needed. &lt;/p&gt;

&lt;p&gt;More coverage was introduced with each release of Windows Server. Windows Server 2012 had an explosion of coverage via native PowerShell commands for just about everything on the platform.&lt;/p&gt;

&lt;p&gt;PowerShell appeared to be the management API for configuring Windows servers. The downside of a straight PowerShell interface is that PowerShell commands aren&amp;#8217;t necessarily idempotent. Some like Add-WindowsFeature are, and do the right thing if the command is run repeatedly. Others are not, like New-Website, which will throw errors if the site already exists.&lt;/p&gt;

&lt;p&gt;DSC was introduced to provide a common management API that offers consistent behavior. Under the covers, it is mostly PowerShell that is running, but the patterns the resources follow ensure that only the work that needs to be done is done, and when a resource is in the proper state, that it is left alone.&lt;/p&gt;

&lt;p&gt;Being a platform feature means that there is a consistent, supported mechanism for customers and vendors to manage and evolve the configured state of Windows servers.&lt;/p&gt;

&lt;h4&gt;Standards Based&lt;/h4&gt;

&lt;p&gt;Desired State Configuration was built using standards already supported on the Windows platform - &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.dmtf.org/standards/cim&quot;&gt;CIM&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.dmtf.org/standards/wsman&quot;&gt;WSMAN&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;CIM, Common Information Model, is the DMTF standard that WMI is based upon and provides structure and schema for DSC.&lt;/p&gt;

&lt;p&gt;WSMAN, WS-Management, is a web services protocol and DMTF standard for management traffic. WinRM and PowerShell remoting are built on this transport as well. &lt;/p&gt;

&lt;p&gt;While these might not be the greatest standards in the world, they do provide a consistent manner for interacting with the Desired State Configuration service.&lt;/p&gt;

&lt;h4&gt;An Evolving API&lt;/h4&gt;

&lt;p&gt;Though Windows Management Framework (WMF) was just recently introduced (it has been released for just over a year), WMF 5 development is well under way and includes many enhancements and bug fixes. One major change is to make the DSC engine&amp;#8217;s API more friendly to use by third-party configuration management systems. &lt;/p&gt;

&lt;p&gt;There was also a recent rollup patch for Server 2012 R2 (KB3000850) that contains a number of bugfixes and some tweaks for ensuring compatibility with changes coming in WMF 5.&lt;/p&gt;

&lt;h3&gt;Diving In&lt;/h3&gt;

&lt;p&gt;Now that we&amp;#8217;ve got a bit of history and rationale for existence out of the way, we can dig in to the substance of Desired State Configuration.&lt;/p&gt;

&lt;h4&gt;The Local Configuration Manager&lt;/h4&gt;

&lt;p&gt;The engine that manages the consistency of a Windows server is the Local Configuration Manager (LCM). The LCM is exposed as a WMI (CIM) class (MSFT_DscLocalConfigurationManager) in the Root/Microsoft/Windows/DesiredStateConfiguration namespace.&lt;/p&gt;

&lt;p&gt;The LCM is responsible for periodically checking the state of resources in a configuration document. This agent controls&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether resources are allowed to reboot the node as part of a configuration cycle&lt;/li&gt;
&lt;li&gt;how the agent should treat deviance from the configuration state (apply and never check, apply and report deviance, apply and autocorrect problems)&lt;/li&gt;
&lt;li&gt;how often consistency checks should be run&lt;/li&gt;
&lt;li&gt;and more&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has a plugin/extension point with the concept of Download Managers. Download Managers are used for Pull mode configurations. There are two download managers that ship in the box, one using a simple REST endpoint to retrieve configurations and one using a SMB file share. As it currently stands, these are not open for replacement by third parties (but it could be made so - please weigh in to the PowerShell team about that before WMF 5 is done!). &lt;/p&gt;

&lt;h5&gt;A Quick Note - Push vs. Pull&lt;/h5&gt;

&lt;p&gt;DSC configurations can be imperatively pushed to a node (via the Start-DscConfiguration cmdlet or directly to the WMI API), or if a Download Manager is configured it can pull a configuration and resources from a central repository (currently either SMB file share or REST-based pull server). If a node is in PULL mode, when a new configuration is retrieved, it is parsed to find the various modules required for the configuration to be applied. If any of the requisite modules and versions are not present on the local node, the pull server can supply those.&lt;/p&gt;

&lt;h4&gt;DSC Resources&lt;/h4&gt;

&lt;p&gt;Resources are the second major component of the DSC ecosystem, and are what make things happen in the context of DSC. There are three ways of creating DSC resources: They can be written in PowerShell, as WMI classes, or in Windows Management Framework 5, as PowerShell classes. As PowerShell class-based resources are still an experimental feature and the level of effort to create WMI based resources is pretty high, we&amp;#8217;ll focus on PowerShell-based resources here.&lt;/p&gt;

&lt;p&gt;DSC resources are implemented as PowerShell modules. They are hosted inside another PowerShell module under a DSCResources folder. The host module needs to have a module metadata file and have a module version defined in order for it to host DSC resources. &lt;/p&gt;

&lt;p&gt;The resources themselves are PowerShell modules that expose three functions or cmdlets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get-TargetResource&lt;/li&gt;
&lt;li&gt;Test-TargetResource&lt;/li&gt;
&lt;li&gt;Set-TargetResource&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get-TargetResource returns the currently configured state (or lack thereof) of the resource. The function returns a hashtable that the LCM converts to an object at a later stage. &lt;/p&gt;

&lt;p&gt;Test-TargetResource is used to determine if the resource is in the desired state or not. It returns a boolean.&lt;/p&gt;

&lt;p&gt;Set-TargetResource is responsible for getting the resource into the desired state. Set-TargetResource is only executed after Test-TargetResource. &lt;/p&gt;

&lt;h4&gt;The Configuration DSL&lt;/h4&gt;

&lt;p&gt;Also introduced with Desired State Configuration are some domain specific language extensions on top of PowerShell. Actually, Windows Management Framework 4 added some public extension points in PowerShell for creating new keywords, which is what DSC uses. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stick with me here, as it may get a bit confusing - I&amp;#8217;ll be using &amp;#8220;configuration&amp;#8221; in two contexts. First is the configuration script. This is defined in PowerShell and can be defined in a script file, a module, or an ad hoc entry at the command line. The second use of &amp;#8220;configuration&amp;#8221; is in the context of the configuration document. This is the final serialized representation of the configuration for a particular machine or class of machines. This document is in Managed Object Format (MOF) and is how CIM classes are serialized.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first keyword defined is configuration. The configuration keyword indicates that the subsequent scriptblock will be a configuration document and should be parsed differently. All your standard PowerShell constructs and commands are valid inside of a configuration, as are a few new keywords. There are two static keywords and a series of dynamic keywords in a configuration document.&lt;/p&gt;

&lt;p&gt;The first two static keywords are node and Import-DscResource. I&amp;#8217;ll deal with the latter first, since it seems very oddly named. Import-DscResource looks in name like a cmdlet or function, but is a keyword that is valid only in a configuration document and only outside of the context of a node. Import-DscResource identifies custom and third-party modules to make available in a configuration document. By default, only DSC resources in modules located at $pshome/modules (usually c:&amp;#92;windows&amp;#92;system32&amp;#92;windowspowershell&amp;#92;v1.0&amp;#92;modules) can be used without using Import-DscResource and specifying which modules to make resources available from. The second static keyword is the node keyword. Node is used to identify the machine or class of machines that the configuration is targeted at. Resources are generally assigned inside node declarations.&lt;/p&gt;

&lt;p&gt;The configuration also includes a number of potential dynamic keywords which represent the DSC resources available for the configuration.&lt;/p&gt;

&lt;p&gt;An example configuration script looks something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;configuration SysAdvent
{
    Import-DscResource -ModuleName cWebAdministration

    node $AllNodes.where({$_.role -like 'web'}).NodeName
    {
      windowsfeature IIS
      {
        Name = 'web-server'
      }

      cWebsite FourthCoffee
      {
        Name = 'FourthCoffee'
        State = 'Started'
        ApplicationPool = 'FourthCoffeeAppPool'
        PhysicalPath = 'c:&amp;#92;websites&amp;#92;fourthcoffee'
        DependsOn = '[windowsfeature]IIS'
      }

    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above configuration script, when run, creates a command in the current PowerShell session called SysAdvent. Running that command will generate a configuration document for every server in a collection that has the role of a web server. The configuration command has a common parameter of ConfigurationData which is where AllNodes comes from (more on that in a bit). The result of this command will be a MOF document describing the desired configuration for every node identified as a web server.&lt;/p&gt;

&lt;p&gt;MOF documents created by the command are written in a folder (of the same name as the configuration) created in the current working directory. Files are named for the node they represent (e.g. server1.mof). You can specify a custom output location. Here is our newly created MOF document:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/*
@TargetNode='localhost'
@GeneratedBy=Administrator
@GenerationDate=12/22/2014 04:12:56
@GenerationHost=ARMORY
*/

instance of MSFT_RoleResource as $MSFT_RoleResource1ref
{
SourceInfo = &quot;::7::7::windowsfeature&quot;;
 ModuleName = &quot;PSDesiredStateConfiguration&quot;;
 ModuleVersion = &quot;1.0&quot;;
 ResourceID = &quot;[WindowsFeature]IIS&quot;;
 Name = &quot;web-server&quot;;

 ConfigurationName = &quot;SysAdvent&quot;;

};
instance of PSHOrg_cWebsite as $PSHOrg_cWebsite1ref
{
ResourceID = &quot;[cWebsite]FourthCoffee&quot;;
 PhysicalPath = &quot;c:&amp;#92;&amp;#92;websites&amp;#92;&amp;#92;fourthcoffee&quot;;
 State = &quot;Started&quot;;
 ApplicationPool = &quot;FourthCoffeeAppPool&quot;;
 SourceInfo = &quot;::12::7::cWebsite&quot;;
 Name = &quot;FourthCoffee&quot;;
 ModuleName = &quot;cWebAdministration&quot;;
 ModuleVersion = &quot;1.1.1&quot;;

DependsOn = {

    &quot;[windowsfeature]IIS&quot;};

 ConfigurationName = &quot;SysAdvent&quot;;

};
instance of OMI_ConfigurationDocument
{
 Version=&quot;1.0.0&quot;;
 Author=&quot;Administrator&quot;;
 GenerationDate=&quot;12/22/2014 04:12:56&quot;;
 GenerationHost=&quot;ARMORY&quot;;
 Name=&quot;SysAdvent&quot;;
};&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Other Tidbits&lt;/h4&gt;

&lt;p&gt;There are a few other things one should know in preparation for digging into DSC.&lt;/p&gt;

&lt;h5&gt;ConfigurationData and AllNodes&lt;/h5&gt;

&lt;p&gt;Configurations have support for a convention-based approach to separating environmental data from the structural configuration. The configuration script represents the structure or model for the machine, and the environmental data (via ConfigurationData) fleshes out the details.&lt;/p&gt;

&lt;p&gt;ConfigurationData is represented by a hashtable with at least one key - AllNodes. AllNodes is an array of hashtables representing the nodes that should have configurations generated and becomes an automatic variable that can be referenced in the configuration (like in the example above). The value provided in $ConfigurationData is also referenced and you can create custom keys and reference those in your configuration document. The PowerShell team reserves the right to use any key in the ConfigurationData hashtable that is prefixed with PS.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ConfigurationData = @{
  AllNodes = (
      @{NodeName = '*', InterestingData = 'Every node can reference me.'}
      @{NodeName = 'Server1'; Role = 'Web'},
      @{NodeName = 'Server2'; Role = 'SQL'},
  )
}

Sysadvent -ConfigurationData $ConfigurationData
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;DependsOn&lt;/h5&gt;

&lt;p&gt;Resources in DSC are not ordered by default and there is no guarantee of ordering. The current WMF 4 implementation and the previews of WMF 5 all seem to serially process resources, but there is NO guarantee that will stay that way. If you need things to happen in a certain order, you need to use DependsOn to tell a resource what needs to happen first before that one can execute.&lt;/p&gt;

&lt;h5&gt;Node Names&lt;/h5&gt;

&lt;p&gt;In PUSH mode, the node name is either the server name, FQDN, or IP address (any valid way you can address that node via PowerShell remoting).&lt;/p&gt;

&lt;p&gt;In PULL mode, the node name is not the server name. Servers are assigned a GUID and they use that to identify which configuration to retrieve from a pull server. Where this GUID comes from is up to you - you can generate them on the fly, pull one from AD, or use one from another system. Since the GUID is the identifier, you can use one GUID to represent an individual server or a class of servers.&lt;/p&gt;

&lt;h5&gt;WMF 5 - In Production&lt;/h5&gt;

&lt;p&gt;If you are running Windows Server 2012 R2, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blogs.msdn.com/b/powershell/archive/2014/12/10/wmf-5-0-preview-defining-quot-experimental-designs-quot-and-quot-stable-designs-quot.aspx&quot;&gt;you can stay on the bleeding edge AND get production support&lt;/a&gt;. The PowerShell team recently announced that if you are using WMF 5, you can get production support for what they call &amp;#8220;stable&amp;#8221; designs - those features that either existed in previous versions of the Management Framework or have reached a level that the team is ready to provide support. Other features, which are more in flux, are labeled experimental and don&amp;#8217;t carry the same support level. With this change, you can safely deploy WMF 5 and begin to test new features and get the bug fixes faster than waiting for the full release. WMF previews are released roughly quarterly.&lt;/p&gt;

&lt;p&gt;With WMF 5, you can dig into new and advanced features like Debug mode, partial configurations, and separate pull servers for different resource types.&lt;/p&gt;

&lt;h3&gt;Building an Ecosystem&lt;/h3&gt;

&lt;p&gt;No tooling is complete without a community around it and Desired State Configuration is no different.&lt;/p&gt;

&lt;h4&gt;PowerShellGet and OneGet&lt;/h4&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/oneget/oneget&quot;&gt;OneGet&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://blogs.msdn.com/b/mvpawardprogram/archive/2014/10/06/package-management-for-powershell-modules-with-powershellget.aspx&quot;&gt;PowerShellGet&lt;/a&gt; are coming onto the scene with WMF 5 (although after they release they should be available somewhat downlevel too). OneGet is a package manager manager and provides an abstraction layer on top of things like nuget, chocolatey, and PowerShellGet, and eventually tools like npm, RubyGems, and more. PowerShellGet provides a way to publish and consume external modules, including those that contain DSC resources. &lt;/p&gt;

&lt;p&gt;Finding new resources becomes as easy as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Find-Module -Includes DscResource
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Third Parties&lt;/h4&gt;

&lt;h5&gt;Chef&lt;/h5&gt;

&lt;p&gt;Back in July 2014, Chef made a preview of our DSC integration available (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=mXaAIawzNic&quot;&gt;video&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://supermarket.chef.io/cookbooks/dsc&quot;&gt;cookbook&lt;/a&gt;) and in September &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.chef.io/blog/2014/09/08/chef-11-16-gets-into-powershell-dsc/&quot;&gt;shipped our first production-supported integration&lt;/a&gt; (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://docs.chef.io/resource_dsc_script.html&quot;&gt;the dsc_script resource&lt;/a&gt;) and have more coming. DSC offers Chef increased coverage on the Windows platform.&lt;/p&gt;

&lt;h5&gt;ScriptRock&lt;/h5&gt;

&lt;p&gt;The guys at ScriptRock (full disclosure - they are friends of mine) have done a pretty interesting thing by &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.scriptrock.com/blog/powershell-dsc-with-guardrail&quot;&gt;taking a configuration visualization and testing tool and offering an export of the configuration as a DSC script&lt;/a&gt;. Very cool.&lt;/p&gt;

&lt;h5&gt;Puppet&lt;/h5&gt;

&lt;p&gt;There is a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://forge.puppetlabs.com/msutter/dsc&quot;&gt;Puppet module on the Forge&lt;/a&gt; showing some DSC integration. I&amp;#8217;m not too familiar with the state of that project, but it&amp;#8217;s great to see it!&lt;/p&gt;

&lt;h5&gt;Aditi&lt;/h5&gt;

&lt;p&gt;Brewmaster from Aditi is a deployment tool and can leverage DSC to get a server in shape to host a particular application, allowing you to distribute a DSC configuration with an application.&lt;/p&gt;

&lt;h4&gt;PowerShell.Org&lt;/h4&gt;

&lt;p&gt;PowerShell.Org hosts a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://powershell.org/wp/dsc-hub/&quot;&gt;DSC Hub&lt;/a&gt; containing forums, blog posts, podcasts, videos and a free e-book on DSC.&lt;/p&gt;

&lt;h3&gt;So, What Are You Waiting For?&lt;/h3&gt;

&lt;p&gt;Start digging in! There&amp;#8217;s a ton of content out there. Shout at me on Twitter (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/stevenmurawski&quot;&gt;@stevenmurawski&lt;/a&gt;) or via &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://stevenmurawski.com&quot;&gt;my blog&lt;/a&gt; if you have any questions.&lt;/p&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/sysadvent/~4/p7sWRCtdrqs&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Christopher Webber</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-3615332969083650973.post-2675725091070196977</guid>
         <pubDate>Thu, 25 Dec 2014 00:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[24ways] Cohesive UX</title>
         <link>http://feedproxy.google.com/~r/24ways/~3/5DxEWYCsfuY/</link>
         <description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cameronmoll.com/&quot;&gt;Cameron Moll&lt;/a&gt; brings the tenth 24 ways to a close with a look at the increasing need for common experiences across devices. Despite our differences, there are more things we share than divide us. Merry Christmas!&lt;/p&gt;
				
				
				
				
				
				&lt;p&gt;&lt;a rel=&quot;nofollow&quot; class=&quot;promo&quot; target=&quot;_blank&quot; href=&quot;http://beanstalkapp.com/?utm_source=24ways&amp;amp;utm_medium=sponsored-post-12-4&amp;amp;utm_campaign=24ways-2014&quot;&gt;
	&lt;strong&gt;Brought to you by Beanstalk.&lt;/strong&gt; Celebrate shipping code again! With Beanstalk, your entire team can ship code as simple as git push.
&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=5DxEWYCsfuY:zLlj08872Ws:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=5DxEWYCsfuY:zLlj08872Ws:7Q72WNTAKBA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=7Q72WNTAKBA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=5DxEWYCsfuY:zLlj08872Ws:V_sGLiPBpWU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?i=5DxEWYCsfuY:zLlj08872Ws:V_sGLiPBpWU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=5DxEWYCsfuY:zLlj08872Ws:dnMXMwOfBR0&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=dnMXMwOfBR0&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/24ways/~4/5DxEWYCsfuY&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>feeds@allinthehead.com (Cameron Moll)</author>
         <guid isPermaLink="false">http://24ways.org/2014/cohesive-ux/</guid>
         <pubDate>Wed, 24 Dec 2014 12:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[perl] Out of Order Perl</title>
         <link>http://perladvent.org/2014/2014-12-24.html</link>
         <description>&lt;div class='pod'&gt;&lt;p&gt;This article will cover asynchronous programming with the AnyEvent library and will show use cases for managing multiple asynchronous requests in a single application. In addition, I hope to introduce good techniques for using metrics to drive technology decisions!&lt;/p&gt;

&lt;h3 id=&quot;Is-an-Asynchronous-Solution-right-for-me&quot;&gt;Is an Asynchronous Solution right for me?&lt;/h3&gt;

&lt;p&gt;New software techniques and practices are always rearing their heads in the industry. While asynchronous functionality is not new to Perl, it is not widely used where it could be, and maybe over-used where it shouldn&amp;#39;t be. When considering whether or not to adopt some new methodology on existing software, it&amp;#39;s important to make sure you have clearly identified what problem you are trying to solve. It&amp;#39;s fine if you want to play around with something new, but remember that every solution has a cost. The cost of asynchronous functionality is that it can be difficult to read and debug (callback soup anyone?) and you have to consider compatibility of your current web framework as well as your current code base.&lt;/p&gt;

&lt;h4 id=&quot;Step-1:-Identify-the-Problem&quot;&gt;Step 1: Identify the Problem&lt;/h4&gt;



&lt;blockquote&gt;“70% of users are unable to download the TPS Report from the website because the
website times out.”&lt;/blockquote&gt;



&lt;blockquote&gt;“Web site latency is reported for 75% of users.”&lt;/blockquote&gt;

&lt;h4 id=&quot;Step-2:-Identify-the-cause-the-clarify-the-problem-with-numbers&quot;&gt;Step 2: Identify the cause the clarify the problem (with numbers!)&lt;/h4&gt;

&lt;p&gt;To identify the cause, you can check logs, collect metrics (a lot of folks use statsd), or attempt to reproduce the problem in a staging environment.&lt;/p&gt;



&lt;blockquote&gt;“The TPS report database query takes 30 seconds to run”&lt;/blockquote&gt;



&lt;blockquote&gt;“Requests to HTTP services are averaging 1 second because each request is made individually and is only made once the previous request is complete.”&lt;/blockquote&gt;

&lt;h4 id=&quot;Step-3:-Propose-a-solution-based-on-data-and-facts&quot;&gt;Step 3: Propose a solution (based on data and facts)&lt;/h4&gt;

&lt;p&gt;Now that you&amp;#39;ve collected data and clarified your problem in terms of metrics, you can say &amp;quot;Asynchronous HTTP requests would reduce overall report loading time to only the amount of time it takes the longest request to return.&amp;quot;&lt;/p&gt;

&lt;p&gt;Implement a Solution based on your results... and use metrics to determine success There is a fully functioning sample application! The sample application from which the code snippets in this article come is located on &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://github.com/missaugustina/perl-out-of-order&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The sample application is a simple Mojolicious::Lite application the generates a &amp;ldquo;TPS&amp;rdquo; report. This report makes calls to 2 external services to collect data and then uses that data to make a complex call to the database. I&amp;#39;m just using simple timing metrics to show the results for each of the reports. You can run it yourself to see the results as it records them in the database. First Improvement: Make it Async!&lt;/p&gt;

&lt;p&gt;As we ascertained from our problem statement exercise just now, kicking off HTTP requests at the same time would drastically improve our report&amp;#39;s performance.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s how you currently use LWP to make HTTP requests:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ua&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;LWP::UserAgent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$req&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;HTTP::Request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# make the request, and wait until we get the results back&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$res&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ua&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$req&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$res&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Here&amp;#39;s how it looks in our sample application:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$req&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;HTTP::Request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$res&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;_user_agent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$req&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$res&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$http_data&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$http_data&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Notice that these requests happen for EACH URL in our list for EACH row in the database results one after the other, waiting for the previous request to return before starting the next. If we have 10 URLs and each one takes 3 milliseconds, our total request takes 10 x 3 milliseconds or 30 milliseconds total. If one of them takes any more time than that, it will hold up processing of the others and makes our request take even longer.&lt;/p&gt;

&lt;p&gt;There are a lot of asynchronous libraries in the CPAN for you to consider. I&amp;#39;m using AnyEvent because we&amp;#39;re going to be talking to RabbitMQ later and AnyEvent::RabbitMQ is one of the better libraries for doing that. When considering what asynchronous library to use, you always need to think about your requirements and to determine if it&amp;#39;s likely you&amp;#39;ll be adding other asynchronous functionality. Swapping one out for another, however, isn&amp;#39;t impossible as they all pretty much follow the same rules (they just call things by different names). What you&amp;#39;ll learn here about how to use AnyEvent will also apply in concept to any other library you might want to use instead.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s what the asynchronous solution looks like in our sample application using AnyEvent::HTTP.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;core&quot;&gt;undef&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Let&amp;#39;s add a few more comments to try and make it a little clearer what&amp;#39;s going on:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;br /&gt;28:&amp;nbsp;&lt;br /&gt;29:&amp;nbsp;&lt;br /&gt;30:&amp;nbsp;&lt;br /&gt;31:&amp;nbsp;&lt;br /&gt;32:&amp;nbsp;&lt;br /&gt;33:&amp;nbsp;&lt;br /&gt;34:&amp;nbsp;&lt;br /&gt;35:&amp;nbsp;&lt;br /&gt;36:&amp;nbsp;&lt;br /&gt;37:&amp;nbsp;&lt;br /&gt;38:&amp;nbsp;&lt;br /&gt;39:&amp;nbsp;&lt;br /&gt;40:&amp;nbsp;&lt;br /&gt;41:&amp;nbsp;&lt;br /&gt;42:&amp;nbsp;&lt;br /&gt;43:&amp;nbsp;&lt;br /&gt;44:&amp;nbsp;&lt;br /&gt;45:&amp;nbsp;&lt;br /&gt;46:&amp;nbsp;&lt;br /&gt;47:&amp;nbsp;&lt;br /&gt;48:&amp;nbsp;&lt;br /&gt;49:&amp;nbsp;&lt;br /&gt;50:&amp;nbsp;&lt;br /&gt;51:&amp;nbsp;&lt;br /&gt;52:&amp;nbsp;&lt;br /&gt;53:&amp;nbsp;&lt;br /&gt;54:&amp;nbsp;&lt;br /&gt;55:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;comment&quot;&gt;# A condition variable.  Basically a mechanism to tell if we're done&lt;br /&gt;# processing all the requests or not.&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# tell the condition variable that it's not &amp;quot;ready&amp;quot; until it sees the &amp;quot;end&amp;quot;&lt;br /&gt;# call at the end of the code signifying we're done setting up all the&lt;br /&gt;# requests.  This is good practice to avoid accidentally completing&lt;br /&gt;# while we're still setting up all the requests.&lt;br /&gt;#&lt;br /&gt;# Also pass the code block that will be executed at this point when the&lt;br /&gt;# condition variable is &amp;quot;ready&amp;quot;.&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# for each of our urls, start a request in parallel&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;  # add another thing to the list of things that must be completed&lt;br /&gt;&amp;nbsp;&amp;nbsp;# before the condition variable is &amp;quot;ready&amp;quot;.  i.e. let the condition variable&lt;br /&gt;&amp;nbsp;&amp;nbsp;# know that we must wait until the HTTP request returns and the callback&lt;br /&gt;&amp;nbsp;&amp;nbsp;# calls a corresponding &amp;quot;end&amp;quot; on the condition variable before we're done.&lt;br /&gt;&lt;/span&gt;  &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;  # schedule a HTTP request to made asynchronously.  Once it's done&lt;br /&gt;&amp;nbsp;&amp;nbsp;# and we've got the content, call the callback.&lt;br /&gt;&lt;/span&gt;  &lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;      # save the content for this request (i.e. what we downloaded) in our&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# result&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;      # clean ourselves up&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;core&quot;&gt;undef&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;      # and let the condition variable know that this scheduled thing&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# is done and once the last one is done it can fire.&lt;br /&gt;&lt;/span&gt;      &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# signify that we're done with stage of setting up all the requests.  The&lt;br /&gt;# condition variable become &amp;quot;ready&amp;quot; until all the requests that called &amp;quot;begin&amp;quot;&lt;br /&gt;# above have also completed and called a corresponding number of &amp;quot;end&amp;quot; calls&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# wait (i.e. block) until the condition variable is ready, i.e. until a&lt;br /&gt;# corresponding number of &amp;quot;end&amp;quot; calls have been called for each &amp;quot;begin&amp;quot; call&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&amp;#39;ll get back to this code, explaining in more depth each section of code bit by bit once we&amp;#39;ve learned a little more about AnyEvent.&lt;/p&gt;

&lt;p&gt;First, let&amp;#39;s look at the advantage of using this significantly more complicated code. With an asynchronous solution, if each request takes 3 milliseconds, then we get our results back in 3 milliseconds. If one of those requests takes 1 second, then we get all of our results back in 1 second. The time it takes to get our results back takes only as long as the longest request!&lt;/p&gt;

&lt;h3 id=&quot;What-does-it-mean-to-be-Asynchronous&quot;&gt;What does it mean to be Asynchronous?&lt;/h3&gt;

&lt;h4 id=&quot;Asynchronous-code-is-event-driven&quot;&gt;Asynchronous code is event-driven&lt;/h4&gt;

&lt;p&gt;An event queue manages code execution. If you&amp;#39;ve ever had to do any work with user interfaces, you should be familiar with the notion of an event-listener. An event in a user interface would be a button click. You would register a function to execute when the the button is pushed. In our example, the function (callback) we&amp;#39;ve registered with the event we&amp;#39;re interested in is pushed to an event queue that fires after all the other code executes. The event loop is a queue of callback functions. When an asynchronous function executes, the callback function is pushed into the event queue.&lt;/p&gt;

&lt;h4 id=&quot;Results-are-returned-in-the-background-while-your-application-does-other-things&quot;&gt;Results are returned in the background while your application does other things&lt;/h4&gt;

&lt;p&gt;The rest of your application proceeds ahead using a placeholder for the result until it reaches a point where it can&amp;#39;t go any further without the actual result (for example writing that result out to a data store).&lt;/p&gt;

&lt;p&gt;The basic formula for Async: &lt;b&gt;Event Loop + Listener + Callbacks&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A listener registers your interest in a particular event. A callback is a function that runs when your request is in a &lt;i&gt;ready&lt;/i&gt; state. No matter what Async library you use, all of them follow these rules.&lt;/p&gt;

&lt;p&gt;Now we&amp;#39;ll talk about more specifically what this looks like in the AnyEvent libraries.&lt;/p&gt;

&lt;h3 id=&quot;AnyEvent-101&quot;&gt;AnyEvent 101&lt;/h3&gt;

&lt;h4 id=&quot;condvar&quot;&gt;&lt;code&gt;condvar&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;AnyEvent is just an abstraction layer on top of event loops. The &lt;code&gt;condvar()&lt;/code&gt; method initializes the condition variable which represents a value that may or may not be available. The condition variable doesn&amp;#39;t have a value until it is &amp;ldquo;ready&amp;rdquo;, meaning the request has completed. You use the &lt;code&gt;condvar()&lt;/code&gt; method to interface with the event loop.&lt;/p&gt;

&lt;h4 id=&quot;send&quot;&gt;&lt;code&gt;send&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;send()&lt;/code&gt; method sets the conditional variable to &lt;i&gt;ready&lt;/i&gt;. This will indicate that one event is complete. In the case of multiple requests, you can bind a callback to &lt;code&gt;send()&lt;/code&gt; so that you can store the values retrieved each time the condvar is in a ready state.&lt;/p&gt;

&lt;h4 id=&quot;recv&quot;&gt;&lt;code&gt;recv&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This returns a value when the &lt;code&gt;condvar&lt;/code&gt; is in a ready state. Note that this is blocking because this is called at the point where your program cannot continue until it has the value it needs. I&amp;#39;ll show why this is important later when we introduce RabbitMQ and have to manage multiple asynchronous requests.&lt;/p&gt;

&lt;h4 id=&quot;begin-and-end&quot;&gt;&lt;code&gt;begin&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;These methods are syntactic sugar for using a counter within an event loop. Begin increments the counter and end decrements it. The event loops runs until the counter is at 0. You can use these methods when you&amp;#39;re managing multiple requests within an event loop and you want to make sure the event loop doesn&amp;#39;t terminate until all of the requests you want have finished.&lt;/p&gt;

&lt;p&gt;If you were to implement this yourself, you could create a loop where you create a &lt;code&gt;condvar&lt;/code&gt; for each individual request. This syntactic sugar lets you declare just one &amp;lt;Ccondvar&amp;gt; and then specify when you want to set its ready state so &lt;code&gt;recv&lt;/code&gt; can return the result.&lt;/p&gt;

&lt;h3 id=&quot;AnyEvent::HTTP-Code-Walkthrough&quot;&gt;AnyEvent::HTTP Code Walkthrough&lt;/h3&gt;

&lt;p&gt;Remember that code sample from earlier? Well now that we have a little better vocabulary, we can walk through it and understand what&amp;#39;s happening in a little more detail, and hopefully understand how we came to write the code like that.&lt;/p&gt;

&lt;p&gt;The first step is to initialize the &lt;code&gt;condvar&lt;/code&gt;. Remember at this point, it has no actual value!&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Next, you need to determine what you want to return at the &lt;i&gt;ready&lt;/i&gt; state and assign it. This is where async programming can get a little tricky (hence the title of this article)! You need to think backwards when you start thinking async. Think from the result and work your way back. Decide at what point your application absolutely needs this data and put your &lt;code&gt;recv&lt;/code&gt; call there.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now all we need to work out what code goes between these two statements. We need to figure out when to call the send event so we can capture our result. We&amp;#39;re going to call it within a callback bound to a begin call. Each time we want to fetch data from a URL, we&amp;#39;ll increment our event loop counter so that we don&amp;#39;t exit out of the event loop before we&amp;#39;ve gotten a response for each of our URL requests. So, this means, in English: Once all the URLs are fetched, set the &lt;code&gt;condvar&lt;/code&gt; to ready and return the result.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;   &lt;span class=&quot;comment&quot;&gt;# &amp;lt;------------- we add this&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Because we&amp;#39;ve declared a begin, we need to declare an end outside of the loop to ensure that send gets called. If our loop has no data (in the while block) we would loop forever without this call to end here. This ensures the send we registered with our begin up above gets called.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;                                   &lt;span class=&quot;comment&quot;&gt;# &amp;lt;------------- we add this&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now that we&amp;#39;ve defined our start and end points, we can focus on the actual logic around retrieving the URLs. We&amp;#39;re going to use the AnyEvent::HTTP library, in particular the &lt;code&gt;http_request&lt;/code&gt; method. Calling &lt;code&gt;http_request&lt;/code&gt; means that you want the request to be made whenever it&amp;#39;s possible (versus a procedural call which would mean stop everything and do it right now). This registers an IO watcher and tells the event loop that we are interested in this IO event.&lt;/p&gt;

&lt;p&gt;When the request finishes, we want to invoke the callback that we&amp;#39;ve bound to the function call.&lt;/p&gt;

&lt;p&gt;This method doesn&amp;#39;t actually do the request, it returns right away and tells the event loop to do the request whenever it can. When this chunk of code runs, the event loop is not running because this chunk of code has control.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;   &lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;                                &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;                    &lt;span class=&quot;readline&quot;&gt;&amp;lt;----&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GET =&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;                              &lt;span class=&quot;readline&quot;&gt;&amp;lt;----    we add&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout =&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds                   &amp;lt;----    all of&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;                                     &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;    &lt;span class=&quot;word&quot;&gt;this&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;           &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;    &lt;span class=&quot;word&quot;&gt;code&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;                                         &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;                                          &lt;span class=&quot;operator&quot;&gt;&amp;lt;----&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We need to unregister our interest in this event once we&amp;#39;re done with it.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;   &lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;    &lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;core&quot;&gt;undef&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;                       &lt;span class=&quot;comment&quot;&gt;# &amp;lt;------------- we add this&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The inner begin and end calls define the individual requests that we want to track in the event loop. For each begin, the AnyEvent event loop will increment a counter. For each end the AnyEvent event loop decrements the counter. Once the counter reaches 0, AnyEvent can set the &lt;code&gt;condvar&lt;/code&gt; to &lt;i&gt;ready&lt;/i&gt;.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;                       &lt;span class=&quot;comment&quot;&gt;# &amp;lt;------------- we add this&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$headers&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;core&quot;&gt;undef&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;                     &lt;span class=&quot;comment&quot;&gt;# &amp;lt;------------- and we add this&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;And that&amp;#39;s it, we&amp;#39;ve got a working example!&lt;/p&gt;

&lt;h3 id=&quot;When-should-I-use-Asynchronous-Programming&quot;&gt;When should I use Asynchronous Programming?&lt;/h3&gt;

&lt;p&gt;An asynchronous solution works best for problems that meet all of the following criteria:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;You need to do many things that could take awhile&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You don&amp;#39;t care about the order you do those things in&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that an asynchronous solution can be hard to read and potentially hard to maintain, you should use metrics to determine if this added complexity really buys you anything.&lt;/p&gt;

&lt;h3 id=&quot;Next-Improvement:-Lets-create-a-work-queue&quot;&gt;Next Improvement: Let&amp;#39;s create a work queue!&lt;/h3&gt;

&lt;p&gt;Work queues are good for throttling the work your application has to do, for scheduling when this work needs to happen, and is a good solution for anything that could potentially take a long time thus causing a timeout experience for the end user. To create a work queue, you need a message queue where one part of your application can post messages to (work to be done) and where another part of your application or a separate &lt;i&gt;worker&lt;/i&gt; process can access the messages and perform the work.&lt;/p&gt;

&lt;p&gt;You can throttle the database load by determining how many messages your worker handles at one time. This could be as simple as a while loop that pauses in between processing. You could also spin up more workers if your message queue gets too long. If you need to do massive updates to lots of records such that you don&amp;#39;t want to do them at a peak time when the database indexes are constantly being updated due to a large number of writes, you can schedule your worker processes to run at an off-peak time. This can be as simple as a perl script you write and then use a cron job to schedule.&lt;/p&gt;

&lt;p&gt;In our example, let&amp;#39;s say our users all hit the database the same time every week for these reports. These reports hit the database pretty hard which causes timeouts for other users and reports to fail to complete. Again, before we jump into adding yet more complexity to our technology stack, we need to consider if this solution is the best one for our problem.&lt;/p&gt;

&lt;p&gt;Other solutions could be to move our single database instance into a cluster, or to pre-compute the data into predictable date chunks. If we have a table that has a lengthy history we could look at windowing or partitioning of the table to limit the total results the query has to run against. Let&amp;#39;s say in this situation, we don&amp;#39;t have the resources to make changes to the database. Apparently that&amp;#39;s another department and there&amp;#39;s a lengthy red tape process we need to follow in order to get anything done in that regard. While that points to greater systemic problems at our example company, this does often reflect reality and we still need to come up with a solution.&lt;/p&gt;

&lt;p&gt;Enter RabbitMQ. RabbitMQ runs as a separate process which the various Perl processes communicate with via AMQP (Advanced Message Queuing Protocol) and is implemented in Erlang. RabbitMQ essentially receives and forwards messages. You could also use Redis and the Redis::Requeue library for the same thing, but RMQ offers us an asynchronous option.&lt;/p&gt;

&lt;h3 id=&quot;What-does-Asynchronous-Programming-have-to-do-with-RabbitMQ&quot;&gt;What does Asynchronous Programming have to do with RabbitMQ?&lt;/h3&gt;

&lt;p&gt;Sockets are traditionally a blocking connection. The actual connection attempt blocks until the connection is available. So to connect to RabbitMQ, we would need to wait for the HTTP connection and we would need to be able to respond to error messages. AnyEvent is an asynchronous library and AnyEvent::RabbitMQ is the canonical Perl library for interacting with RabbitMQ.&lt;/p&gt;

&lt;p&gt;The reason using an asynchronous connection with RabbitMQ is important is because RabbitMQ sends a heartbeat to determine if the connection is still active. Most web framework applications by their nature are blocking, code is only triggered when a specific request (usually via a URL route) is made.&lt;/p&gt;

&lt;p&gt;Once the publisher has established a connection, RabbitMQ can create an exchange. This exchange handles all incoming updates and redistributes them to the available queues. Once the exchange is created, RabbitMQ can send messages.&lt;/p&gt;

&lt;p&gt;If the web application does not respond to the RMQ heartbeat, RMQ will hang up on you thereby closing the connection. So unless you want to hang up and reconnect every time you want to send a message to RabbitMQ, you&amp;#39;ll need to double check that your web framework has a way to respond to this heartbeat.&lt;/p&gt;

&lt;p&gt;In the example code, I&amp;#39;ve chosen to use Mojolicious because Mojo::IO Loop handles multiple reactor backends.&lt;/p&gt;

&lt;h4 id=&quot;Step-1:-Replace-the-original-work-section-with-publishing-a-message-to-RabbitMQ&quot;&gt;Step 1: Replace the original &amp;ldquo;work&amp;rdquo; section with publishing a message to RabbitMQ&lt;/h4&gt;

&lt;p&gt;Some things to think about:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;do you need to keep a record of the queue data?&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;do you need to recreate the queue if the messages are lost?&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First we need to set up our RabbitMQ connection. This is in the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/missaugustina/perl-out-of-order/blob/master/worker-queue/bin/main.pl&quot;&gt;main.pl&lt;/a&gt; file of the worker queue version of the sample code.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ar&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent::RabbitMQ&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;load_xml_spec&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;host&lt;/span&gt;       &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'localhost'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;port&lt;/span&gt;       &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;5672&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;user&lt;/span&gt;       &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'guest'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;pass&lt;/span&gt;       &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'guest'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;vhost&lt;/span&gt;      &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;on_success&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This essentially connects to the message queue and then calls the &lt;code&gt;on_success&lt;/code&gt; callback. Inside this &lt;code&gt;on_success&lt;/code&gt; callback we then open the channel:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;word&quot;&gt;on_success&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ar&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$ar&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;open_channel&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;on_success&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;And inside the &lt;code&gt;on_success&lt;/code&gt; callback of the &lt;code&gt;open_channel&lt;/code&gt; we have the bit of code that actually puts stuff on the message queue:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;word&quot;&gt;on_success&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;     # use a named queue &amp;quot;reports&amp;quot;&lt;br /&gt;&lt;/span&gt;     &lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;declare_queue&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;queue&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'reports'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;auto_delete&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;     # publish (send) to the message queue&lt;br /&gt;&lt;/span&gt;     &lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;%publish_args&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;content_type&lt;/span&gt;    &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;encode_json&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;routing_key&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'reports'&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;%publish_args&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;     # and update the condition variable to say we're done with the&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# queue sending part&lt;br /&gt;&lt;/span&gt;     &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;Added report request to queue&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h4 id=&quot;Step-2:-Move-the-work-to-a-worker-process&quot;&gt;Step 2: Move the &lt;i&gt;work&lt;/i&gt; to a worker process&lt;/h4&gt;

&lt;p&gt;Now we&amp;#39;ve got something requesting work, we need a worker on the other end of the message queue actually doing the work.&lt;/p&gt;

&lt;p&gt;You can schedule your worker as a cron job which works with RabbitMQ because there isn&amp;#39;t any overstepping if the previous job hasn&amp;#39;t finished yet. You can also use AnyEvent::timer on a loop if you aren&amp;#39;t a fan of cron jobs. There a quite a few options for running your worker process on a schedule, the sample application just uses a simple Perl script with the idea that it would be a cron job.&lt;/p&gt;

&lt;p&gt;The worker will need to take a message, process it, then grab the next one. You can have as many of these running as you want depending on your work load. To determine your work load, log metrics and keep an eye on them. Don&amp;#39;t make assumptions that aren&amp;#39;t based on actual data!&lt;/p&gt;

&lt;p&gt;We&amp;#39;ll use the &lt;code&gt;consume()&lt;/code&gt; method to get the next message in the message queue. Once we get the message, we get the delivery tag for communication with the queue later. The payload is the queue item content. In our example we have this encoded in JSON so we need to decode it to do anything with it. This code can be found in the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/missaugustina/perl-out-of-order/blob/master/worker-queue/bin/report_worker.pl&quot;&gt;report_worker.pl&lt;/a&gt; file.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;comment&quot;&gt;# connect to the message queue as in the previous example&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$ar&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;open_channel&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;on_success&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;        # consume (read) messages when they arrive&lt;br /&gt;&lt;/span&gt;        &lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;consume&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;on_consume&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$message&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$frame&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$message&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;deliver&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;method_frame&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$delivery_tag&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$frame&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;delivery_tag&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$params&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;decode_json&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$message&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;                  # do work specified in %params...&lt;br /&gt;&lt;/span&gt;                                &lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;                  # confirm that we've done the work and the message&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# queue can drop the message&lt;br /&gt;&lt;/span&gt;                  &lt;span class=&quot;symbol&quot;&gt;$channel&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;ack&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;delivery_tag&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$delivery_tag&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&quot;The-Gotcha&quot;&gt;The Gotcha&lt;/h3&gt;

&lt;p&gt;Here&amp;#39;s what the work looks like in the &lt;i&gt;do work&lt;/i&gt; section mentioned above. We create a ReportBuilder instance and tell it to build the report.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$report_builder&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Poo::ReportBuilder&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$report&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$report_builder&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;build_report&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$report_json&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;encode_json&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$report_data&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$report&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Poo::Report&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cast&quot;&gt;&amp;#92;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now here&amp;#39;s the gotcha, and this is an easy mistake to make when you&amp;#39;re first dealing with asynchronous programming: Remember that our &lt;code&gt;build_report&lt;/code&gt; function itself uses AnyEvent::HTTP to build the reports - to run more than one web request at a time - and we didn&amp;#39;t write it in a way that plays well with the AnyEvent code we just wrote to deal with the message queue.&lt;/p&gt;

&lt;p&gt;If you were to run this code as is, you would get the following error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  AnyEvent::CondVar: recursive blocking wait attempted at ../lib/Poo/ReportBuilder.pm line 238&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For reference, I&amp;#39;ve implemented this in the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/missaugustina/perl-out-of-order/tree/master/async&quot;&gt;async&lt;/a&gt; version of the application in Github with a comment explaining to not do that. Use that code to play around with adding another asynchronous call (say by adding the RabbitMQ code) and seeing what happens.&lt;/p&gt;

&lt;p&gt;Remember, we have to call &lt;code&gt;recv&lt;/code&gt; at the point in our code when we absolutely need the result to continue: Because our program cannot continue until this method returns something, &lt;code&gt;recv()&lt;/code&gt; is considered a blocking function, but we don&amp;#39;t want to block in the middle of generating a report - we need to be going back to the event loop in order to respond to those heartbeats!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;recv&lt;/code&gt; always needs to be at the top level. We need to use callbacks at the highest level, not the &lt;code&gt;condvar&lt;/code&gt;. Anything that depends on any return value shouldn&amp;#39;t depend on a variable, it should bind to a callback.&lt;/p&gt;

&lt;p&gt;This is also why asynchronous programming can be very confusing and also very hard to maintain and debug. There are some techniques to improve this workflow, including Promises or Futures, but that&amp;#39;s outside of the scope of this article. I do encourage you to research them though as they are reasonable solutions for dealing with callback soup.&lt;/p&gt;

&lt;p&gt;Our original build_report method had this code:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;build_report&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$http_data&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;_get_data_from_urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;&amp;#92;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;%urls_list&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;    # do stuff with $http_data...&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We need to change this to bind to a callback so a caller can manage their own &lt;code&gt;condvar&lt;/code&gt; and their own &lt;code&gt;recv&lt;/code&gt; call.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;build_report&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$self&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;_get_data_from_urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;cast&quot;&gt;&amp;#92;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;%urls_list&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;        # do stuff with $http_data...&lt;br /&gt;&lt;/span&gt;        &lt;span class=&quot;operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&amp;#39;ll alter the &lt;code&gt;_get_data_from_urls()&lt;/code&gt; method by removing the &lt;code&gt;recv&lt;/code&gt; method and by using the &lt;code&gt;cb&lt;/code&gt; method instead. Whenever it completes and something is sent to the &lt;code&gt;condvar&lt;/code&gt;, the &lt;code&gt;cb&lt;/code&gt; method of the &lt;code&gt;condvar&lt;/code&gt; calls the specified function as soon as it completes. The caller is responsible for providing a callback.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;br /&gt;28:&amp;nbsp;&lt;br /&gt;29:&amp;nbsp;&lt;br /&gt;30:&amp;nbsp;&lt;br /&gt;31:&amp;nbsp;&lt;br /&gt;32:&amp;nbsp;&lt;br /&gt;33:&amp;nbsp;&lt;br /&gt;34:&amp;nbsp;&lt;br /&gt;35:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;_get_data_from_urls&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$urls&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$callback&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;AnyEvent&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;condvar&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$customerid&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;http_request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# seconds&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$body&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$hdr&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$customerid&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$service_name&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$body&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;  # this replaces &amp;quot;my $http_result = $cv-&amp;gt;recv;&amp;quot;               # &amp;lt;--&lt;br /&gt;&amp;nbsp;&amp;nbsp;# now the condition variable calls the callback when it      # &amp;lt;-- new&lt;br /&gt;&amp;nbsp;&amp;nbsp;# reaches the ready state                                    # &amp;lt;-- code&lt;br /&gt;&lt;/span&gt;  &lt;span class=&quot;symbol&quot;&gt;$cv&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$callback&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;                                          &lt;span class=&quot;comment&quot;&gt;# &amp;lt;--&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&quot;Sample-Code-Available&quot;&gt;Sample Code Available&lt;/h3&gt;

&lt;p&gt;Again, I want to reiterate, I have &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/missaugustina/perl-out-of-order/&quot;&gt;sample code&lt;/a&gt; available for you to download and play with. Please experiment with this, try setting different values and using your debugger to step through the code to see when things get called and what values they produce. Asynchronous programming isn&amp;#39;t something you really understand until you have to use it, and it&amp;#39;s worth understanding.&lt;/p&gt;

&lt;h2 id=&quot;See-Also&quot;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/AnyEvent&quot;&gt;AnyEvent&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://github.com/missaugustina/perl-out-of-order&quot;&gt;Sample code&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=VYBLCvMu_pA&quot;&gt;YAPC::NA talk video&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/AnyEvent::HTTP&quot;&gt;AnyEvent::HTTP&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/AnyEvent::RabbitMQ&quot;&gt;AnyEvent::RabbitMQ&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.rabbitmq.com/&quot;&gt;http://www.rabbitmq.com/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Promises&quot;&gt;Promises&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Future&quot;&gt;Future&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</description>
         <author>Augustina Ragwitz</author>
         <guid isPermaLink="false">http://perladvent.org/2014/2014-12-24.html</guid>
         <pubDate>Wed, 24 Dec 2014 05:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[java] A Musical Finale</title>
         <link>http://feedproxy.google.com/~r/JavaAdventCalendar/~3/DvLi6qSq238/a-musical-finale.html</link>
         <description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align:left;&quot;&gt;&lt;h2 style=&quot;text-align:left;&quot;&gt;What could be more fitting than Christmas music for Christmas Eve?&lt;/h2&gt;&lt;div&gt;&lt;div&gt;&lt;div style=&quot;text-align:left;&quot;&gt;In this post I want to discuss the joy of making music with Java and why/how I have come to use Python...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;But first, let us celebrate the season!&lt;/h3&gt;We are all human and irrespective of our beliefs, it seems we all enjoy music of some form. For me some of the most beautiful music of all was written by Johan Sebastian Bach. Between 1708 and 1717 he wrote a set of pieces which are collectively called Orgelbüchlein (Little Organ Book). For this post and to celebrate the Java Advent Calendar I tasked Sonic Field to play this piece of music modelling the sounds of a 18th century pipe organ. If you did not know, yes some German organs of about that time really were able to produce huge sounds with reed pipes (for example, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://youtu.be/F51uHpH3yQk&quot;&gt;Passacaglia And Fugue&lt;/a&gt; the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.organartmedia.com/trost&quot;&gt;Trost Organ&lt;/a&gt;). The piece here is a 'Choral Prelude' which is based on what we would in English commonly call a Carol to be sung by an ensemble.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;embed width=&quot;320&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/v/Xdm0_eKyaT0?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style=&quot;text-align:center;&quot;&gt;BWV 610 Jesu, meine Freude [Jesus, my joy]&lt;br /&gt;&lt;i&gt;This performance dedicated to the Java Advent Calendar&lt;/i&gt;&lt;br /&gt;&lt;i&gt;and created exclusively on the JVM using pure&lt;/i&gt;&lt;br /&gt;&lt;i&gt;mathematics.&lt;/i&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;How was this piece created?&lt;/b&gt;&lt;br /&gt;Step one is to transcribe the score into midi. Fortunately, someone else already did this for me using automated score reading software. Not so fortunately, this software makes all sorts of mistakes which have to be fixed. The biggest issue with automatically generated midi files is that they end up with &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://manual.ardour.org/editing-and-arranging/edit-midi/handle-overlapping-notes/&quot;&gt;overlapped notes on the same channel&lt;/a&gt;; that is strictly impossible in midi and ends up with an ambiguous interpretation of what the sound should be. Midi considers audio as note on, note off. So Note On, Note On, Note Off, Note Off is ambiguous; does it mean:&lt;br /&gt;&lt;br /&gt;One note overlapping the next or:&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;-----------------&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;---------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One note entirely contained in a longer note?&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;----------------------------&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;----&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;Fortunately, tricks can be used to try and figure this out based on note length etc. The Java decoder always treats notes as fully contained. The Python method looks for very short notes which are contained in long ones and guesses the real intention was two long notes which ended up overlapped slightly. Here is the python (the Java is here on &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/src/com/nerdscentral/audio/io/MidiFunctions.java&quot;&gt;github&lt;/a&gt;).&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;def repareOverlapMidi(midi,blip=5):&lt;br /&gt;    print &quot;Interpretation Pass&quot;&lt;br /&gt;    mute=True&lt;br /&gt;    while mute:&lt;br /&gt;        endAt=len(midi)-1&lt;br /&gt;        mute=False&lt;br /&gt;        index=0&lt;br /&gt;        midiOut=[]&lt;br /&gt;        this=[]&lt;br /&gt;        next=[]&lt;br /&gt;        print &quot;Demerge pass:&quot;,endAt&lt;br /&gt;        midi=sorted(midi, key=lambda tup: tup[0])&lt;br /&gt;        midi=sorted(midi, key=lambda tup: tup[3])&lt;br /&gt;        while index&amp;lt;endAt:&lt;br /&gt;            this=midi[index]&lt;br /&gt;            next=midi[index+1]&lt;br /&gt;            ttickOn,ttickOff,tnote,tkey,tvelocity=this&lt;br /&gt;            ntickOn,ntickOff,nnote,nkey,nvelocity=next&lt;br /&gt;    &lt;br /&gt;            # Merge interpretation&lt;br /&gt;            finished=False&lt;br /&gt;            dif=(ttickOff-ttickOn)&lt;br /&gt;            if dif&amp;lt;blip and tkey==nkey and ttickOff&amp;gt;=ntickOn and ttickOff&amp;lt;=ntickOff:&lt;br /&gt;                print &quot;Separating: &quot;,this,next,&quot; Diff: &quot;,(ttickOff-ntickOn)&lt;br /&gt;                midiOut.append([ttickOn ,ntickOn ,tnote,tkey,tvelocity])&lt;br /&gt;                midiOut.append([ttickOff,ntickOff,nnote,nkey,nvelocity])&lt;br /&gt;                index+=1&lt;br /&gt;                mute=True     &lt;br /&gt;            elif  dif&amp;lt;blip:&lt;br /&gt;                print &quot;Removing blip: &quot;,(ttickOff-ttickOn)&lt;br /&gt;                index+=1&lt;br /&gt;                mute=True     &lt;br /&gt;                continue&lt;br /&gt;            else:&lt;br /&gt;                midiOut.append(this)       &lt;br /&gt;            # iterate the loop&lt;br /&gt;            index+=1&lt;br /&gt;        if index==endAt:&lt;br /&gt;            midiOut.append(next)&lt;br /&gt;        if not mute:&lt;br /&gt;            return midiOut&lt;br /&gt;        midi=midiOut&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;[&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/scripts/python/Bach-Large-Organ/note-formation.sy&quot;&gt;This AGPL code is on Github&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;Then comes some real fun. If you know the original piece, you might have noticed that the introduction is not original. I added that in the midi editing software &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://ariamaestosa.sourceforge.net/&quot;&gt;Aria Maestosa&lt;/a&gt;. It does not need to be done this way; we do not even need to use midi files. A lot of the music I have created in Sonic Field is just coded directly in Python. However, from midi is how it was done here.&lt;br /&gt;&lt;br /&gt;Once we have a clean set of notes they need to be converted into sounds. That is done with 'voicing'. I will talk a little about that to set the scene then we can get back into more Java code oriented discussion. After all, this is the Java advent calendar!&lt;br /&gt;&lt;br /&gt;Voicing is exactly the sort of activity which brings Python to the fore. Java is a wordy language which has a large degree of strictness. It favours well constructed, stable structures. Python relies on its clean syntax rules and layout and the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Principle_of_least_astonishment&quot;&gt;principle of least astonishment.&lt;/a&gt; For me, this Pythonic approach really helps with the very human process of making a sound:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;def chA():&lt;br /&gt;    global midi,index&lt;br /&gt;    print &quot;##### Channel A #####&quot;&lt;br /&gt;    index+=1&lt;br /&gt;    midi=shorterThanMidi(midis[index],beat,512)&lt;br /&gt;    midi=dampVelocity(midi,80,0.75)&lt;br /&gt;    doMidi(voice=leadDiapason,vCorrect=1.0)&lt;br /&gt;    postProcess()&lt;br /&gt;    &lt;br /&gt;    midi=longAsMidi(midis[index],beat,512)&lt;br /&gt;    midi=legatoMidi(midi,beat,128)&lt;br /&gt;    midi=dampVelocity(midi,68,0.75)&lt;br /&gt;    midi=dampVelocity(midi,80,0.75)&lt;br /&gt;    doMidi(voice=orchestralOboe,vCorrect=0.35,flatEnv=True,pan=0.2)&lt;br /&gt;    postProcessTremolate(rate=3.5)&lt;br /&gt;    doMidi(voice=orchestralOboe,vCorrect=0.35,flatEnv=True,pan=0.8)&lt;br /&gt;    postProcessTremolate(rate=4.5)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Above is a 'voice'. Contrary to what one might think, a synthesised sound does not often consist of just one sound source. It consists of many. A piece of music might have many 'voices' and each voice will be a composite of several sounds. To create just the one voice above I have split the notes into long notes and short notes. Then the actual notes are created by a call to doMidi. This takes advantage of Python's 'named arguments with default values' feature. Here is the signature for doMidi:&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;def doMidi(voice,vCorrect,pitchShift=1.0,qFactor=1.0,subBass=False,flatEnv=False,pure=False,pan=-1,rawBass=False,pitchAdd=0.0,decay=False,bend=True):&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float:left;margin-right:1em;text-align:left;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://1.bp.blogspot.com/-EAAntOrHBnw/VJb3guSNz_I/AAAAAAAAqWA/sG7LfMZrbYc/s1600/sing-spectrum.tiff&quot; style=&quot;clear:left;margin-bottom:1em;margin-left:auto;margin-right:auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-EAAntOrHBnw/VJb3guSNz_I/AAAAAAAAqWA/sG7LfMZrbYc/s1600/sing-spectrum.tiff&quot; height=&quot;146&quot; width=&quot;320&quot;/&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align:center;&quot;&gt;&lt;i&gt;The most complex (unsurprisingly) voice to create is that&lt;/i&gt;&lt;br /&gt;&lt;i&gt;of a human singing. I have been working on this for&lt;/i&gt;&lt;br /&gt;&lt;i&gt;a long time and there is a long way to go; however, its&lt;/i&gt;&lt;br /&gt;&lt;i&gt;is a spectrogram of a piece of music which does&lt;/i&gt;&lt;br /&gt;&lt;i&gt;a passable job of sounding like someone singing.&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The first argument is actually a reference to a function which will create the basic tone. The rest of the arguments describe how that tone will be manipulated in the note formation. Whilst an approach like this can be mimicked using a builder pattern in Java; this latter language does not lend it self to the 'playing around' nature of Python (at least for me).&lt;br /&gt;&lt;br /&gt;For example, I could just run the script and add flatEvn=True to the arguments and run it again and compare the two sounds. It is an intuitive way of working.&lt;br /&gt;&lt;br /&gt;Anyhow, once each voice has been composited from many tones and tweaked into the shape and texture we want, they turn up as a huge list of lists of notes which are all mixed together and written out to disk as a flat file format which is basically just a dump of the underlying double data. At this point it sounds terrible! Making the notes is often only half the story.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;embed width=&quot;320&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/v/LGYcCJXKtgw?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-size:x-small;&quot;&gt;Voice Synthesis by Sonic Field&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-size:x-small;&quot;&gt;played specifically for this post.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;You see, real sounds happen in a space. Our Choral is expected to be performed in a church. Notes played without a space around them sound completely artificial and lack any interest. To solve this we use impulse response reverberation. The mathematics behind this is rather complex and so I will not go into it in detail. However in the next section I will start to look at this as a perfect example of why Java is not only necessary but ideal as the back end to Python/Jython.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;You seem to like Python Alex - Why Bother With Java?&lt;/h3&gt;&lt;div class=&quot;p1&quot;&gt;My post might seem a bit like a Python sales job so far. What has been happening is simply a justification of using Python when Java is so good as a language (especially when written in a great IDE like Eclipse for Java). Let us look at something Python would be very bad indeed at. Here is the code for performing the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Fast_Fourier_transform&quot;&gt;Fast Fourier Transform&lt;/a&gt;, which is a the heart of putting sounds into a space.&lt;/div&gt;&lt;div class=&quot;p1&quot;&gt;&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;package com.nerdscentral.audio.pitch.algorithm;&lt;br /&gt;&lt;br /&gt;public class CacheableFFT&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    private final int      n, m;&lt;br /&gt;&lt;br /&gt;    // Lookup tables. Only need to recompute when size of FFT changes.&lt;br /&gt;    private final double[] cos;&lt;br /&gt;    private final double[] sin;&lt;br /&gt;    private final boolean  forward;&lt;br /&gt;&lt;br /&gt;    public boolean isForward()&lt;br /&gt;    {&lt;br /&gt;        return forward;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int size()&lt;br /&gt;    {&lt;br /&gt;        return n;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public CacheableFFT(int n1, boolean isForward)&lt;br /&gt;    {&lt;br /&gt;        this.forward = isForward;&lt;br /&gt;        this.n = n1;&lt;br /&gt;        this.m = (int) (Math.log(n1) / Math.log(2));&lt;br /&gt;&lt;br /&gt;        // Make sure n is a power of 2&lt;br /&gt;        if (n1 != (1 &amp;lt;&amp;lt; m)) throw new RuntimeException(Messages.getString(&quot;CacheableFFT.0&quot;)); //$NON-NLS-1$&lt;br /&gt;&lt;br /&gt;        cos = new double[n1 / 2];&lt;br /&gt;        sin = new double[n1 / 2];&lt;br /&gt;        double dir = isForward ? -2 * Math.PI : 2 * Math.PI;&lt;br /&gt;&lt;br /&gt;        for (int i = 0; i &amp;lt; n1 / 2; i++)&lt;br /&gt;        {&lt;br /&gt;            cos[i] = Math.cos(dir * i / n1);&lt;br /&gt;            sin[i] = Math.sin(dir * i / n1);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void fft(double[] x, double[] y)&lt;br /&gt;    {&lt;br /&gt;        int i, j, k, n1, n2, a;&lt;br /&gt;        double c, s, t1, t2;&lt;br /&gt;&lt;br /&gt;        // Bit-reverse&lt;br /&gt;        j = 0;&lt;br /&gt;        n2 = n / 2;&lt;br /&gt;        for (i = 1; i &amp;lt; n - 1; i++)&lt;br /&gt;        {&lt;br /&gt;            n1 = n2;&lt;br /&gt;            while (j &amp;gt;= n1)&lt;br /&gt;            {&lt;br /&gt;                j = j - n1;&lt;br /&gt;                n1 = n1 / 2;&lt;br /&gt;            }&lt;br /&gt;            j = j + n1;&lt;br /&gt;&lt;br /&gt;            if (i &amp;lt; j)&lt;br /&gt;            {&lt;br /&gt;                t1 = x[i];&lt;br /&gt;                x[i] = x[j];&lt;br /&gt;                x[j] = t1;&lt;br /&gt;                t1 = y[i];&lt;br /&gt;                y[i] = y[j];&lt;br /&gt;                y[j] = t1;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // FFT&lt;br /&gt;        n1 = 0;&lt;br /&gt;        n2 = 1;&lt;br /&gt;&lt;br /&gt;        for (i = 0; i &amp;lt; m; i++)&lt;br /&gt;        {&lt;br /&gt;            n1 = n2;&lt;br /&gt;            n2 = n2 + n2;&lt;br /&gt;            a = 0;&lt;br /&gt;&lt;br /&gt;            for (j = 0; j &amp;lt; n1; j++)&lt;br /&gt;            {&lt;br /&gt;                c = cos[a];&lt;br /&gt;                s = sin[a];&lt;br /&gt;                a += 1 &amp;lt;&amp;lt; (m - i - 1);&lt;br /&gt;&lt;br /&gt;                for (k = j; k &amp;lt; n; k = k + n2)&lt;br /&gt;                {&lt;br /&gt;                    t1 = c * x[k + n1] - s * y[k + n1];&lt;br /&gt;                    t2 = s * x[k + n1] + c * y[k + n1];&lt;br /&gt;                    x[k + n1] = x[k] - t1;&lt;br /&gt;                    y[k + n1] = y[k] - t2;&lt;br /&gt;                    x[k] = x[k] + t1;&lt;br /&gt;                    y[k] = y[k] + t2;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;[&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/src/com/nerdscentral/audio/pitch/algorithm/CacheableFFT.java&quot;&gt;This AGPL code is on Github&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;It would be complete lunacy to implement this methematics in JPython (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Late_binding#Late_binding_in_dynamically-typed_languages&quot;&gt;dynamic late binding&lt;/a&gt;&amp;nbsp;would give unusably bad performance). Java does a great job of running it quickly and efficiently. In Java this runs just about as fast as it could in any language plus the clean, simple object structure of Java means that using the 'caching' system as straight forward. The caching comes from the fact that the cos and sin multipliers of the FFT can be re-used when the transform is the same length. Now, in the creation of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Reverberation&quot;&gt;reverberation effects&lt;/a&gt; (those effects which put sound into a space) FFT lengths are the same over and over again due to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.ni.com/white-paper/4844/en/&quot;&gt;windowing&lt;/a&gt;. So the speed and object oriented power of Java have both fed into creating a clean, high performance implementation.&lt;br /&gt;&lt;br /&gt;But we can go further and make the FFT parallelised:&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;def reverbInner(signal,convol,grainLength):&lt;br /&gt;    def rii():&lt;br /&gt;        mag=sf.Magnitude(+signal)&lt;br /&gt;        if mag&amp;gt;0:&lt;br /&gt;            signal_=sf.Concatenate(signal,sf.Silence(grainLength))&lt;br /&gt;            signal_=sf.FrequencyDomain(signal_)&lt;br /&gt;            signal_=sf.CrossMultiply(convol,signal_)&lt;br /&gt;            signal_=sf.TimeDomain(signal_)&lt;br /&gt;            newMag=sf.Magnitude(+signal_)&lt;br /&gt;            if newMag&amp;gt;0:&lt;br /&gt;                signal_=sf.NumericVolume(signal_,mag/newMag)        &lt;br /&gt;                # tail out clicks due to amplitude at end of signal &lt;br /&gt;                return sf.Realise(signal_)&lt;br /&gt;            else:&lt;br /&gt;                return sf.Silence(sf.Length(signal_))&lt;br /&gt;        else:&lt;br /&gt;            -convol&lt;br /&gt;            return signal&lt;br /&gt;    return sf_do(rii)&lt;br /&gt;            &lt;br /&gt;def reverberate(signal,convol):&lt;br /&gt;    def revi():&lt;br /&gt;        grainLength = sf.Length(+convol)&lt;br /&gt;        convol_=sf.FrequencyDomain(sf.Concatenate(convol,sf.Silence(grainLength)))&lt;br /&gt;        signal_=sf.Concatenate(signal,sf.Silence(grainLength))&lt;br /&gt;        out=[]&lt;br /&gt;        for grain in sf.Granulate(signal_,grainLength):&lt;br /&gt;            (signal_i,at)=grain&lt;br /&gt;            out.append((reverbInner(signal_i,+convol_,grainLength),at))&lt;br /&gt;        -convol_&lt;br /&gt;        return sf.Clean(sf.FixSize(sf.MixAt(out)))&lt;br /&gt;    return sf_do(revi)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Here we have the Python which performs the FFT to produce &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Convolution_reverb&quot;&gt;impulse response reverberation&lt;/a&gt;&amp;nbsp;(c&lt;i&gt;onvolution reverb&lt;/i&gt; is another name for this approach). The second function breaks the sound into grains. Each grain is then processes individually and they all have the same length. This performs that windowing effect I talked about earlier (I use a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Window_function#Triangular_window&quot;&gt;triangular window&lt;/a&gt; which is not ideal but works well enough due to the long window size). If the grains are long enough, the impact of lots of little FFT calculation basically the same as the effect of one huge one. However, FFT is a nLog(n) process, so lots of little calculations is a lot faster than one big one. In effect, windowing make FFT become a linear scaling calculation.&lt;br /&gt;&lt;br /&gt;Note that the granulation process is performed in a future. We define a closure called &lt;i&gt;revi&lt;/i&gt; and pass it to &lt;i&gt;sf_do()&lt;/i&gt; which is executed it at some point in the future base on demand and the number of threads available. &amp;nbsp;Next we can look at the code which performs the FFT on each grain - &lt;i&gt;rii&lt;/i&gt;. That again is performed in a future. In other words, the individual windowed FFT calculations are all performed in futures. The expression of a parallel windowed FFT engine in C or FORTRAN ends up very complex and rather intractable. I have not personally come across one which is integrated into the generalised, thread pooled, future based schedular. Nevertheless, the combination of Jython and Java makes such a thing very easy to create.&lt;br /&gt;&lt;br /&gt;&lt;h3 style=&quot;text-align:left;&quot;&gt;How are the two meshed?&lt;/h3&gt;Now that I hope I have put a good argument for hybrid programming between a great dynamic language (in this case Python) and a powerful mid level static language (in this case Java) it is time to look at how the two are fused together. There are many ways of doing this but Sonic Field picks a very distinct approach. It does not offer a general interface between the two where lots of intermediate code is generated and each method in Java is exposed separately into Python; rather it uses a uniform single interface with virtual dispatch.&lt;br /&gt;&lt;br /&gt;Sonic Field defines a very (aggressively) simple calling convention from Python into Java which initially might look like a major pain in the behind but works out to create a very flexible and powerful approach.&lt;br /&gt;&lt;br /&gt;Sonic Field defines 'operators' which all implement the following interface:&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;/* For Copyright and License see LICENSE.txt and COPYING.txt in the root directory */&lt;br /&gt;package com.nerdscentral.sython;&lt;br /&gt;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * @author AlexTu&lt;br /&gt; * &lt;br /&gt; */&lt;br /&gt;public interface SFPL_Operator extends Serializable&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * &amp;lt;b&amp;gt;Gives the key word which the parser will use for this operator&amp;lt;/b&amp;gt;&lt;br /&gt;     * &lt;br /&gt;     * @return the key word&lt;br /&gt;     */&lt;br /&gt;    public String Word();&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * &amp;lt;b&amp;gt;Operate&amp;lt;/b&amp;gt; What ever this operator does when SFPL is running is done by this method. The execution loop all this&lt;br /&gt;     * method with the current execution context and the passed forward operand.&lt;br /&gt;     * &lt;br /&gt;     * @param input&lt;br /&gt;     *            the operand passed into this operator&lt;br /&gt;     * @param context&lt;br /&gt;     *            the current execution context&lt;br /&gt;     * @return the operand passed forward from this operator&lt;br /&gt;     * @throws SFPL_RuntimeException&lt;br /&gt;     */&lt;br /&gt;    public Object Interpret(Object input, SFPL_Context context) throws SFPL_RuntimeException;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style=&quot;font-weight:normal;&quot;&gt;&lt;span style=&quot;font-size:small;&quot;&gt;[&lt;/span&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/src/com/nerdscentral/sython/SFPL_Operator.java&quot;&gt;&lt;span style=&quot;font-size:small;&quot;&gt;This AGPL code is on Github&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-size:small;&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size:small;&quot;&gt;&lt;span style=&quot;font-weight:normal;&quot;&gt;The word() method returns the name of the operator as it will be expressed in Python. The Interpret() method processes arguments passed to it from Python. As Sonic Field comes up it creates a Jython interpreter and then adds the operators to it.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-weight:normal;&quot;&gt;The mechanism for doing this is a little involved so rather than go into detail here, I will simply give links to the code on github:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/src/com/nerdscentral/sython/Sython.java&quot; style=&quot;font-weight:normal;&quot;&gt;&lt;span style=&quot;font-size:small;&quot;&gt;SonicField.java&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-size:small;font-weight:normal;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/nerds-central/SonicFieldRepo/blob/master/SonicField/src/com/nerdscentral/sython/Sython.java&quot; style=&quot;font-weight:normal;&quot;&gt;SonicField.py&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;div style=&quot;text-align:left;&quot;&gt;&lt;span style=&quot;font-size:small;font-weight:normal;&quot;&gt;The result is that every operator is exposed in Python as sf.xxx where xxx is the return from the word() method. With clever operator overloading and other syntactical tricks in Python I am sure that the approach could be refined. Right now, there are a lot of sf.xxx calls in Sonic Field Python ( I call it Synthon ) but I have not gotten around to improving on this simple and effective approach.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:small;font-weight:normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;You might have noticed that everything passed into Java from Python is just 'object'. This seems a bit crude at first take. However, as we touched on in the section of futures in the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.javaadvent.com/2014/12/a-serpentine-path-to-music.html&quot;&gt;previous post&lt;/a&gt;, it offers many advantages because the translation from Jython to Java is orchestrated via the Caster object and a layer of Python which transparently perform many useful translations. For example, the code automatically translates multiple arguments in Jython to a list of objects in Java:&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;    def run(self,word,input,args):&lt;br /&gt;        if len(args)!=0:&lt;br /&gt;            args=list(args)&lt;br /&gt;            args.insert(0,input)&lt;br /&gt;            input=args&lt;br /&gt;        trace=''.join(traceback.format_stack())&lt;br /&gt;        SFSignal.setPythonStack(trace)&lt;br /&gt;        ret=self.processors.get(word).Interpret(input,self.context)&lt;br /&gt;        return ret&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;Here we can see how the arguments are processed into a list &amp;nbsp;(which is Jython is implemented as an ArrayList) if there are more than one but are passed as a single object is there is only one. We can also see how the Python stack trace is passed into a thread local in &amp;nbsp;the Java SFSignal object. Should an SFSignal not be freed or be double collected, this Python stack is displayed to help debug the program.&lt;br /&gt;&lt;br /&gt;&lt;h4 style=&quot;text-align:left;&quot;&gt;Is this interface approach a generally good idea for Jython/Java Communication?&lt;/h4&gt;Definitely not! It works here because of the nature of the Sonic Field audio progressing architecture. We have processors which can be chained. Each processor has a simple input and output. The semantic content passed between Python and Java is quite limited. In more general purpose programming, this simple architecture, rather than being flexible and powerful, would be highly restrictive. In this case, the normal Jython interface with Java would be much more effective. Again, we can see a great example of this simplicity in the previous post when talking about threading (where Python access Java Future objects). Another example is the direct interaction of Python with SFData objects in this post on &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://sonic-field.blogspot.co.uk/2014/03/python-creating-oscillators-in-python.html&quot;&gt;modelling oscillators in Python&lt;/a&gt;.&lt;br /&gt;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;&lt;br /&gt;from com.nerdscentral.audio import SFData&lt;br /&gt;...&lt;br /&gt;            data=SFData.build(len)&lt;br /&gt;            for x in range(0,length):&lt;br /&gt;                s,t,xs=osc.next()&lt;br /&gt;                data.setSample(x,s)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Which violated the programming model of Sonic Field by creating audio samples directly from Jython, but at the same time illustrates the power of Jython! It also created one of the most unusual soundscapes I have so far achieved with the technology:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;embed width=&quot;320&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/v/nV5T2n6RAa0?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;font-size:x-small;&quot;&gt;&lt;i&gt;Engines of war, sound modelling&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;font-size:x-small;&quot;&gt;&lt;i&gt;from oscillators in Python.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;h3 style=&quot;text-align:left;&quot;&gt;Wrapping It Up&lt;/h3&gt;Well, that is all folks. I could ramble on for ever, but I think I have answered most if not all of the questions I set out in the first post. The key ones that really interest me are about creativity and hybrid programming. Naturally, I am obsessed with performance as I am by profession an optimisation consultant, but moving away from my day job, can Jython and Java be a creating environment and do they offer more creativity than pure Java?&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float:left;margin-right:1em;text-align:left;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://4.bp.blogspot.com/-_OASFw1c9Ak/VJajaqMzERI/AAAAAAAAqU0/n6Es1yyaNwA/s1600/F3.large.jpg&quot; style=&quot;clear:left;margin-bottom:1em;margin-left:auto;margin-right:auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-_OASFw1c9Ak/VJajaqMzERI/AAAAAAAAqU0/n6Es1yyaNwA/s1600/F3.large.jpg&quot; height=&quot;296&quot; width=&quot;320&quot;/&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align:center;&quot;&gt;Transition State Analysis using&lt;br /&gt;hybrid programming&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Too many years ago I worked on a similar hybrid approach in scientific computing. The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://people.bath.ac.uk/chsihw/grace/grace.html&quot;&gt;GRACE&lt;/a&gt; software which I helped develop as part of the team at &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.bath.ac.uk/&quot;&gt;Bath&lt;/a&gt; was able to break new ground because it was easier to explore ideas in the hybrid approach than writing raw FORTRAN constantly. I cannot present in deterministic, reductionist language a consistent argument for why this applied then to science or now to music; nevertheless, experience from myself and others has show this to be a strong argument.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;Whether you agree or disagree; irrespective of if you like the music or detest it; I wish you a very merry Christmas indeed.&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;&lt;em style=&quot;background-color:#fcffee;color:#222222;font-family:Verdana, Geneva, sans-serif;font-size:18px;line-height:24.6399993896484px;&quot;&gt;This post is part of the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://javaadvent.com/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Java Advent Calendar&lt;/a&gt;&amp;nbsp;and is licensed under the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://creativecommons.org/licenses/by/3.0/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Creative Commons 3.0 Attribution&lt;/a&gt;&amp;nbsp;license. If you like it, please spread the word by sharing, tweeting, FB, G+ and so on!&lt;/em&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=DvLi6qSq238:AstJ4UwAz5w:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=DvLi6qSq238:AstJ4UwAz5w:4cEx4HpKnUU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?i=DvLi6qSq238:AstJ4UwAz5w:4cEx4HpKnUU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=DvLi6qSq238:AstJ4UwAz5w:YwkR-u9nhCs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=YwkR-u9nhCs&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=DvLi6qSq238:AstJ4UwAz5w:qj6IDK7rITs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=qj6IDK7rITs&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/JavaAdventCalendar/~4/DvLi6qSq238&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Alexander Turner</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-2481158163384033132.post-373003818198838120</guid>
         <pubDate>Wed, 24 Dec 2014 00:30:00 +0000</pubDate>
         <media:thumbnail height="72" url="http://1.bp.blogspot.com/-EAAntOrHBnw/VJb3guSNz_I/AAAAAAAAqWA/sG7LfMZrbYc/s72-c/sing-spectrum.tiff" width="72" xmlns:media="http://search.yahoo.com/mrss/"/>
      </item>
      <item>
         <title>[sysadvent] Day 24 - 12 days of SecDevOps</title>
         <link>http://feedproxy.google.com/~r/sysadvent/~3/LK4uoLjMd1U/day-24-12-days-of-secdevops.html</link>
         <description>&lt;p&gt;Written by: Jen Andre (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/fun_cuddles&quot;&gt;@fun_cuddles&lt;/a&gt;)&lt;br&gt;
Edited by: Ben Cotton (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/funnelfiasco&quot;&gt;@funnelfiasco&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Ah, the holidays. The time of year when we want to be throwing back the eggnogs, chilling in front our fake fireplaces, maybe catching a funny Christmas day movie&amp;#8230; but oh no we can’t, because guess what, a certain entertainment company was held hostage by a security breach the likes of which corporate America has never seen before&amp;#8230; and no more movie for you. &lt;/p&gt;

&lt;p&gt;It’s an interesting time to be a security defender. The recent Sony breach has just put a period on the worst-of-the-worst scenarios that us tinfoil-hat, paranoid security people have been ranting about all along: one bad breach could be business shattering. &lt;/p&gt;

&lt;p&gt;But let’s step back, and look at the theme of this blog: the 12 days of SecDevOps. Besides being a ridiculous title that I’m 90% sure my ops director chose specifically as a troll for me (thanks, Pete), it underlines an important concept. &lt;strong&gt;Whether `security` is in your job title or not, operations is increasingly becoming the front-line for implementing security defenses.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given that reality, and the fact that security breaches are NOT going away, and that most of us don’t have yacht-sized security budgets, I thought it would be interesting to come up with 12 practical, high-impact things that small organizations could be doing to shore up their security posture. &lt;/p&gt;

&lt;h3&gt;Day 1: Fear and Loathing and Risk Assessment and Hipsters&lt;/h3&gt;

&lt;p&gt;Risk assessment. It’s not just some big words auditors love to use. It’s simply weighing the probability of bad things happening against the cost to mitigate the risk of that bad thing happening. And using that to make good security decisions as you make day-to-day architecture and ops choices:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;risk = (threat) x (probability) x (business impact)*&lt;/p&gt;

&lt;p&gt;*whoever told you there would be no math lied to you&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You may not be aware of it, but as an ops person you are likely doing risk assessment already, except more likely around things like uptime and reliability. Consider this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;John, the web guy, proposes replacing PostgreSQL with SomeNewHipsterDB.&lt;/li&gt;
&lt;li&gt;You ask yourself, ‘huh, what’s the chances that I’m going to get paged at 3am because writes stop happening and my web site starts screaming in pain?’ You are probably not having warm-fuzzy feelings about this plan.&lt;/li&gt;
&lt;li&gt;Your development and ops team evaluates the &lt;strong&gt;benefits&lt;/strong&gt; to the engineering team and business for switching to SomeNewHipsterDB and weighs it against the &lt;strong&gt;probability&lt;/strong&gt; that you are going to get woken up all of the time, and the &lt;strong&gt;impact&lt;/strong&gt; it will have on your sunny disposition and decide that yeah… maybe not gonna do it.&lt;/li&gt;
&lt;li&gt;Or, you do, except you &lt;strong&gt;mitigate&lt;/strong&gt; this risk by saying ‘John, you will be forever paged for all SomeNewHipsterDB issues. Done.’&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cool. Now do this for security. Every time you are making architecture choices, or changing configuration of your infrastructure, or considering some new third-party service SaaS you’ll be sending data to, you should be asking yourself: what’s the impact if that service or system gets hacked? How will you mitigate the risks? &lt;/p&gt;

&lt;p&gt;This doesn’t have to be a formal or fancy report. It can be a running text file or spreadsheet with all of the possible points of failure. Get everyone involved with thinking of ways pieces of the infrastructure or organization can be hacked, and ways you are protected against those worst-case scenarios. It can be like ‘ANYONE WHO OWNS OUR CHEF SERVER COULD DESTROY EVERYTHING [but we have uber-monitoring and Jane over there reviews audit logs daily]’. Start with the scenario: what if… ? and have conversations with engineers and business owners defend why what we’re doing is good enough. Make security a fundamentally collaborative process.&lt;/p&gt;

&lt;h3&gt;Day 2: Shared Secrets: Figure it Out Now&lt;/h3&gt;

&lt;p&gt;There’s 3 things in life that are inevitable: death, taxes&amp;#8230; and the fact that a sales guy left to his own devices will always put all of his passwords in a plain text file (or if fancy, an Excel spreadsheet).&lt;/p&gt;

&lt;p&gt;The lesson is this: password management isn’t something that just the technical team decides and manages for itself. We should be advocating &lt;strong&gt;organization-wide&lt;/strong&gt; education on managing credentials, because guess what? Access to Salesforce, Gmail, and all of these SaaS services with sensitive business data are being used by people who are not engineers. &lt;/p&gt;

&lt;p&gt;Solution? As part of every employee’s onboarding process, &lt;strong&gt;install password management on an employee’s workstation, and show them how to use it&lt;/strong&gt; (e.g. 1Password or LastPass, or whatever your tool of choice is). Start doing this from the outset, as it’s best to figure this out on Day 1 rather than 200 employees in. &lt;/p&gt;

&lt;h3&gt;Day 3: Shared Secrets for Infrastructure, Too&lt;/h3&gt;

&lt;p&gt;When it comes to infrastructure secrets, there are extra concerns because in most cases, systems needs to be able to access these secrets in a non-interactive, automated way (e.g. I need to be able to spin up an app server that knows how to authenticate to my database). &lt;/p&gt;

&lt;p&gt;If all of your infra passwords start unencrypted somewhere in a git repo, You Are Going To Have A Bad Time. &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://coderanger.net/chef-secrets/&quot;&gt;Noah has a good article on various options for managing shared secrets in your infrastructure.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Day 4: Config Management On All Of The Things (So You Aren’t Sweating from Shell Shocks)&lt;/h3&gt;

&lt;p&gt;This should be obvious to everyone who drinks from the DevOps Koolaid, but CM has done beautiful things for patch management. It may be tempting to deploy a one-off box used for dev manually without config management installed, but guess what? &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.browserstack.com/attack-and-downtime-on-9-November&quot;&gt;In the case of Browser Stack, that turned out to be a massive achilles heel.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making the process easy for devs to get access to the infrastructure they need (while giving you the ability to manage systems) is key. Do this right away.&lt;/p&gt;

&lt;h3&gt;Day 5: Secure your Development Environments (Because No One Else Will)&lt;/h3&gt;

&lt;p&gt;If left to their own devices, development environments tend to veer to chaotic. This isn’t just because developers are lazy (and as a developer, I mean this in the nicest possible way) but because of the nature of the prototyping and testing process. &lt;/p&gt;

&lt;p&gt;From a security perspective, this all means bad juju (see Browser Stack example above). I can assure you that if you start building your prototype or dev infrastructure exposed to the public internet, deploying it without even the basic config management, it will stay that way forever. &lt;/p&gt;

&lt;p&gt;So: if you are using AWS, start with an Amazon VPC with strict perimeter security, and require VPN access for any development infrastructure. Get some config management on everything, even if it’s just for system patches. &lt;/p&gt;

&lt;p&gt;Put some bounds around the chaos early on, and this will make it easy to mature the security controls as the product and organization mature. &lt;/p&gt;

&lt;h3&gt;Day 6: 2-Factor all of the things (well, the important things)&lt;/h3&gt;

&lt;p&gt;Require 2-factor wherever you can. Google Apps has made enforcing this super easy, and technologies like DuoSecurity and YubiKey make adding 2-factor to your critical infrastructure (e.g., your VPN accounts) far, far less annoying than it used to be.&lt;/p&gt;

&lt;h3&gt;Day 7: Encrypt your Emails (and other communications)&lt;/h3&gt;

&lt;p&gt;Encrypt your emails. It’s annoying to set up, but guess what? Hackers just &lt;em&gt;love&lt;/em&gt; to post juicy stuff on pastebin. Again, from Day 1, help every single employee configure PGP or SMIME encryption as part of the onboarding process. Once installed, it’s relatively painless to use (as long as you don’t mind archaic mail clients from 1999). &lt;/p&gt;

&lt;p&gt;This is especially important to drill into executives because they tend to have more sensitive emails (e.g. their private boardroom chatter), and are particularly susceptible to phishing style-attacks. With the recent Sony email leaks, you now have some leverage. You can throw the ‘Angelina Jolie’ emails in front of them and ask: how much do you think business and reputations would suffer were their entire email archives publically disclosed via a breach? &lt;/p&gt;

&lt;p&gt;For many of us, chat is as crucial as email in terms of the type of reputation-critical information we put there. It may not be reasonable to switch to a self-hosted chat solution, but in that case, ensure you are picking a service that helps YOU mitigate your risk. E.g., do you need all of the history? Do you need private history for user chats? &lt;/p&gt;

&lt;h3&gt;Day 8: Security Monitoring: Start Small, Plan Big&lt;/h3&gt;

&lt;p&gt;Put the infrastructure in place to collect as much security data as possible, then start slowly making potential security issues &lt;em&gt;visible&lt;/em&gt; by adding reports and alerts that deal with threat scenarios you are most worried about.&lt;/p&gt;

&lt;p&gt;Start small. Remember that risk assessment list you made? Identify what you are most afraid of (um, that PHP CMS that has hundreds of vulnerabilities reported per year? Your VPN server?) and tackle monitoring for those items first. &lt;/p&gt;

&lt;p&gt;Instrumenting your infrastructure from day 1 for security monitoring (even if it’s just collecting all of the system and application logs) puts you in a good position later on to start sophisticated reporting and intrusion detection on that data. &lt;/p&gt;

&lt;h3&gt;Day 9: Code/Design Reviews&lt;/h3&gt;

&lt;p&gt;Although there have been a lot of advancement in static and dynamic source code analysis tools (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://samate.nist.gov/index.php/Source_Code_Security_Analyzers.html&quot;&gt;which you can integrate right into your CI process&lt;/a&gt;), a good-old fashion code review by a human being goes a long way. If you’re using GitHub, just make it part of the development workflow and testing pipeline. Whenever changes are made to authentication or authorization, have someone look for automated tests that deal with those cases.&lt;/p&gt;

&lt;h3&gt;Day 10: Test Your Users&lt;/h3&gt;

&lt;p&gt;Phish yourself regularly. It’s really easy to do, and can be illuminating to the rest of the business which may not be as technical as the operations/engineering side, and not really understand really the impact of opening an attachment in an email or not checking URLs where they are logging into a website. &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://krebsonsecurity.com/2012/01/phishing-your-employees-101/&quot;&gt;You can use some open source tools&lt;/a&gt;, but are also many services now that you can pay to do this for you.&lt;/p&gt;

&lt;h3&gt;Day 11: Make an Incident Response Plan Now&lt;/h3&gt;

&lt;p&gt;So, you see something odd in your logs. Like, Bob your DBA ran a Postgres backup on production DB, tar’d it up, and sent it to an FTP server in Singapore. Bob lives in Reston VA, and this is definitely not normal. You start seeing evidence of other weird stuff ‘bob’ is doing that he shouldn’t be.&lt;/p&gt;

&lt;p&gt;What now? Do you email Bob and say ‘something weird is happening?’ Do you call the Director of Ops? Do you put a message in a lonely chat room? &lt;/p&gt;

&lt;p&gt;Figure out a plan for escalating possible critical security issues. Doesn’t have to be fancy or use specialize ITIL incident response workflow tools. Make a group in PagerDuty. Have an out-of-band channel for communicating details, in case your normal network goes the way of Sony and is totally compromised or just plain is not working. Maybe it’s as simple as an email list that doesn’t use the corporate email accounts, or a conference bridge everyone can hop on.&lt;/p&gt;

&lt;h3&gt;Day 12: Don’t be the Security ‘A**hole’&lt;/h3&gt;

&lt;p&gt;You. Yes, you. Don’t be the security a**hole that gets in everyone’s way and loses sight of the real reason for everyone’s existence: to run a business. You can be the security champion without being the blocker. In fact, that’s the only way to be effective. If a user is coming to you and saying ‘this is really really annoying, I don’t want to do it’ - &lt;strong&gt;listen to them&lt;/strong&gt;. Too many security personnel disregard the usability issue of security controls for the sake of security theater, which leads to (unsurprisingly) abandonment, cynicism, and apathy when it comes to real security concerns.&lt;/p&gt;

&lt;p&gt;DevOps is really a philosophy: it’s not a job title, or a set of tools, it’s the concept of using modern tools and processes to facilitate collaboration with the engineers who deliver the code and those who must maintain it. Um, that was a lot of words, but the key word is &lt;strong&gt;collaboration&lt;/strong&gt;. It’s no longer acceptable to throw ‘security over the wall’ and expect your users and ops people to just do what you say. &lt;/p&gt;

&lt;p&gt;The best security cultures are not prescriptive, they are collaborative. They understand that business needs to get done. They are intellectually honest and admit ‘yeah, we could get hacked’ - but what can we do about this in a way that doesn’t bring everything to a halt? &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.duosecurity.com/blog/duo-tech-talk-building-a-modern-security-engineering-organization&quot;&gt;Zane Lackey has a great talk on building a modern security engineering organization&lt;/a&gt; that expounds many of these ideas, and more.&lt;/p&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/sysadvent/~4/LK4uoLjMd1U&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Christopher Webber</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-3615332969083650973.post-7223093802223447718</guid>
         <pubDate>Wed, 24 Dec 2014 00:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[ux] The Elf that Came in From the Cold</title>
         <link>http://uxmas.com/2014/the-elf-that-came-in-from-the-cold</link>
         <description>&lt;p&gt;UCD City was asleep. The gin joints were shut. Hoods and flatfoots and gumshoes alike were all in their holes. Snow fell like a silent movie, blanketing the usual street noise of passing cars and fighting alley cats. Christmas neon flashed on every second apartment. Behind the lopsided shutters of my one-man agency I poured myself another lonely egg nog.&lt;/p&gt;

&lt;p&gt;The doorknob of my front door jiggled. I thought nothing of it&amp;mdash;probably kids on holidays up past their bedtime. Suddenly&amp;nbsp;the door burst open, and an elf tumbled in, clutching a mobile phone. His eyes screamed silently as he reached toward&amp;nbsp;me.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Merry &amp;hellip;&amp;rdquo;&lt;/p&gt;

&lt;p&gt;He hit the floor. Only then did I notice the kitchen knife protruding from his kidneys.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img alt=&quot;A silhouette of an elf at the doorway&quot; src=&quot;http://uxmas.com/images/uploads/elf-in-doorway.jpg&quot; style=&quot;width:549px;height:496px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;I heard footsteps downstairs. Leaping over the elf&amp;rsquo;s body and flying down the staircase railings, I spied a shadow fleeing the building. I made it to the street, breathless, in time to watch twin tail lights screech around the corner. Another win for the bad guys. The neighbourhood fell silent and lonely again.&lt;/p&gt;

&lt;p&gt;Footprints were melting into the muddy slush: size 12 at least, probably boots. I glanced up at the window to my room where a dead elf lay.&lt;/p&gt;

&lt;p&gt;I was definitely going to be on the naughty list again this year.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;Most of the dark red wasn&amp;#39;t an intentional part of the elf&amp;#39;s costume&amp;mdash;it was now pooling on my floorboards. I was no stranger to crime, but this was heinous: a dead pixie on my doorstep on Christmas Eve? Hardly a Merry Christmas.&lt;/p&gt;

&lt;p&gt;What had he been trying to say? &amp;ldquo;Merry!&amp;rdquo; What did that mean? Merry Christmas? How was that a dying man&amp;#39;s secret this time of year? And why to me? I&amp;#39;d consulted with Santa&amp;#39;s Workshop much earlier in my career&amp;mdash;half a lifetime ago. But I&amp;rsquo;d had nothing to do with the operation since.&lt;/p&gt;

&lt;p&gt;There was a buzz from the smartphone in his little hand: a SnapChat message. I swiped the screen before thinking what I was doing, and deserved what I saw.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img alt=&quot;A SnapChat photo of Santa, bound and gagged&quot; src=&quot;http://uxmas.com/images/uploads/santa-tied-up.jpg&quot; style=&quot;width:550px;height:466px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;It was Saint Nick himself, bound, gagged, and seated on a stool. He looked haggard and beaten, and two armed men stood over him. Good grief&amp;mdash;who would dare mess with Santa? Was all of Christmas in jeopardy? I cursed as SnapChat erased the photo. Evidence and answers were slipping through my fingers. Damned &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/designing-for-ephemerality&quot;&gt;ephemeral messaging&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I rifled through the elf&amp;#39;s pockets, and turned up a Sharpie marker, some half-finished sketches on a bunch of post-it notes, the elf&amp;rsquo;s company RFID card, and a sealed envelope.&lt;/p&gt;

&lt;p&gt;I wrapped the envelope in a plastic bag, and pinned it to the outside window ledge. Then I took a closer look at the rest of the items.&lt;/p&gt;

&lt;p&gt;Printed on the RFID card was the elf&amp;rsquo;s name and position:&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;em&gt;&lt;strong&gt;Zachary Kringle&lt;/strong&gt;&lt;br /&gt;
Chief of Operations&lt;br /&gt;
Workshop Division&lt;br /&gt;
Santa&amp;rsquo;s Workshop Inc.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not a junior then. I sifted through&amp;nbsp;the post-it notes. The sketches were pretty basic&amp;mdash;an early concept for some sort of board game similar to Snakes &amp;amp; Ladders, with additional cards that formed part of the mix. The sketches were annotated&amp;mdash;&lt;strong&gt;process&lt;/strong&gt;, &lt;strong&gt;iterate&lt;/strong&gt;, &lt;strong&gt;collaborative&lt;/strong&gt;&amp;mdash;obviously some new gift idea he&amp;rsquo;d been working on. Too bad he&amp;rsquo;d croaked. It looked like a good game.&lt;/p&gt;

&lt;p&gt;I retrieved the sealed envelope from the bag on the windowsill. The gum was now frozen stiff, making it easy to open the envelope without damaging it. There was a photo inside. I recognised the face instantly.&lt;/p&gt;

&lt;p&gt;Mary Christmas.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img alt=&quot;A polaroid photograph of Mary Christmas getting into a black car&quot; src=&quot;http://uxmas.com/images/uploads/mary-getting-into-car.jpg&quot; style=&quot;width:550px;height:517px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;The elf&amp;#39;s words made more sense now: &amp;ldquo;Mary&amp;rdquo;, not &amp;ldquo;Merry&amp;rdquo;. Panic hit me like ice water. Could the Mary I knew really be behind such a brutal crime?&lt;/p&gt;

&lt;p&gt;Mary was as curvy as always. Not a young woman, but a plenty real one, like someone had poured her into her clothes and forgot to say when. It had been taken recently, and with a zoom lens: she was getting into a black car while her minders stood around. Behind her, the corner of a warehouse partially hid a dockside crane.&lt;/p&gt;

&lt;p&gt;I had my lead.&lt;/p&gt;

&lt;p&gt;There were two things I needed to do right away. The first was a simple task. I sat on my desk looking at the elf and called Uncle Xavier, the only straight cop I knew in homicide. Xavier worked old-school, and although we didn&amp;rsquo;t always see eye to eye, we both knew the way the game was played. I spilled my story but conveniently omitted the photo&amp;mdash;I would confront Mary myself when the time was right.&lt;/p&gt;

&lt;p&gt;The last few hours of downing egg nog had made my brain as lazy as an old dog. So I shrugged on my hat and trenchcoat, packed my trusty 357 snubnose and hit the icy pavement to clear my head.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;A dead elf, a captive Santa, Mary Christmas and a mystery warehouse: not much of a brief. I remembered a project I&amp;#39;d worked on with an engineer at Path-E-Tech Management. As the engineer said himself:&lt;/p&gt;

&lt;p&gt;&amp;ldquo;We interviewed hundreds of users, and turned all their suggestions into features. As it turns out, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/is-the-user-always-right&quot;&gt;every user we talked to was an idiot&lt;/a&gt;. And their dumb suggestions ruined our product. In hindsight &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.dilbert.com/strips/comic/2012-05-07/&quot;&gt;we should have talked to people outside the building&lt;/a&gt;.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Not the best attitude, but it does say something about user research outside the obvious. And that&amp;rsquo;s exactly what I planned to do.&lt;/p&gt;

&lt;p&gt;A pile of cardboard and old blankets moved as I walked past. &quot;Help an old graphic artist fallen on bad times?&quot; a voice croaked from within.&lt;/p&gt;

&lt;p&gt;&quot;You see anyone come past here in the last half hour?&quot; I asked.&lt;/p&gt;

&lt;p&gt;A&amp;nbsp;hooligan in a turtleneck poked his head out.&amp;nbsp;&quot;Just a short guy&amp;mdash;real shorty he was, and a gorilla. Jumped into a car and took off that way.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;I flipped him a few coins. He grinned in appreciation.&lt;/p&gt;

&lt;p&gt;&quot;Thanks man, Merry Christmas&quot;, he said.&lt;/p&gt;

&lt;p&gt;&quot;Yeah. Merry Christmas.&quot;&lt;/p&gt;

&lt;p&gt;No elf I&amp;#39;d ever met had size twelve boots and looked like a gorilla. Someone outside the Workshop had stabbed him in the back&amp;mdash;someone who didn&amp;#39;t want Christmas to run the usual clockwork. But who? And why was someone sending a SnapChat of a nicked Saint Nick to the elf? Did they know he was dead? What would happen if Santa wasn&amp;#39;t released in time? &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/the-5ws-and-1h-of-user-interviews&quot;&gt;These were the questions that needed answering.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I grunted. &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/santa-the-child-and-the-magic-of-ux&quot;&gt;Two billion unhappy kids&lt;/a&gt; is what would happen. The stakes couldn&amp;rsquo;t be higher.&lt;/p&gt;

&lt;p&gt;I talked to anyone who would listen: lovers buying last-minute gifts, retailers and late-night carol singers. And when my first coffee-stained notebook was full, I turned south&amp;mdash;I needed to triangulate my findings with a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/3-ways-to-select-the-perfect-method-for-your-research-goal&quot;&gt;different technique altogether&lt;/a&gt;.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;I stopped at a local toy store and made my way towards the back. Two figures behind frosted glass moved like a puppet show, and I stepped behind a giant cuddly Pink Panther to eavesdrop. I waited patiently, catching only snippets of information, but enough to make out something about global shipments. I was on the right path.&lt;/p&gt;

&lt;p&gt;The silhouettes left via a back door, and I waited until I heard the door slam. I stepped from my hiding place and into the back room. I fumbled with the lock on the drawer of the desk where they&amp;rsquo;d been seated. The lock was no match for my expertise with a paper clip, and once it was open I found the jackpot: the store manager&amp;rsquo;s journal.&lt;/p&gt;

&lt;p&gt;My greedy eyes ran over the entries from the past few weeks. I felt dirty&amp;mdash;it wasn&amp;#39;t my usual method of conducting a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmastery.com/resources/techniques/#diary-study&quot;&gt;diary study&lt;/a&gt;, but it sure delivered the goods. I tried to ignore the personal and stick to business: names, meeting times, summary notes &amp;hellip; I struck gold with a purchase order form for a toy shipment. It listed a warehouse address down on the waterfront. I took a quick snap using my camera phone.&lt;/p&gt;

&lt;p&gt;There was a creak behind me and a torch blinded me.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img alt=&quot;Our hero is held at gunpoint&quot; src=&quot;http://uxmas.com/images/uploads/grab-some-air.jpg&quot; style=&quot;width:550px;height:455px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;&quot;Grab some air, pal&quot; a gruff voice barked from the shadows. I raised my hands.&lt;/p&gt;

&lt;p&gt;I turned to look at him. I didn&amp;#39;t like his face. When he said his name was Skinny I didn&amp;#39;t like his name either. But the secret to being a great detective is to listen more and talk less&amp;mdash;I kept my trap shut.&lt;/p&gt;

&lt;p&gt;Two goons loomed behind him: dull eyes, flat heads, black hats, and no brains at all. I looked uneasily at their hands. They were big&amp;mdash;as big as plates of pork ribs, and twice as greasy. I knew exactly what was coming next.&lt;/p&gt;

&lt;p&gt;With a nod from Mr Skinny, the other two moved in and started to work me over. I braced myself for the blows, and winced as they rained down on me.&amp;nbsp;Then my world went dark.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;The thing about getting licked by goons is that if you&amp;#39;re lucky enough to wake up, you&amp;#39;ll always be missing grey cells. I was a veteran now. I hoped what I&amp;rsquo;d lost in intelligence was more than made up for by experience. At least that&amp;rsquo;s what I told myself when returning the favour to some gunsel. When you&amp;rsquo;re on a case, you need to defend your thinking, and can&amp;rsquo;t pull punches.&lt;/p&gt;

&lt;p&gt;I dragged my sorry ass to a joint where I knew I&amp;#39;d find a few fellow gumshoes. Donna was there, absent-mindedly &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmastery.com/design-games-card-sorting/&quot;&gt;sorting cards into groups&lt;/a&gt;. Patrick was there too, cradling a rye as he always did. He had a reputation for &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.uxdrinkinggame.com/&quot;&gt;drinking anyone under the table&lt;/a&gt;, especially after a &amp;ldquo;UX fail&amp;rdquo;. He&amp;#39;d made a game of it, they said. But this time I didn&amp;rsquo;t feel like playing.&lt;/p&gt;

&lt;p&gt;I accepted a glass of hooch but waved away their questions. All I wanted was quiet companionship. They got the gist and went back to cards and drinking.&lt;/p&gt;

&lt;p&gt;My body was bruised, but my thinking was as sharp as ever. If Skinny and his goons wanted me out of the way they could have left me alone to just drink myself to death. Why didn&amp;rsquo;t they finish me? They obviously didn&amp;rsquo;t know why I was there.&lt;/p&gt;

&lt;p&gt;After resuming my balance I returned to my office and stared at the post-its stuck between strips of peeling pink wallpaper.&lt;/p&gt;

&lt;p&gt;Outside the snow had turned to rain. Someone somewhere was blowing a horn as mournful as a turkey in December. It went nicely with my mood.&lt;/p&gt;

&lt;p&gt;The post-its were grouped with all the nuggets of info I&amp;rsquo;d collected so far. I had an affinity for mapping out thoughts like this since working with the feds. I added my new findings: the waterfront warehouse address, and the dates from the journal.&lt;/p&gt;

&lt;p&gt;But there wasn&amp;#39;t yet enough to work with&amp;mdash;I couldn&amp;#39;t draw any threads, and I reluctantly realised what I had to do. I preferred to work alone but there was no way this could be solved without getting another set of eyes on the case. And there was only one person who could help, even if she was too close to the furnace.&lt;/p&gt;

&lt;p&gt;I picked up the phone and dialled her number for the first time in years.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;Mary Christmas crossed her legs. She knew they were good.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;I&amp;rsquo;m just not that kind of girl,&quot; she snarled. &amp;ldquo;I played your game once, but now I do things differently. Sorry&amp;mdash;you&amp;rsquo;re on your own.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;I hinted that I knew she was in up to her neck with the impolite crowd.&lt;/p&gt;

&lt;p&gt;&quot;I don&amp;#39;t like to see cheap hoods messing with a sweet kid like you, Princess.&quot;&lt;/p&gt;

&lt;p&gt;She went bright red, and I should have seen the slap coming. I nursed my jaw and just let her fume.&lt;/p&gt;

&lt;p&gt;&quot;Careful, Mac&quot;, she said. &quot;Don&amp;#39;t be a dick.&quot;&lt;/p&gt;

&lt;p&gt;I let the obvious comment slide.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img alt=&quot;A close-up portrait of the enigmatic Mary Christmas&quot; src=&quot;http://uxmas.com/images/uploads/mary-up-close.jpg&quot; style=&quot;width:550px;height:520px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;&quot;That elf died on my doormat, and those goons don&amp;#39;t mess about either.&quot; I reminded her. &quot;I&amp;#39;m just saying ... don&amp;#39;t go there.&quot;&lt;/p&gt;

&lt;p&gt;She knocked back her shot and glared at me. &quot;No&quot; she said, &quot;don&amp;#39;t you go there. If I were you, I&amp;#39;d take the easy option and go back to your two-bit sleazy dive. Forget any of this ever happened!&quot;&lt;/p&gt;

&lt;p&gt;They were the same words as the Dear John letter she&amp;#39;d written me all those years ago. I was obviously still learning.&lt;/p&gt;

&lt;p&gt;We looked at each other sadly over the table. &quot;Lucky I&amp;#39;m not you then,&quot; I said, and this time I was the one to walk out.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;Something woke me to the world of cigarette smoke and last night&amp;#39;s leftover &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/gluten-free-mince-pies&quot;&gt;fruit mince pies&lt;/a&gt;. It was the office phone.&lt;/p&gt;

&lt;p&gt;&quot;Mac here,&quot; I mumbled.&lt;/p&gt;

&lt;p&gt;&quot;Sit this dance out, Mac,&quot; snapped a voice. Not Mr Skinny&amp;mdash;he was older, more sure of himself. A Danish accent?&lt;/p&gt;

&lt;p&gt;I waited for him to continue, but the line went dead.&lt;/p&gt;

&lt;p&gt;Perhaps it was someone working with Skinny? Maybe the higher-ups were starting to show concern.&lt;/p&gt;

&lt;p&gt;The thought gave me a mild sense of satisfaction. But the other side definitely had all the cards&amp;mdash;and all the eyes. Time to get up and work. I pulled the blinds shut and prepared myself a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/mid-uxmas-season-tipple&quot;&gt;Mexican Hot Chocolate&lt;/a&gt;. Taking a long swig, I turned back to the notes on my wall.&lt;/p&gt;

&lt;p&gt;It was going to be a long night.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;&quot;You&amp;#39;re not to work this case any more, Mac. You&amp;#39;re fired!&quot;&lt;/p&gt;

&lt;p&gt;Uncle Xavier was none too happy that I&amp;rsquo;d been doing my own investigation, especially as I wasn&amp;rsquo;t off the suspects list.&lt;/p&gt;

&lt;p&gt;&quot;Maybe you&amp;#39;ve fired me, but I haven&amp;#39;t fired me!&quot;&lt;/p&gt;

&lt;p&gt;The fuzz were on my case, the goons were hitting on me, and Mary was playing hard to get. I had to crack this before someone caught up, or Christmas would be cancelled and I&amp;#39;d be making licence plates.&lt;/p&gt;

&lt;p&gt;I hadn&amp;#39;t started this thing, but it was up to me to finish it.&lt;/p&gt;

&lt;p&gt;Luckily, I had a plan.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;Anyone that knows me will say I&amp;#39;m a sucker for punishment. I keep going back, failing again and again. Most people think I&amp;#39;m nuts, but you actually learn a lot from failing. More than winning the first time, at least. I never had the brains to win first time, but if I made my mind up I could stick to something like superglue. And I always came through in the end.&lt;/p&gt;

&lt;p&gt;My limpet-style antics were about to pay off again. &amp;ldquo;Follow the data,&amp;rdquo; they say. My coffee-stained notebook contained multiple statements from Christmas shoppers stating that new toy store stock always seemed to be available in store on Wednesdays. Tonight was Tuesday.&lt;/p&gt;

&lt;p&gt;The old waterfront warehouse that Santa&amp;rsquo;s Workshop had used before going digital back in the &amp;lsquo;80s was long abandoned. Were they planning to open operations again? That&amp;#39;d explain the elf&amp;#39;s involvement. And if Skinny and his goons managed to squeeze Santa for his trade secrets, they&amp;rsquo;d have a monopoly on Christmas.&lt;/p&gt;

&lt;p&gt;I was battling with barbed wire in the fence when a waft of perfume cut through the stink of grease and bilgewater and rotting fish. I sighed and sat pretty. I knew that smell. Mary strutted around the corner like she owned the place. Which I guess she did&amp;mdash;the three minders she had with her underlined that fact.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;You&amp;rsquo;re getting rusty&amp;rdquo; she said to me, looking at the wire.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;You know me. I like to get stuck into things.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Tangled up in a mess, you mean.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;It&amp;rsquo;d help if you gave me a hand rather than just standing there.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;The worry in my own eyes was reflected in hers.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;You&amp;rsquo;re gonna need this.&amp;rdquo; I handed her the elf&amp;rsquo;s RFID card.&lt;/p&gt;

&lt;p&gt;Peering through a window, we saw a warehouse filled with crates of toys, puddings, holly, tinsel, and Christmas decorations. Either Christmas had been postponed, or these were next year&amp;rsquo;s goods.&lt;/p&gt;

&lt;p&gt;One entire wall was covered with notes and sketches: annotated blueprints, moodboards, experience maps. This was a major project. I recognised some of the sketches from those I&amp;rsquo;d taken out of the elf&amp;rsquo;s pockets.&lt;/p&gt;

&lt;p&gt;I stopped short when I saw the broad back and shoulders of a red-suited old man, sitting in the corner, bound and helpless. He turned to face us. His face said a lot. Those eyes would&amp;rsquo;ve even made a bloodhound sad.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&amp;nbsp;&amp;nbsp; &amp;nbsp;*&lt;/p&gt;

&lt;p&gt;Mary swiped the elf&amp;rsquo;s ID card, and the massive doors of the warehouse rattled open, revealing four figures. I&amp;rsquo;d have bet any money the biggest wore size 12 boots. He dwarfed the three others, especially the skinny runt at the front. I nodded in recognition at the two goons and they nodded back. They both packed Chicago heaters. Things were getting crowded.&lt;/p&gt;

&lt;p&gt;Mr Skinny reached for the bulge inside his coat. He revealed the top corner of a Samsung Galaxy S6.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Don&amp;rsquo;t make me use this.&amp;rdquo; he drawled.&lt;/p&gt;

&lt;p&gt;What was he going to do&amp;mdash;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/digital-transgressions&quot;&gt;SnapChat me to death&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;I made a beeline for Santa, and managed to untie him before the goons stitched a neat burst of holes just in front of our toes. Santa didn&amp;rsquo;t flinch. He shook the ropes free and flew at the gorilla, catching him off guard while he reloaded.&lt;/p&gt;

&lt;p&gt;The two large men rolled across the floor while I fired a Hail Mary at Skinny and his goons to distract them. For an old guy, Santa could give plenty.&lt;/p&gt;

&lt;p&gt;Their fisticuffs interspersed with gunfire in the cavernous warehouse was deafening. Bullets flew like wasps. Mary&amp;#39;s men were solid but I was running low on ammo.&amp;nbsp;I ducked behind a shipping container of Buzz Lightyear figurines, and crouched beside Mary. She pointed across the floor at a row of crates&amp;mdash;one crate in particular looked like a single shove would topple it.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;If you&amp;rsquo;re thinking what I&amp;rsquo;m thinking, you&amp;rsquo;re crazy.&amp;rdquo; I whispered.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;This is nothing compared to ballet school!&amp;rdquo; she chuckled. She made a dash for it and covered&amp;nbsp;the gap in less than a second&amp;mdash;quick enough to reach the opposite side before the goons noticed. I wasn&amp;rsquo;t going to be left huddling there like a sissy, but they were watching me now, and I&amp;rsquo;d have to hightail it. I dug deep and sprinted towards Mary, throwing in a Commando roll for old time&amp;rsquo;s sake. I landed safely beside her, but my hat and coat now had some extra ventilation.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Right as rain.&amp;rdquo; I grinned, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/hooked-on-a-feeling&quot;&gt;feeling more alive than ever&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We leant into the crate and felt it start to set off a domino effect, the smaller crates crashing into ever larger ones. It was a giant, slow-motion tsunami. I couldn&amp;rsquo;t hear it over the chatter of the Tommy guns, but I was surprised the goons couldn&amp;rsquo;t feel each crash. Too late for them now anyway. Fifty tonnes of toy blocks makes a God almighty noise when it lands. It also turns goons into pancakes.&lt;/p&gt;

&lt;p&gt;The dust settled&amp;nbsp;as Xavier&amp;#39;s men arrived, sirens blaring, late to the party&amp;nbsp;as always. At least we&amp;#39;d saved Christmas. Santa&amp;#39;s global delivery&amp;nbsp;project would meet its annual deadline once more.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;You&amp;rsquo;re one helluva mental model, Mary.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;&quot;You old dog,&quot;&amp;nbsp;she grinned.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d certainly &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/old-dog-how-can-you-learn-some-new-tricks&quot;&gt;learnt some new tricks&lt;/a&gt;. Not sure I&amp;rsquo;d be up for putting them to use any time soon, though. This caper had almost done me, and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://uxmas.com/2014/were-living-in-the-fast-web&quot;&gt;I longed for the slow life&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A sprig of mistletoe and holly from the firefight dangled from a girder above us.&lt;/p&gt;

&lt;p&gt;&quot;Tell me you had nothing to do with this,&quot; I pleaded with Mary. &quot;Even if you lie, I&amp;#39;ll believe you.&quot;&lt;/p&gt;

&lt;p&gt;She smiled and we kissed, but I knew it was for the last time.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;strong&gt;&lt;em&gt;The End.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false"></guid>
         <pubDate>Tue, 23 Dec 2014 21:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[24ways] Taglines and Truisms</title>
         <link>http://feedproxy.google.com/~r/24ways/~3/eVYk4olZJWg/</link>
         <description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://stuffandnonsense.co.uk/&quot;&gt;Andrew Clarke&lt;/a&gt; poses the question, that if we&amp;#8217;re all telling prospective clients that we&amp;#8217;re crafting and designing delightful, beautiful and remarkable digital experiences, what marks any of us out?&lt;/p&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=eVYk4olZJWg:ojQnjUq_8Uw:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=eVYk4olZJWg:ojQnjUq_8Uw:7Q72WNTAKBA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=7Q72WNTAKBA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=eVYk4olZJWg:ojQnjUq_8Uw:V_sGLiPBpWU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?i=eVYk4olZJWg:ojQnjUq_8Uw:V_sGLiPBpWU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=eVYk4olZJWg:ojQnjUq_8Uw:dnMXMwOfBR0&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=dnMXMwOfBR0&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/24ways/~4/eVYk4olZJWg&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>feeds@allinthehead.com (Andrew Clarke)</author>
         <guid isPermaLink="false">http://24ways.org/2014/taglines-and-truisms/</guid>
         <pubDate>Tue, 23 Dec 2014 12:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[perl] CLDR TL;DR</title>
         <link>http://perladvent.org/2014/2014-12-23.html</link>
         <description>&lt;div class='pod'&gt;&lt;p&gt;2014 has been an exciting year for CLDR development on the CPAN. But first, what is the CLDR? The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cldr.unicode.org/&quot;&gt;Unicode Common Locale Data Repository&lt;/a&gt; is a standardized repository of locale data along with a specification for its use and implementation. The simplest use case is easy access to translations for use in user interfaces, including month and day names, country and language names, and units of measure such as hours, bytes, meters, and even furlongs. More complex uses include localized ranges of dates using the local calendaring and numbering systems.&lt;/p&gt;

&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.unicode.org/reports/tr35/&quot;&gt;CLDR specification&lt;/a&gt;, however, is increasingly complex and the amount of data is increasingly large. This makes sense because natural languages are complex and each release supports additional minority locales. Fortunately, the CPAN has had more CLDR-based development this year than ever before. This means you don&amp;rsquo;t have to worry about reading complex specifications or manually parsing large XML data structures.&lt;/p&gt;

&lt;h3 id=&quot;What-are-locales&quot;&gt;What are locales?&lt;/h3&gt;

&lt;p&gt;There are two parts to a locale: an identifier and data. The identifier is used to specify user preferences, generally based on languages and regions. The simplest locale is a language code alone, such as &lt;b&gt;es&lt;/b&gt; for Spanish and &lt;b&gt;zh&lt;/b&gt; for Chinese. Including the user&amp;rsquo;s country in the locale can provide additional valuable information. For example there are many differences in displaying dates and even numbers between European Spanish (&lt;b&gt;es-ES&lt;/b&gt;) and Mexican Spanish (&lt;b&gt;es-MX&lt;/b&gt;). Much additional information can be explicitly included in the locale, but most of the time it&amp;rsquo;s implicitly derived from the language and region. For example, many locales default to the Gregorian calendar while some to the Buddhist calendar or others; &lt;b&gt;zh-CN&lt;/b&gt; defaults to Simplified Han script while &lt;b&gt;zh-TW&lt;/b&gt; defaults to Traditional Han. However, if you want to get really explicit, you could say &lt;b&gt;tlh-Hira-AQ-u-ca-julian-nu-roman&lt;/b&gt; for Klingon in the Hiragana script as used in Antarctica with the Julian calendar and Roman numerals.&lt;/p&gt;

&lt;p&gt;Whenever possible, include the user&amp;rsquo;s language and country when constructing a locale identifier in order to provide the most localized experience.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s take a tour of some simple solutions to common localization problems using CPAN modules.&lt;/p&gt;

&lt;h3 id=&quot;CLDR::Number&quot;&gt;CLDR::Number&lt;/h3&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/CLDR::Number&quot;&gt;CLDR::Number&lt;/a&gt; is a new module that become stable early this year and provides localized formatting of numbers, prices, and even percents and ranges of numbers. Full disclosure: I wrote this module and it powers Shutterstock in 20 languages, 150+ countries, and many currencies.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example of formatting numbers:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;CLDR::Number&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;CLDR::Number&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$locale&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$decf&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;decimal_formatter&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;word&quot;&gt;say&lt;/span&gt; &lt;span class=&quot;double&quot;&gt;&amp;quot;$locale: &amp;quot;&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$decf&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;float&quot;&gt;123456.7&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now let&amp;rsquo;s see the results in European Spanish, Mexican Spanish, and Bengali:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;es-ES: 123 456,7&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;es-MX: 123,456.7&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;bn-IN: &amp;#x9E7;,&amp;#x9E8;&amp;#x9E9;,&amp;#x9EA;&amp;#x9EB;&amp;#x9EC;.&amp;#x9ED;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This demonstrates that both the language and the country can significantly change the results of basic number formatting. Now let&amp;rsquo;s see this applied to prices in different currencies.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$curf&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;currency_formatter&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;currency_code&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$currency&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;word&quot;&gt;say&lt;/span&gt; &lt;span class=&quot;double&quot;&gt;&amp;quot;$locale / $currency: &amp;quot;&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$curf&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;float&quot;&gt;9.99&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Here are the results in American English and Canadian English for both US Dollars and Canadian Dollars.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;en-US / USD: $9.99&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;en-CA / USD: US$9.99&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;en-CA / CAD: $9.99&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;en-US / CAD: CA$9.99&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This demonstrates that localized formatting is important even when your only supported language is English. When it comes to currency formatting, the language, country, and currency each can significantly change the results.&lt;/p&gt;

&lt;h3 id=&quot;Locale::CLDR&quot;&gt;Locale::CLDR&lt;/h3&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Locale::CLDR&quot;&gt;Locale::CLDR&lt;/a&gt; is another new module released earlier this year by John Imrie, with the goal of providing access to all of the CLDR via locale objects&amp;mdash;an impressive task!&lt;/p&gt;

&lt;p&gt;Different locales use different punctuation and this is commonly ignored even in applications with translations in many languages. Fortunately, Locale::CLDR makes this aspect of localization easy.&lt;/p&gt;

&lt;p&gt;Here is a simple solution to formatting a list of strings for the user:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Locale::CLDR&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Locale::CLDR&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$locale&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@gifts&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;words&quot;&gt;qw( foo bar baz )&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;word&quot;&gt;say&lt;/span&gt; &lt;span class=&quot;double&quot;&gt;&amp;quot;$locale: &amp;quot;&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cldr&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;magic&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@gifts&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The &lt;code&gt;quote&lt;/code&gt; method is used to quote each element and the &lt;code&gt;list&lt;/code&gt; method is used to format the entire list. Let&amp;rsquo;s take a look at the results in Portuguese, French, and Urdu.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;pt: &amp;ldquo;foo&amp;rdquo;, &amp;ldquo;bar&amp;rdquo; e &amp;ldquo;baz&amp;rdquo;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fr: &amp;laquo;foo&amp;raquo;, &amp;laquo;bar&amp;raquo; et &amp;laquo;baz&amp;raquo;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ur: &amp;rdquo;foo&amp;ldquo;&amp;#x60C; &amp;rdquo;bar&amp;ldquo;&amp;#x60C; &amp;#x627;&amp;#x648;&amp;#x631; &amp;rdquo;baz&amp;ldquo;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that for support of all locales, you currently have to use the Locale::CLDR v0.25.x release on CPAN instead of v0.26.x because the latter is in the process of being broken into locale bundles and that work is ongoing.&lt;/p&gt;

&lt;h3 id=&quot;New-year-new-development&quot;&gt;New year, new development&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;ve had a great year for Perl localization and I hope 2015 will be even better. Once the most important &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/CLDR::Number::TODO&quot;&gt;CLDR::Number::TODO&lt;/a&gt; tasks are completed, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/DateTime::Locale&quot;&gt;DateTime::Locale&lt;/a&gt; will receive some much needed love. The top gift on my wishlist is a Perl wrapper for &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://site.icu-project.org/&quot;&gt;ICU4C&lt;/a&gt; (International Components for Unicode), which is a mature project providing full CLDR support. I&amp;rsquo;m confident that if I continue to fill my uncle&amp;rsquo;s boots with coleslaw on Yaksmas Eve, the Gilded Yak may finally deliver.&lt;/p&gt;

&lt;h2 id=&quot;See-Also&quot;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Locales&quot;&gt;Locales&lt;/a&gt; provides much of the basic CLDR data, such as names of countries and languages.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/DateTime&quot;&gt;DateTime&lt;/a&gt; provides CLDR-based formatting using &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/DateTime::Locale&quot;&gt;DateTime::Locale&lt;/a&gt;.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Geo::Region&quot;&gt;Geo::Region&lt;/a&gt; provides UN M.49 and CLDR geographical region and grouping data.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</description>
         <author>Nova Patch</author>
         <guid isPermaLink="false">http://perladvent.org/2014/2014-12-23.html</guid>
         <pubDate>Tue, 23 Dec 2014 05:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[java] The Java Ecosystem - My top 5 highlights of 2014</title>
         <link>http://feedproxy.google.com/~r/JavaAdventCalendar/~3/Ux6HFTOQIoY/the-java-ecosystem-my-top-5-highlights.html</link>
         <description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align:left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;1. February the 1st - RedMonk Analyst firm declares that Java is more popular &amp; diverse than ever!&lt;/h3&gt; &lt;p&gt;The Java Ecosystem started off with a hiss and a roar in 2014 with the annual meeting of the Free Java room at FOSDEM. As well as the many fine deep technical talks on OpenJDK and related topics there was also a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.slideshare.net/sogrady/what-a-long-strange-trip-its-been&quot;&gt;surprise presentation&lt;/a&gt; on the industry from  Steve O'Grady (RedMonk Analyst). Steve gave a data lead insight into where Java ranked in terms of both popularity and scope at the start of 2014. The analysis on where Java is as a language is repeated &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://redmonk.com/sogrady/2014/01/22/language-rankings-1-14/&quot;&gt; on RedMonk's Blog&lt;/a&gt;. The fact it remains a top two language didn't surprise anyone, but it was the other angle that really surprised even those of us heavily involved in the ecosystem. Steve's talk clearly showed that Java is aggressively diverse, appearing in industries such as social media, messaging, gaming, mobile, virtualisation, build systems and many more, not just Enterprise apps that people most commonly think about. Steve also showed that Java is being used heavily in new projects (across all of those industry sectors) which certainly killed the myth of Java being a legacy enterprise platform.&lt;/p&gt; &lt;h3&gt;2. March the 18th - Java 8 arrives&lt;/h3&gt; &lt;p&gt;The arrival of Java 8 ushered in a new Functional/OO hybrid direction for the language giving it a new lease of life.  The adoption rates have been incredible (See &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://info.typesafe.com/COLL-2014-10-20-Java-8-II-Survey-Report-LP.html?lsd=COLL-2014-10-20-Java-8-II-Survey-Report&amp;lst=RW&quot;&gt;Typesafe's full report&lt;/a&gt; on this) it was clearly the release that Java developers were waiting for. &lt;/p&gt; &lt;p&gt;Some extra thoughts around the highlights of this release: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Lambdas&lt;/strong&gt; (JSR 335) - There has been so much written about this topic already with a ton of fantastic books and tutorials to boot. For me the clear benefit to most Java developers was that they're finally able to express the correct intent of behaviour with collections without all of the unnecessary boiler plate that imperative/OO constructs forced upon them.  It boils down to the old adage of &lt;i&gt;That there are only two problems in computer science, cache invalidation, naming things, and off-by-one errors.&lt;/i&gt;  The new streams API for collection in conjunction with Lambdas certainly helps with the last two!&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Project Nashorn&lt;/strong&gt; (JSR 223, JEP 174) - The JavaScript runtime which allows developers to embed JavaScript code within their Java applications. Although I personally won't be using this anytime soon, it was yet another boost to the JVM in terms of first class support for dynamically typed languages. I'm looking forward to this trend continuing!&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Date and Time API&lt;/strong&gt; (JSR 310, JEP 150) - This is sort of bread and butter API that a blue collar language like Java just needs to get right, and this time (take 3) they did! It's been great to finally be able to work with timezones correctly and it also set a new precedence of &lt;i&gt;Immutable First&lt;/i&gt; as a conscious design decision for new APIs in Java.&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;3. ~July - ARM 64 port (AArch64)&lt;/h3&gt; &lt;p&gt;RedHat have lead the effort to get the ARMv8 64-bit architecture supported in Java. This is clearly an important step to keep Java truly &quot;Run anywhere&quot; and alongside SAP's &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://openjdk.java.net/projects/ppc-aix-port/&quot;&gt;PowerPC/AIX port&lt;/a&gt; represents two major ports that are primarily maintained by non-Oracle participants in OpenJDK. If you'd like to help get involved see the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://openjdk.java.net/projects/aarch64-port/&quot;&gt;project page&lt;/a&gt; for more details. &lt;/p&gt; &lt;p&gt;Java still has a way to go before becoming a major player in the embedded space, but the signs in 2014 were encouraging with Java SE Embedded featuring regularly on the Raspberry Pi and Java ME Embedded getting a much needed feature parity boost with Java SE APIs. &lt;/p&gt; &lt;h3&gt;4. Sept/Oct - A Resurgence in the JCP &amp; it's 15th Anniversary&lt;/h3&gt; &lt;p&gt;The Java Community Process (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.jcp.org/en/home/index&quot;&gt;JCP&lt;/a&gt;) is the standards body that defines what goes into Java SE, Java EE and the Java ME. It re-invented itself as a much more open community based organisation in 2013 and continued that good work in 2014, reversing the dropping membership trend.  Most importantly - it now truly represents the incredible diversity that the Java ecosystem has.  You can see the make up of the existing &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://www.jcp.org/en/participation/committee&quot;&gt;Executive Committee&lt;/a&gt; - you can see that institutions like Java User Groups sitting alongside industry and end user heavyweights such as IBM, Twitter and Goldman Sachs. &lt;/p&gt; &lt;h3&gt;Community Collaboration at an all time high &amp; Microsoft joins OpenJDK.&lt;/h3&gt; &lt;p&gt;The number of new joiners to OpenJDK (see &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.javaadvent.com/2014/12/how-is-java-jvm-built-adopt-openjdk-is.html&quot;&gt;Mani's excellent post&lt;/a&gt; on this) was higher than ever.  OpenJDK now represents a huge melting pot of major tech companies such as Red Hat, IBM, Oracle, Twitter and of course the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.reddit.com/tb/2hewc7&quot;&gt;shock entry&lt;/a&gt; this year of Microsoft.  &lt;/p&gt; &lt;p&gt;The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://adoptajsr.java.net&quot;&gt;Adopt a JSR&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://adoptopenjdkjava.net&quot;&gt;Adopt OpenJDK&lt;/a&gt; programmes continue to bring more day to day developers involved in guiding the future of various APIs with regular workshops now being organised globally around the world to test new APis and ideas out early and feed that back in OpenJDK and the Java EE specifications in particular. &lt;/p&gt; &lt;p&gt;Community conferences &amp; the number of Java User Groups continue rise in numbers, JavaOne in particular having it's strongest year in recent memory. It was also heartening to see a large number of community efforts helping kids learn to code with after school and weekend programmes such as &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.devoxx4kids.org/&quot;&gt;Devoxx for Kids&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;What for 2015?&lt;/h3&gt; I'll expect 2015 to be a little bit quieter in terms of changes for the core language or exciting new features to Java EE or Java ME as their next major releases aren't due to 2016. On the community etc front I expect to see Java developers having to firmly embrace web/UI technologies such as AngularJS, More systems/Devops toolchains such as Docker, AWS, Puppet etc and of course migrate to Java 8 and all of the functional goodness it now brings!  The community I'm sure will continue to thrive and the looming spectre of IoT will start to come into the mainstream as well. Java developers will likely have to wait until Java 9 to get a truly first class platform for embedded, but early adopters will want to begin taking a look at early builds throughout 2015.  Java/JVM applications now tend to be complex, with many moving parts and distributed deployments.  It can often take poor frustrated developers weeks to fix issues in production. To combat this there are a new wave of interesting analysis tools dealing with Java/JVM based applications and deployments. Oracle's &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.oracle.com/technetwork/java/javaseproducts/mission-control/java-mission-control-1998576.html&quot;&gt;Mission Control&lt;/a&gt; is a powerful tool that can give lots of interesting insights into the JVM and other tools like &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://zeroturnaround.com/software/xrebe/&quot;&gt;Xrebel&lt;/a&gt; from ZeroTurnaround, jClarity's &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jclarity.com/censum&quot;&gt;Censum&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jclarity.com/illuminate&quot;&gt;Illuminate&lt;/a&gt; take the next step of applying machine learned analysis to the raw numbers.  One final important note.  Project Jigsaw is the modularisation story for Java 9 that will massively impact tool vendors and day to day developers alike. The community at large needs your help to help test out early builds of Java 9 and to help OpenJDK developers and tool vendors ensure that IDEs, build tools and applications are ready for this important change.  You can join us in the Adoption Group at OpenJDK:  http://adoptopenjdk.java.net  I hope everyone has a great holiday break - I look forward to seeing the Twitter feeds and the GitHub commits flying around in 2015 :-).  &lt;br/&gt;Cheers,&lt;br/&gt;Martijn (CEO - &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jclarity.com&quot;&gt;jClarity&lt;/a&gt;, Java Champion &amp; Diabolical Developer) &lt;br/&gt;&lt;br/&gt;&lt;em style=&quot;background-color:#fcffee;color:#222222;font-family:Verdana, Geneva, sans-serif;font-size:18px;line-height:24.6399993896484px;&quot;&gt;This post is part of the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://javaadvent.com/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Java Advent Calendar&lt;/a&gt;&amp;nbsp;and is licensed under the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://creativecommons.org/licenses/by/3.0/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Creative Commons 3.0 Attribution&lt;/a&gt;&amp;nbsp;license. If you like it, please spread the word by sharing, tweeting, FB, G+ and so on!&lt;/em&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=Ux6HFTOQIoY:_SiN42moKys:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=Ux6HFTOQIoY:_SiN42moKys:4cEx4HpKnUU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?i=Ux6HFTOQIoY:_SiN42moKys:4cEx4HpKnUU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=Ux6HFTOQIoY:_SiN42moKys:YwkR-u9nhCs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=YwkR-u9nhCs&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=Ux6HFTOQIoY:_SiN42moKys:qj6IDK7rITs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=qj6IDK7rITs&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/JavaAdventCalendar/~4/Ux6HFTOQIoY&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Martijn Verburg</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-2481158163384033132.post-5307468721553846522</guid>
         <pubDate>Tue, 23 Dec 2014 00:15:00 +0000</pubDate>
      </item>
      <item>
         <title>[sysadvent] Day 23 - The Importance of Pluralism, or The Danger of the Letter &quot;S&quot;</title>
         <link>http://feedproxy.google.com/~r/sysadvent/~3/3eSSTwhfVOE/day-23-importance-of-pluralism-or.html</link>
         <description>&lt;p&gt;Written by: Mike Fiedler (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/mikefiedler&quot;&gt;@mikefiedler&lt;/a&gt;)&lt;br&gt;
Edited by: Hugh Brown (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/saintaardvark&quot;&gt;@saintaardvark&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;Prologue: A Concept&lt;/h3&gt;

&lt;p&gt;One aspect of Chef that&amp;#8217;s confusing to people comes up when searching for nodes that have
some attribute: just what is the difference between a nodes reported &amp;#8216;role&amp;#8217; attribute,
and its &amp;#8216;roles&amp;#8217; attribute? It seems like it could almost be taken for a typo &amp;#8211; but underlying it
are some very deep statements about pluralism, pluralization, and the differences between them.&lt;/p&gt;

&lt;p&gt;One definition of the term &amp;#8216;pluralism&amp;#8217; is &amp;#8220;a condition or system in which two or more states, groups, principles,
sources of authority, etc., coexist.&amp;#8221;
And while pluralism is common in descriptions of politics, religion and culture,
it also has a place in computing: to describe situations in which many systems
are in more than one &lt;em&gt;desired&lt;/em&gt; state.&lt;/p&gt;

&lt;p&gt;Once a desired state is determined, it&amp;#8217;s enforced. But then time passes &amp;#8211; days,
minutes, seconds or even nanoseconds &amp;#8211; and every moment has the potential to
change the server&amp;#8217;s &lt;em&gt;actual&lt;/em&gt; state.
Files are edited, hardware degrades, new data is pulled from external sources;
anyone who has run a production service can attest to this.&lt;/p&gt;

&lt;h3&gt;Act I: Terms&lt;/h3&gt;

&lt;p&gt;Businesses commonly offer products. These products may be composed of multiple systems, where each system
could be a collection of services, which run on any number of servers, which run on some amount of hosts.
Each host, in turn, provides another set of services to the server that makes up part of the system, which then
makes up part of the product, which the business sells.&lt;/p&gt;

&lt;p&gt;An example to illustrate: MyFace offers a social web site (the product), which may need a web portal,
a user authentication system, index and search systems, long-term photo storage systems, and many more.
The web portal system may need servers like Apache or Nginx, running on any number of instances.
A given server-instance will need to use any number of host services, such as /o, cpu, memory and more.&lt;/p&gt;

&lt;p&gt;So what we loosely have is: products =&amp;gt; systems =&amp;gt; services =&amp;gt; servers =&amp;gt; hosts =&amp;gt; services. (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Turtles_all_the_way_down&quot;&gt;Turtles, turtles, turtles.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In Days of Yore, when a Company ran a &amp;#8216;Web Site&amp;#8217;, they may have had a single System, maybe some web content Service,
made up of a web Server, a database Server (maybe even on the same host) - both consuming host services
(CPU, Memory, Disk, Network) - to provide the Service the Company then sells, hopefully at a profit (right!?).&lt;/p&gt;

&lt;p&gt;Back then, if you wanted to enact a change on the web and database at the same time (maybe release a new feature),
it was relatively simple, as you could control both things in one place, at roughly the same time.&lt;/p&gt;

&lt;h3&gt;Intermission&lt;/h3&gt;

&lt;p&gt;In English, to pluralize something, we generally add a suffix of &amp;#8220;s&amp;#8221; to the word.
For instance, to convey more than one instance, &amp;#8220;instance&amp;#8221; becomes &amp;#8220;instances&amp;#8221;, &amp;#8220;server&amp;#8221; becomes &amp;#8220;servers&amp;#8221;,
&amp;#8220;system&amp;#8221; becomes &amp;#8220;systems&amp;#8221;, &amp;#8220;turtle&amp;#8221; becomes &amp;#8220;turtles&amp;#8221;.&lt;/p&gt;

&lt;p&gt;We commonly use pluralization to describe the concept of a collection of similar items, like &amp;#8220;apples&amp;#8221;, &amp;#8220;oranges&amp;#8221;,
&amp;#8220;users&amp;#8221;, &amp;#8220;web pages&amp;#8221;, &amp;#8220;databases&amp;#8221;, &amp;#8220;servers&amp;#8221;, &amp;#8220;hosts&amp;#8221;, &amp;#8220;turtles&amp;#8221;. I think you see the pattern.&lt;/p&gt;

&lt;p&gt;This extends even in to programming languages and idiomatic use in development frameworks.
For example, all tables in a Rails application will typically pluralize a table name for objects named &lt;code&gt;Apple&lt;/code&gt; to &lt;code&gt;apples&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This emphasizes that the table in question does not store a singular &lt;code&gt;Apple&lt;/code&gt;, rather many
&lt;code&gt;Apple&lt;/code&gt; instances will be located in a table named &lt;code&gt;apples&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is not pluralism, this is pluralization - don&amp;#8217;t get them confused. Let&amp;#8217;s move on to the next act.&lt;/p&gt;

&lt;h3&gt;Act II: Progress&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;ve evolved quite a bit since the Days of Yore. Now, a given business product
can span hundreds or even thousands of systems of servers running on hosts all over the world.&lt;/p&gt;

&lt;p&gt;As systems grow, it becomes more difficult to enact a desired change at a deterministic point in time across
a fleet of servers and hosts.&lt;/p&gt;

&lt;p&gt;In the realm of systems deployment, many solutions perform what has become known as &amp;#8220;test-and-repair&amp;#8221; operations -
meaning that when provided a &amp;#8220;map&amp;#8221; desired state (which typically manifests in human-written and readable code), that
when executed, will &amp;#8220;test the current state of a given host, and perform and &amp;#8221;repair&amp;quot; operations to bring the host
to the desired state - whether it be installing packages, writing files&lt;/p&gt;

&lt;p&gt;Each system calls this map something different - cfengine:policies, bcfg2:specifications, puppet:modules, chef:recipes,
ansible:playbooks, and so on.
While they don&amp;#8217;t always map 1:1, they all have &lt;em&gt;some&lt;/em&gt; sort of concept for &amp;#8216;Things that are similar, but not the same.&amp;#8217;
They will have unique IP addresses, hostnames, while sharing enough of a set of common features to become termed something
like &amp;#8220;web heads&amp;#8221; or the like.&lt;/p&gt;

&lt;h3&gt;Act III: Change&lt;/h3&gt;

&lt;p&gt;In the previous sections, I laid the groundwork to understand one of the more subtle features in Chef.
This feature may be available in other services, but I&amp;#8217;ll describe the one I know.&lt;/p&gt;

&lt;p&gt;Using Chef, there is a common deployment model where Chef Clients check in with a Chef Server to ask
&amp;#8220;What is the desired state I should have?&amp;#8221; The Chef terminology is &amp;#8216;a node asks the server for its run list&amp;#8217;.&lt;/p&gt;

&lt;p&gt;A run list can contain a list of recipes and/or roles. A recipe tells Chef how to accomplish
a particular set of tasks, like installing a package or editing a file.
A role is typically a collection of recipes, and maybe some role-specific metadata (&amp;#8216;attributes&amp;#8217; in Chef lingo).&lt;/p&gt;

&lt;p&gt;The node may be in any state at this point. Chef will test for each desired state, and take action to enforce
it: install this package, write that file, etc.
The end result should either be &amp;#8220;this node now conforms to the desired state&amp;#8221; or &amp;#8220;this node was unable to comply&amp;#8221;.&lt;/p&gt;

&lt;p&gt;When the node completes successfully, it will report back to Chef Server that &amp;#8220;I am node &amp;#8216;XYZZY&amp;#8217;,
and my roles are &amp;#8216;base&amp;#8217; and &amp;#8216;webhead&amp;#8217;, my recipes are &amp;#8216;base::packages&amp;#8217;, &amp;#8216;nginx&amp;#8217;, &amp;#8216;webapp&amp;#8217;&amp;#8221; along with a lot of node-specific metdata (IP addresses, CPU, Memory, Disk, and much more).&lt;/p&gt;

&lt;p&gt;This information is then indexed and available for others to search for.
A common use case we have is where a load balancing node will perform a search for all nodes holding the &lt;code&gt;webhead&lt;/code&gt; role, and add these to the balancing list.&lt;/p&gt;

&lt;h4&gt;Pièce de résistance, or Searching for Servers&lt;/h4&gt;

&lt;p&gt;In a world where we continue to scale and deploy systems rapidly and repeatedly, we often choose to reduce
the need for strong consistency amongst a cluster of hosts.
This means we cannot expect to change all hosts at the precise same moment.
Rather we opt for &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Eventual_consistency&quot;&gt;eventual consistency&lt;/a&gt;: either all my nodes
will eventually be correct, or failures will occur and I&amp;#8217;ll be notified that something is wrong.&lt;/p&gt;

&lt;p&gt;This changes how we think about deployments, and more importantly, how do we use our tools to find other nodes.&lt;/p&gt;

&lt;p&gt;Using Chef&amp;#8217;s search feature, a search like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;webheads = search(:node, 'role:webheads')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;will use the &lt;code&gt;node&lt;/code&gt; index (a collection of node data) to look for nodes with the &lt;code&gt;webheads&lt;/code&gt; role in the node&amp;#8217;s
&lt;strong&gt;run list&lt;/strong&gt; - this will also return nodes that have not yet completed an initial Chef run and reported the complete
&lt;code&gt;run list&lt;/code&gt; back to Chef Server.&lt;/p&gt;

&lt;p&gt;This means that my load balancer could find a node that is still mid-provisioning, and potentially begin
to send traffic to a node that&amp;#8217;s not ready to receive yet, based on the &lt;code&gt;role&lt;/code&gt; assignment alone.&lt;/p&gt;

&lt;p&gt;A better search, in this case might be:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;webheads = search(:node, 'roles:webheads')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One letter, and &lt;em&gt;all&lt;/em&gt; the difference.&lt;/p&gt;

&lt;p&gt;This search now looks for an &amp;#8220;expanded list&amp;#8221; that the node has reported back.
Any node with the role &lt;code&gt;webheads&lt;/code&gt; that has completed a Chef run would be included.
If the mandate is that only &lt;code&gt;webhead&lt;/code&gt; nodes get the &lt;code&gt;webhead&lt;/code&gt; role assigned to them, then I can safely use this search to include nodes that have &lt;strong&gt;completed their provisioning cycle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another way to use this search to our benefit is to search one axis and compare with another to find nodes that never completed provisioning:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;badnodes = search(:node, 'role:webheads AND NOT roles:webheads')
# Or, with knife command line:
$ knife search node 'role:webheads AND NOT roles:webheads'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will grab any nodes with an assignment but not a completion &amp;#8211; very helpful when launching large amounts of nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is not restricted to roles; this also applies to &lt;code&gt;recipe/recipes&lt;/code&gt;. I&amp;#8217;ve used roles here,
as we use them heavily in our organization, but the same search patterns apply for using recipes directly
in a run list.&lt;/p&gt;

&lt;h3&gt;Curtain&lt;/h3&gt;

&lt;p&gt;This little tidbit of &lt;code&gt;role&lt;/code&gt; vs &lt;code&gt;roles&lt;/code&gt; has proven time and again to be a confusing point when someone tries to pick up more of Chef&amp;#8217;s searching abilities.
But having &lt;strong&gt;both&lt;/strong&gt; adjectives describe a state of the node is helpful in making a determination
of what state the node is in, and whether it should be included in some other node&amp;#8217;s list (such as in the
loadbalancer/webhead example from before).&lt;/p&gt;

&lt;p&gt;Now, you may argue against the use of roles entirely, or the use of Chef Server and search, and use something else for service discovery.
This is a valid argument - but be careful you&amp;#8217;re not tethering a racehorse to a city
carriage.
If you don&amp;#8217;t fully understand its abilities, someday it might run away on you.&lt;/p&gt;

&lt;h3&gt;Epilogue&lt;/h3&gt;

&lt;p&gt;A surgeon spends a lot of time how to use a sharpened bit of metal to fix the human body.
While there are many instruments he or she will go on to master, the scalpel remains the fundamental tool, available when all else is gone.&lt;/p&gt;

&lt;p&gt;While we don&amp;#8217;t have the same risks involved as a surgeon, the tools we use can be more complex, and provide us
with a large amount of power at our fingertips.&lt;/p&gt;

&lt;p&gt;It behooves us to learn how they work, and when and how to use its features to provide better systems and services for our businesses.&lt;/p&gt;

&lt;p&gt;Chef&amp;#8217;s ability to discern between what a node has been &lt;em&gt;told&lt;/em&gt; about itself, and what it &lt;em&gt;reports&lt;/em&gt; about itself, can make all the difference when using Chef to accomplish complex deployment scenarios and maintain flexible infrastructure as code.
This not only lets you accomplish fundamentals of service discovery and less hard-coded configurations, but lets you avoid the uncertainty of bringing in yet another
outside tool.&lt;/p&gt;

&lt;p&gt;On that note, Happy Holiday(s)!&lt;/p&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/sysadvent/~4/3eSSTwhfVOE&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Christopher Webber</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-3615332969083650973.post-5996547621296317135</guid>
         <pubDate>Tue, 23 Dec 2014 00:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[ux] Designing For the Slow Web</title>
         <link>http://uxmas.com/2014/were-living-in-the-fast-web</link>
         <description>&lt;p&gt;Let&amp;rsquo;s face it. Our obsession with the internet has gotten out of hand.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re spending more time online than ever before. Every spare moment is spent in front of a screen&amp;mdash;whether it&amp;rsquo;s checking our email in bed, Facebook on the train or Twitter in the toilet (come on, admit it). And the explosion in mobile this decade means that we are always online, to some degree.&lt;/p&gt;

&lt;p&gt;On top of that, we are constantly bombarded with notifications&amp;mdash;likes, retweets,&amp;nbsp;favourites, friend requests, alerts.&amp;nbsp;And &amp;#39;shiny-new-object syndrome&amp;rsquo; is always drawing us towards the newest gadget or app.&lt;/p&gt;

&lt;p&gt;On average:&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;An adult will spend over 5 hours per day online&lt;/li&gt;
	&lt;li&gt;Workers send and receive 40 email per day, and an estimated 20 notifications&lt;/li&gt;
	&lt;li&gt;People visit over 10 websites per day&lt;/li&gt;
	&lt;li&gt;A smartphone user will picks up their phone more than 1,500 times in any week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stream of information flows like a sip from a firehouse&amp;nbsp;and we can&amp;rsquo;t stop it.&amp;nbsp;Even if we wanted to. And it&amp;rsquo;s getting us nowhere.&lt;/p&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://jackcheng.com/the-slow-web&quot;&gt;Jack Cheng&lt;/a&gt; calls this the era of the &amp;lsquo;Fast Web&amp;rsquo;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the Fast Web? It&amp;rsquo;s the out of control web. The &quot;oh my god there&amp;rsquo;s so much stuff,&amp;nbsp;I can&amp;rsquo;t possibly keep up&quot; web. It&amp;rsquo;s the &quot;spend two dozen times a day checking&quot; web. The &quot;in one end and out the other&quot; web. The web designed to appeal to the basest of our intellectual palettes, the salt, sugar and fat of online content web. It&amp;rsquo;s the scale hard and fast web. The &quot;create a destination for billions of people&quot; web. The you have two hundred twenty six new updates web. Keep up or be lost. Click me. Like me. Tweet me. Share me. The Fast Web demands that you do things and do them &lt;strong&gt;now&lt;/strong&gt;. The Fast Web is a cruel wonderland of shiny shiny things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And you know what? Things are going to get worse before they get better.&amp;nbsp;The advances in new technologies around home automation will only add to the noise.&amp;nbsp;Soon your alarm clock will be talking to your coffee machine, and you&amp;rsquo;ll get a notification about it. And wearable&amp;nbsp;technology means we&amp;rsquo;ll never be completely off the grid.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s not just us, it&amp;rsquo;s our children too. Leading&amp;nbsp;paediatricians suggest that kids should spend no more than 2 hours per day in front of a screen. Yet, they too are obsessed. The task of keeping a child away from an ipad is&amp;nbsp;sisyphean.&lt;/p&gt;

&lt;p&gt;&amp;#39;Internet addiction disorder&amp;rsquo; is now recognised as a legitimate clinical disorder,&amp;nbsp;with its own wikipedia page. And&amp;nbsp;don&amp;rsquo;t get me started with &amp;#39;Phantom vibration syndrome&amp;rsquo;.&lt;/p&gt;

&lt;p&gt;It can&amp;rsquo;t go on like this. The fast web is killing us.&lt;/p&gt;

&lt;p&gt;The first step to recovery is admitting we&amp;nbsp;have a problem. But what&amp;rsquo;s the solution?&lt;/p&gt;

&lt;h1&gt;The slow web: the antidote to our fast-web woes.&lt;/h1&gt;

&lt;p&gt;Imagine a web that wasn&amp;rsquo;t so rushed. A web that empowered us to consume it in a more leisurely fashion. A web that felt more like a farmers market than a hyper market.&amp;nbsp;Perhaps even a web that encouraged you to disconnect from time to time.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ve heard of slow food, but have you heard about the slow web movement?&lt;/p&gt;

&lt;p&gt;Again, I&amp;rsquo;ll allow Jack to explain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The Slow Web Movement is a lot like the Slow Food Movement, in that they&amp;rsquo;re both blanket terms that mean a lot of different things. Slow Food began in part as a reaction to the opening of a McDonald&amp;rsquo;s in Piazza di Spagna in Rome, so from its very origin, it was defined by what it&amp;rsquo;s not. It&amp;rsquo;s not Fast Food, and we all know what Fast Food is&amp;hellip; right?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We spend way too much time&amp;nbsp;eating fast-food online. Facebook&amp;nbsp;is the cheeseburger of the web. Twitter is the chicken nugget.&amp;nbsp;We need to cut down on quarter-pounders, and we need to spend less time the fast-web too.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;I think 2015 will be the year of the slow web. And together we can help build it.&lt;/p&gt;

&lt;h1&gt;Designing for a slower web&lt;/h1&gt;

&lt;p&gt;As designers, we&amp;rsquo;ll never win over our users if we&amp;rsquo;re constantly hassling them with more notifications and email updates.&lt;/p&gt;

&lt;p&gt;The slow web is the opposite. It&amp;rsquo;s about getting out of our user&amp;rsquo;s way.&amp;nbsp;It&amp;rsquo;s about reducing the noise, not adding to it. It&amp;rsquo;s about providing real quality, not quantity. It&amp;rsquo;s about turning down the volume, and letting our users enjoy the quiet.&lt;/p&gt;

&lt;p&gt;So how might we design for the slow web?&amp;nbsp;By showing you some examples below, I hope provide some ideas into how we can do it.&lt;/p&gt;

&lt;h1&gt;Do less, but better&lt;/h1&gt;

&lt;p&gt;As designers and product people, we&amp;rsquo;re under constant pressure to give more. More content, more features. More updates.&lt;/p&gt;

&lt;p&gt;We need to get off this hamster wheel and&amp;nbsp;aim to give our users more by giving them less. Focusing on producing more quality, not more quantity.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/medium_screen.png&quot; style=&quot;width:550px;height:503px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;Probably one of the early winners of the slow web movement is Medium. It&amp;rsquo;s the writing platform that that has made long-form reading popular again. Medium&amp;nbsp;has developed a community of quality writing and imagery from its contributors. It feels more like&amp;nbsp;blogging for the slow web.&lt;/p&gt;

&lt;p&gt;Designing for a slower web is also about making things simpler and intuitive without&amp;nbsp;draining our cognitive resources. Let&amp;rsquo;s think about reducing features, and delivering fewer, but better, updates so that we can get out of our users&amp;rsquo; way sooner.&lt;/p&gt;

&lt;h1&gt;Hold back on notifications&lt;/h1&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/notifications.png&quot; style=&quot;width:310px;height:550px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;Here are two notifications I&amp;nbsp;received today. The first one was from Fire Ready app, alerting me of a fire near my home. An important message that I&amp;rsquo;m interested in&amp;nbsp;knowing about&amp;nbsp;and that I opted-in to.&amp;nbsp;The second was an irrelevant message from Shazaam that I never signed up for.&lt;/p&gt;

&lt;p&gt;Guess which one pissed me off the most?&lt;/p&gt;

&lt;p&gt;In a quest to get users to to form long-lasting habits with our products, we&amp;rsquo;re bombarding our user base with shit and dribble. The &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://developer.android.com/design/patterns/notifications.html&quot;&gt;Android design guide&lt;/a&gt; puts it more politely:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Unwanted or unimportant notifications can annoy the user or make them resent how much attention the app wants from them, so use notifications judiciously.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next year, let&amp;rsquo;s be more strategic about using notifications. Let&amp;rsquo;s make sure that the notifications we send are:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Crucial&lt;/strong&gt; - information that the user must see.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Expected&lt;/strong&gt; - make sure that your users have clearly opted in to your notifications, and are expecting your message.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Timely&lt;/strong&gt; - Don&amp;rsquo;t send notifications in the middle of the night. Send notifications at a time that is most useful for your user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or, perhaps, we shouldn&amp;rsquo;t send any at all.&lt;/p&gt;

&lt;h1&gt;The web on my watch&lt;/h1&gt;

&lt;p&gt;One of the biggest problems with the fast web is the enormous sense of immediacy. The&amp;nbsp;Dopamine hit. The sense that something is out of date when it&amp;rsquo;s five minutes old. And the need to &amp;lsquo;stay up to date&amp;rsquo; is a major cause of anxiety. At least for me.&lt;/p&gt;

&lt;p&gt;A slower web should reduce immediacy. It should allow people to take use it on their&amp;nbsp;terms, and at a time that suits them.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/pocket.png&quot; style=&quot;width:310px;height:550px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;One of my favourite web applications is Pocket. Much like Instapaper before it, Pocket allows me to save articles and blog posts to for later reading. I can read saved articles whenever I choose, even when I&amp;rsquo;m offline. This save-for-later feature gives me&amp;nbsp;a greater control over the web I consume, and also where and when I consume it.&lt;/p&gt;

&lt;p&gt;Likewise, we should be creating experiences that fit a little better into the rhythm of our users&amp;rsquo; lives. Don&amp;rsquo;t just think about how and why&amp;mdash;understand the cadence of your experience, and give your users control over when, and how often, they interact with you.&lt;/p&gt;

&lt;h1&gt;Send them outside&lt;/h1&gt;

&lt;p&gt;As slow web designers, perhaps we should be encouraging our users to spend less time using our apps. Less time in front of screens.&lt;/p&gt;

&lt;p&gt;There are some great examples of technology that do this well.&lt;/p&gt;

&lt;p&gt;Firstly, there&amp;rsquo;s &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.strava.com/&quot;&gt;Strava&lt;/a&gt;, a run-tracking app that&amp;rsquo;s all about getting you outside to run or ride.&lt;/p&gt;

&lt;p&gt;Or &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://inthemoment.io/&quot;&gt;Moment&lt;/a&gt;. Moment is an iOS app that automatically tracks how much you use your iPhone and iPad each day - and actively encourages you to turn off.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/inthemoment.png&quot; style=&quot;width:310px;height:550px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;And then there&amp;rsquo;s Toymail. Toymail make wi-fi connected toys that encourages your kids to express themselves and communicate with family digitally, but without the screen exposure. Using an Android or iOS app, you can send messages to your children, via the Mailmen toys - like snort here.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/toymail.jpg&quot; style=&quot;width:452px;height:550px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;Kids can also reply right back, again via the toy. So it&amp;rsquo;s a two-way conversion that doesn&amp;rsquo;t happen over a screen.&lt;/p&gt;

&lt;p&gt;Are there ways that you can encourage your users to stop, unplug, and smell the roses?&lt;/p&gt;

&lt;h1&gt;Respect thy user&lt;/h1&gt;

&lt;p&gt;Ultimately, designing for the slow web is about showing respect for our users.&lt;/p&gt;

&lt;p&gt;Your users are probably very busy people, with constant distractions in their lives. So make sure you&amp;#39;re always respecting their&amp;nbsp;time. Never be a distraction to your user&amp;rsquo;s already-busy day. Never be pushy.&lt;/p&gt;

&lt;p&gt;A slower web should reduce the noise&amp;nbsp;and informational clutter, not add to it. So&amp;nbsp;next time you&amp;rsquo;re adding a feature, or sending out a notification, ask yourself,&amp;nbsp;&amp;ldquo;Is this interaction or&amp;nbsp;this touch-point truly going to make my user&amp;rsquo;s day better?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;If not, why do it?&lt;/p&gt;</description>
         <guid isPermaLink="false"></guid>
         <pubDate>Mon, 22 Dec 2014 21:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[24ways] Integrating Contrast Checks in Your Web Workflow</title>
         <link>http://feedproxy.google.com/~r/24ways/~3/lyDC22dYLOc/</link>
         <description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.hellogeri.com/&quot;&gt;Geri Coady&lt;/a&gt; bends low the Christmas tree branches with bright and contrasting baubles. This isn&amp;#8217;t some gaudy seasonal distraction, though. It&amp;#8217;s responsible accessibility advice you can work with throughout the year.&lt;/p&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=lyDC22dYLOc:Jvn0jerPAQA:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=lyDC22dYLOc:Jvn0jerPAQA:7Q72WNTAKBA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=7Q72WNTAKBA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=lyDC22dYLOc:Jvn0jerPAQA:V_sGLiPBpWU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?i=lyDC22dYLOc:Jvn0jerPAQA:V_sGLiPBpWU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=lyDC22dYLOc:Jvn0jerPAQA:dnMXMwOfBR0&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=dnMXMwOfBR0&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/24ways/~4/lyDC22dYLOc&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>feeds@allinthehead.com (Geri Coady)</author>
         <guid isPermaLink="false">http://24ways.org/2014/integrating-contrast-checks-in-your-web-workflow/</guid>
         <pubDate>Mon, 22 Dec 2014 12:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[perl] A Holiday PAPR-ation</title>
         <link>http://perladvent.org/2014/2014-12-22.html</link>
         <description>&lt;div class='pod'&gt;&lt;p&gt;Jesse, Junior IT Elf Second Class grumbled to himself, &amp;quot;Who even thought this was a good idea anyway.&amp;quot; He had grabbed a ticket out of the North Pole&amp;#39;s ticketing system, thinking that adding a simple new endpoint to an existing RESTful API would be a fairly trivial task. He had hoped to get out of the office early today, and instead he was staring at a creeping horror and the possibility of working all weekend.&lt;/p&gt;

&lt;p&gt;Clearly, the code had originally started out as a very simple API of only a few endpoints. The original coder, either being in a hurry or just not knowing any better, had decided to implement it as a series of &lt;code&gt; if &lt;/code&gt;-&lt;code&gt; elsif &lt;/code&gt;-&lt;code&gt; else &lt;/code&gt; blocks based on the first element in the URL string.&lt;/p&gt;

&lt;p&gt;Now, 10 years later, there were dozens of &lt;code&gt; elsif &lt;/code&gt; blocks, each with its own specialized handling of the subsequent parts of the URL. There was no overall organization to the code -- it seemed as if every time a new endpoint was required, the elf doing the work had just slapped in an &lt;code&gt; elsif &lt;/code&gt; block whereever they felt like. The end result now had a structure something like this (only much worse -- the example is sanitized for a family audience):&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;br /&gt;28:&amp;nbsp;&lt;br /&gt;29:&amp;nbsp;&lt;br /&gt;30:&amp;nbsp;&lt;br /&gt;31:&amp;nbsp;&lt;br /&gt;32:&amp;nbsp;&lt;br /&gt;33:&amp;nbsp;&lt;br /&gt;34:&amp;nbsp;&lt;br /&gt;35:&amp;nbsp;&lt;br /&gt;36:&amp;nbsp;&lt;br /&gt;37:&amp;nbsp;&lt;br /&gt;38:&amp;nbsp;&lt;br /&gt;39:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cgi&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$first&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$cgi&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;path_info&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# /present/present_id/action&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$first&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'present'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validate_present_id&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad id&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ENV&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;match&quot;&gt;/^(add|update|delete)$/&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad action&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_present_update&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ENV&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'GET'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_present_get&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# /good_child/child_id/reason&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;elsif&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$first&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'good_child'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validate_child_id&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad id&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validate_reason&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad reason&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ENV&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_child_update&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'good_child'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# /bad_child/child_id/reason&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;elsif&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$first&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'bad_child'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validate_child_id&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad id&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validate_reason&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad reason&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$ENV&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_child_update&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'bad_child'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;no match!&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;As Jesse sat and stared at screen after screen of cascading conditionals, grumbling and muttering to himself, his boss Margaret walked by and asked, &amp;quot;What&amp;#39;s going on, Jesse?&amp;quot;&lt;/p&gt;

&lt;p&gt;Jesse started to rant about the API code, but Margaret cut him off quickly. &amp;quot;Listen, didn&amp;#39;t you see the last memo that came out from the Big Guy? We&amp;#39;re supposed to be replacing all those old CGIs with PSGIs when ever we have to make any changes to them. This is your lucky day, Junior! You get to clean up this mess. But we&amp;#39;ve got apps deployed in the field that rely on this API, so make sure you don&amp;#39;t change any of the endpoints while you&amp;#39;re porting it over, or there will be heck to pay.&amp;quot;&lt;/p&gt;

&lt;p&gt;&amp;quot;Fine&amp;quot;, Jesse sighed. &amp;quot;I guess I can go on &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/&quot;&gt;MetaCPAN&lt;/a&gt; and research the best way to...&amp;quot;&lt;/p&gt;

&lt;p&gt;Margaret cut him off again. &amp;quot;No need, kid. Just use PAPR -- &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack::App::Path::Router&quot;&gt;Plack::App::Path::Router&lt;/a&gt;!&amp;quot;&lt;/p&gt;

&lt;p&gt;Jesse sighed again as he pulled up the documentation on MetaCPAN. He learned that &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack::App::Path::Router&quot;&gt;Plack::App::Path::Router&lt;/a&gt; provides a convenient way to take a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Path::Router&quot;&gt;Path::Router&lt;/a&gt; specification and wrap it up as a PSGI. Jesse was quickly able to turn the existing conditional cascade into a much more declarative set of &lt;code&gt; add_route &lt;/code&gt; statements. He also quickly realized that he could replace all the custom validation routines in the old code with &lt;code&gt;Path::Router&lt;/code&gt;&amp;#39;s parameter extraction and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Moose&quot;&gt;Moose&lt;/a&gt;-style validations.&lt;/p&gt;

&lt;p&gt;Within a few hours, Jesse had converted all the old style code to a form that looked like this:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;br /&gt;28:&amp;nbsp;&lt;br /&gt;29:&amp;nbsp;&lt;br /&gt;30:&amp;nbsp;&lt;br /&gt;31:&amp;nbsp;&lt;br /&gt;32:&amp;nbsp;&lt;br /&gt;33:&amp;nbsp;&lt;br /&gt;34:&amp;nbsp;&lt;br /&gt;35:&amp;nbsp;&lt;br /&gt;36:&amp;nbsp;&lt;br /&gt;37:&amp;nbsp;&lt;br /&gt;38:&amp;nbsp;&lt;br /&gt;39:&amp;nbsp;&lt;br /&gt;40:&amp;nbsp;&lt;br /&gt;41:&amp;nbsp;&lt;br /&gt;42:&amp;nbsp;&lt;br /&gt;43:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::App::Path::Router&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Path::Router&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Path::Router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# note - formerly handled by a single conditional stanza; now split into two&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;add_route&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/present/:present_id'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;present_id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;target&lt;/span&gt;      &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;    # $request is a L&amp;lt;Plack::Request&amp;gt; object&lt;br /&gt;&lt;/span&gt;    &lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'GET'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_present_get&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;add_route&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/present/:present_id/:action'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;present_id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;action&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;regexp&quot;&gt;qr/^(add|update|delete)$/&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# validations can also be plain regexps&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_present_update&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# covers both /good_child/ and /bad_child/ endpoints&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;add_route&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/:child_type/:child_id/:reason'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;child_type&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;regexp&quot;&gt;qr/^(good|bad)_child/&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;child_id&lt;/span&gt;   &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;reason&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Str'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$type&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;_handle_child_update&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$type&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$reason&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# now create the Plack app&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$app&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::App::Path::Router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;He commited his changes, and then added in one more change that added the new endpoint that had originally started him down this path. Work all done, he pushed his branch, and moved the ticket into the code review stage. While it had taken him a little longer than he expected, it still looked like he&amp;#39;d be done early.&lt;/p&gt;

&lt;p&gt;As he made one last scan over his email, Jesse realized that Margaret had already responded to his code review request ... and worse, she&amp;#39;d rejected his changes! She was asking for something that was more data-driven and didn&amp;#39;t have so much boilerplate code. Her suggestion was to look at &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack::App::Path::Router::Custom&quot;&gt;Plack::App::Path::Router::Custom&lt;/a&gt; -- which Jesse dutifully pulled up on MetaCPAN. After a few minutes of reading, he saw exactly what she was talking about. He rapidly converted the previous version into this completely data-driven form:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;br /&gt;8:&amp;nbsp;&lt;br /&gt;9:&amp;nbsp;&lt;br /&gt;10:&amp;nbsp;&lt;br /&gt;11:&amp;nbsp;&lt;br /&gt;12:&amp;nbsp;&lt;br /&gt;13:&amp;nbsp;&lt;br /&gt;14:&amp;nbsp;&lt;br /&gt;15:&amp;nbsp;&lt;br /&gt;16:&amp;nbsp;&lt;br /&gt;17:&amp;nbsp;&lt;br /&gt;18:&amp;nbsp;&lt;br /&gt;19:&amp;nbsp;&lt;br /&gt;20:&amp;nbsp;&lt;br /&gt;21:&amp;nbsp;&lt;br /&gt;22:&amp;nbsp;&lt;br /&gt;23:&amp;nbsp;&lt;br /&gt;24:&amp;nbsp;&lt;br /&gt;25:&amp;nbsp;&lt;br /&gt;26:&amp;nbsp;&lt;br /&gt;27:&amp;nbsp;&lt;br /&gt;28:&amp;nbsp;&lt;br /&gt;29:&amp;nbsp;&lt;br /&gt;30:&amp;nbsp;&lt;br /&gt;31:&amp;nbsp;&lt;br /&gt;32:&amp;nbsp;&lt;br /&gt;33:&amp;nbsp;&lt;br /&gt;34:&amp;nbsp;&lt;br /&gt;35:&amp;nbsp;&lt;br /&gt;36:&amp;nbsp;&lt;br /&gt;37:&amp;nbsp;&lt;br /&gt;38:&amp;nbsp;&lt;br /&gt;39:&amp;nbsp;&lt;br /&gt;40:&amp;nbsp;&lt;br /&gt;41:&amp;nbsp;&lt;br /&gt;42:&amp;nbsp;&lt;br /&gt;43:&amp;nbsp;&lt;br /&gt;44:&amp;nbsp;&lt;br /&gt;45:&amp;nbsp;&lt;br /&gt;46:&amp;nbsp;&lt;br /&gt;47:&amp;nbsp;&lt;br /&gt;48:&amp;nbsp;&lt;br /&gt;49:&amp;nbsp;&lt;br /&gt;50:&amp;nbsp;&lt;br /&gt;51:&amp;nbsp;&lt;br /&gt;52:&amp;nbsp;&lt;br /&gt;53:&amp;nbsp;&lt;br /&gt;54:&amp;nbsp;&lt;br /&gt;55:&amp;nbsp;&lt;br /&gt;56:&amp;nbsp;&lt;br /&gt;57:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Path::Router&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::App::Path::Router&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::Request&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;SantasWorkshop::API&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;comment&quot;&gt;# all the '_handle' methods were migrated to here&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# each entry is 'route definition' =&amp;gt; 'method' =&amp;gt; 'hashref of options'&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@routes&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/present/:present_id'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'handle_present_get'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;methods&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'GET'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;present_id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}]&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/present/:present_id/:action'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'handle_present_update'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;methods&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;present_id&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;action&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;regexp&quot;&gt;qr/^(add|update|delete)$/&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# validations can also be plain regexpsld&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}]&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;  # covers both /good_child/ and /bad_child/ endpoints&lt;br /&gt;&lt;/span&gt;  &lt;span class=&quot;structure&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'/:child_type/:child_id/:reason'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'handle_child_update'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;methods&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'POST'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;child_type&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;regexp&quot;&gt;qr/^(good|bad)_child/&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;child_id&lt;/span&gt;   &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Int'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;reason&lt;/span&gt;     &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;single&quot;&gt;'Str'&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}]&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# dynamically build the routing table based on the @routes data structure&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Path::Router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;@routes&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$endpoint&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$options&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cast&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;magic&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;add_route&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$endpoint&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;magic&quot;&gt;@_&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;exists&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request_method&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;();&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;return_error&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;double&quot;&gt;&amp;quot;bad method&amp;quot;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}{&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$request_method&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;};&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;SantasWorkshop::API&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;$action&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;symbol&quot;&gt;@rest&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;validations&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;structure&quot;&gt;));&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;# once the routing table is all build, make the app using that router.&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$app&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::App::Path::Router::Custom&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;router&lt;/span&gt;      &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;word&quot;&gt;new_request&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;word&quot;&gt;Plack::Request&lt;/span&gt;&lt;span class=&quot;operator&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;word&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;core&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;structure&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;structure&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;structure&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Jesse pushed the final revision up for code review and got notification of Margaret&amp;#39;s merging of the code into the release branch only a few minutes later -- along with an IM saying, &amp;quot;Nice work, kid -- how about you take off early today.&amp;quot;&lt;/p&gt;

&lt;h2 id=&quot;See-Also&quot;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack::App::Path::Router&quot;&gt;Plack::App::Path::Router&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Path::Router&quot;&gt;Path::Router&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack::App::Path::Router::Custom&quot;&gt;Plack::App::Path::Router::Custom&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/Plack&quot;&gt;Plack&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://perladvent.org/2014/2014-12-04.html&quot;&gt;The Perl Advent Article on PSGI and Plack&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</description>
         <author>John SJ Anderson</author>
         <guid isPermaLink="false">http://perladvent.org/2014/2014-12-22.html</guid>
         <pubDate>Mon, 22 Dec 2014 05:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[java] A persistent KeyValue Server in 40 lines and a sad fact</title>
         <link>http://feedproxy.google.com/~r/JavaAdventCalendar/~3/3JqUVVqxGoY/a-persistent-keyvalue-server-in-40.html</link>
         <description>Advent time again .. picking up Peters &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.javaadvent.com/2014/12/how-and-why-is-unsafe-used-in-java.html&quot;&gt;well written overview&lt;/a&gt; on the uses of Unsafe, i'll have a &lt;strike&gt;short&lt;/strike&gt; fly-by on how low level techniques in Java can save development effort by enabling a higher level of abstraction&amp;nbsp;&lt;b&gt;or&lt;/b&gt; allow for Java performance levels probably unknown to many.&lt;br /&gt;&lt;br /&gt;My major point is to show that conversion of Objects to bytes and vice versa is an important fundamental, affecting virtually any modern java application.&lt;br /&gt;&lt;br /&gt;Hardware enjoys to process streams of bytes, not object graphs connected by pointers as&amp;nbsp;&lt;i&gt;&quot;All memory is tape&quot;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/i&gt;&lt;span style=&quot;font-size:x-small;font-weight:bold;&quot;&gt;(M.Thompson if I remember correctly ..).&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:x-small;font-weight:bold;&quot;&gt;&lt;br /&gt;&lt;/span&gt;Many basic technologies are therefore hard to use with vanilla Java heap objects:&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Memory Mapped Files&lt;/b&gt;&amp;nbsp;- a great and simple technology to persist application data safe, fast &amp;amp; easy.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Network communication&lt;/b&gt;&amp;nbsp;is based on sending packets of bytes&lt;/li&gt;&lt;li&gt;&lt;b&gt;Interprocess communication&lt;/b&gt;&amp;nbsp;(shared memory)&lt;/li&gt;&lt;li&gt;&lt;b&gt;Large main memory&lt;/b&gt;&amp;nbsp;of today's servers (64GB to 256GB). (GC issues)&lt;/li&gt;&lt;li&gt;CPU caches work best on data stored as a continuous stream of bytes in memory&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;so use of the Unsafe class in most cases boil down in helping to transform a java object graph into a continuous&amp;nbsp;memory region and vice versa either using&lt;br /&gt;&lt;ul&gt;&lt;li&gt;[performance enhanced]&amp;nbsp;&lt;b&gt;object serialization&lt;/b&gt;&amp;nbsp;or&lt;/li&gt;&lt;li&gt;&lt;b&gt;wrapper classes&lt;/b&gt;&amp;nbsp;to ease access to data stored in a continuous memory region.&lt;/li&gt;&lt;/ul&gt;(&lt;b&gt;source&lt;/b&gt; of examples used in this post can be found &lt;b&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/advcalendar2014&quot;&gt;here&lt;/a&gt;, &lt;/b&gt;messaging&lt;b&gt;&amp;nbsp;&lt;/b&gt;latency test &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/fast-cast/tree/3.0/examples/src/main/java/org/nustaq/fastcast/examples/latency&quot;&gt;&lt;b&gt;here&lt;/b&gt;&lt;/a&gt;)&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;span style=&quot;font-size:x-large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-size:x-large;&quot;&gt;Serialization based Off-Heap&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Consider a retail WebApplication where there might be millions of registered users. We are actually not interested in representing data in a relational database as all needed is a quick retrieve of user related data once he logs in. Additionally one would like to traverse the social graph quickly.&lt;br /&gt;&lt;br /&gt;Let's take a simple user class holding some attributes and a list of 'friends' making up a social graph.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-ko41Bd7TWxE/VI9xMGIs5_I/AAAAAAAAAYE/CW_7XOTepPs/s1600/user.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-ko41Bd7TWxE/VI9xMGIs5_I/AAAAAAAAAYE/CW_7XOTepPs/s1600/user.png&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;easiest way to store this on heap, is a simple huge HashMap.&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;/div&gt;Alternatively one can use &lt;b&gt;off heap maps&lt;/b&gt;&amp;nbsp;to store large amounts of data. An off heap map stores its keys and values inside the native heap, so garbage collection does not need to track this memory. In addition, native heap can be told to automagically get synchronized to disk (memory mapped files). This even works in case your application crashes, as the OS manages write back of changed memory regions.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;There are some open source off heap map implementations out there with various feature sets (e.g. &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/OpenHFT/Chronicle-Map#complex-types&quot;&gt;ChronicleMap&lt;/a&gt;), for this example I'll use a plain and simple implementation featuring fast iteration (optional full scan search) and ease of use.&lt;br /&gt;&lt;br /&gt;Serialization is used to store objects, deserialization is used in order to pull them to the java heap again. Pleasantly I have written the (afaik) &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/fast-serialization&quot;&gt;fastest fully JDK compliant object serialization&lt;/a&gt; on the planet, so I'll make use of that.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://3.bp.blogspot.com/-22QrzOq-L9g/VJCceMM_MzI/AAAAAAAAAY0/vFZb_4ItgDY/s1600/omap.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-22QrzOq-L9g/VJCceMM_MzI/AAAAAAAAAY0/vFZb_4ItgDY/s1600/omap.png&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;Done:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;persistence by memory mapping a file (map will reload upon creation).&amp;nbsp;&lt;/li&gt;&lt;li&gt;Java Heap still empty to serve real application processing with Full GC &amp;lt; 100ms.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Significantly less&amp;nbsp;overall&amp;nbsp;memory consumption. A user record serialized is ~60 bytes, so in theory 300 million records fit into 180GB of server memory. No need to raise the big data flag and run 4096 hadoop nodes on AWS ;).&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;Comparing a regular in-memory java HashMap and a fast-serialization based persistent off heap map holding&amp;nbsp;&lt;b&gt;15 millions&lt;/b&gt;&amp;nbsp;user records, will show following results (on a 3Ghz older XEON 2x6):&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; dir=&quot;ltr&quot; style=&quot;border-collapse:collapse;border:1px solid rgb(204, 204, 204);font-family:arial, sans, sans-serif;font-size:13px;table-layout:fixed;&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;209&quot;&gt;&lt;col width=&quot;165&quot;&gt;&lt;col width=&quot;79&quot;&gt;&lt;col width=&quot;115&quot;&gt;&lt;col width=&quot;115&quot;&gt;&lt;col width=&quot;112&quot;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;background-color:#d9d9d9;border-left-color:rgb(0, 0, 0);border-left-style:solid;border-left-width:1px;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;consumed Java Heap (MB)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;Full GC (s)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;Native Heap (MB)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;get/put ops per s&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-right-color:rgb(0, 0, 0);border-right-style:solid;border-right-width:1px;border-top-color:rgb(0, 0, 0);border-top-style:solid;border-top-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;required VM size (MB)&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;background-color:#d9d9d9;border-left-color:rgb(0, 0, 0);border-left-style:solid;border-left-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;HashMap&lt;/td&gt;&lt;td style=&quot;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;6.865,00&lt;/td&gt;&lt;td style=&quot;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;26,039&lt;/td&gt;&lt;td style=&quot;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;0&lt;/td&gt;&lt;td style=&quot;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;3.800.000,00&lt;/td&gt;&lt;td style=&quot;border-right-color:rgb(0, 0, 0);border-right-style:solid;border-right-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;12.000,00&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;background-color:#d9d9d9;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;border-left-color:rgb(0, 0, 0);border-left-style:solid;border-left-width:1px;padding:2px 3px;vertical-align:bottom;&quot;&gt;OffheapMap (Serialization based)&lt;/td&gt;&lt;td style=&quot;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;63,00&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;0,026&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;3.050&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;750.000,00&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom-color:rgb(0, 0, 0);border-bottom-style:solid;border-bottom-width:1px;border-right-color:rgb(0, 0, 0);border-right-style:solid;border-right-width:1px;padding:2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;&lt;div style=&quot;text-align:right;&quot;&gt;500,00&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;[&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/OffHeapMapExample.java&quot;&gt;test source / blog project&lt;/a&gt;] Note: You'll need at least 16GB of RAM to execute them.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://1.bp.blogspot.com/-3zdF-3eVk2Q/VJYxMWURZuI/AAAAAAAAAbs/Muh1UrE6q6w/s1600/offheap.jpg&quot; style=&quot;clear:left;float:left;margin-bottom:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-3zdF-3eVk2Q/VJYxMWURZuI/AAAAAAAAAbs/Muh1UrE6q6w/s1600/offheap.jpg&quot; height=&quot;133&quot; width=&quot;200&quot;/&gt;&lt;/a&gt;&lt;/div&gt;As one can see, even with fast serialization there is a heavy penalty (~factor 5) in access performance, anyway: compared to other persistence alternatives, its still superior (1-3 microseconds per &quot;get&quot; operation, &quot;put()&quot; very similar).&lt;br /&gt;&lt;br /&gt;Use of JDK serialization would perform at least 5 to 10 times slower (direct comparison below) and therefore render this approach useless.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;&lt;span style=&quot;font-size:x-large;&quot;&gt;Trading performance gains against higher level of abstraction: &quot;Serverize me&quot;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-size:large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://1.bp.blogspot.com/-whWSINSD8aE/VJYueU4yaQI/AAAAAAAAAbc/qsrfl-8SQ-g/s1600/parking-like-a-mini-boss-bike.gif&quot; style=&quot;clear:left;float:left;margin-bottom:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-whWSINSD8aE/VJYueU4yaQI/AAAAAAAAAbc/qsrfl-8SQ-g/s1600/parking-like-a-mini-boss-bike.gif&quot; height=&quot;112&quot; width=&quot;200&quot;/&gt;&lt;/a&gt;&lt;/div&gt;A single server won't be able to serve (hundreds of) thousands of users, so we somehow need to share data amongst processes, even better: across machines.&lt;br /&gt;&lt;br /&gt;Using a fast implementation, its possible to generously use (fast-) serialization for over-the-network messaging. Again: if this would run like 5 to 10 times slower, it just wouldn't be viable. Alternative approaches require an order of magnitude more work to achieve similar results.&lt;br /&gt;&lt;br /&gt;By wrapping the persistent off heap hash map by an Actor implementation (async ftw!), some lines of code make up a persistent KeyValue server with a TCP-based and a HTTP interface (uses&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/kontraktor&quot;&gt;kontraktor actors&lt;/a&gt;). Of course the Actor can still be used in-process if one decides so later on.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://4.bp.blogspot.com/-mDMLeaHyXhM/VJNAtBcwC5I/AAAAAAAAAac/GfXHtq07s8E/s1600/kvs.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-mDMLeaHyXhM/VJNAtBcwC5I/AAAAAAAAAac/GfXHtq07s8E/s1600/kvs.png&quot; height=&quot;640&quot; width=&quot;604&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now that's a micro service. Given it lacks any attempt of optimization and is &lt;b&gt;single threaded&lt;/b&gt;, its reasonably fast [same XEON machine as above]:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;280_000 successful remote lookups per second&amp;nbsp;&lt;/li&gt;&lt;li&gt;800_000 in case of fail lookups (key not found)&lt;/li&gt;&lt;li&gt;serialization based TCP interface (1 liner)&lt;/li&gt;&lt;li&gt;a stringy webservice for the REST-of-us (1 liner).&lt;/li&gt;&lt;/ul&gt;[&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/advcalendar2014/tree/master/src/main/java/keyvalue&quot;&gt;source: KVServer, KVClient&lt;/a&gt;] Note: You'll need at least 16GB of RAM to execute the test.&lt;br /&gt;&lt;br /&gt;A real world implementation might want to double performance by directly putting received serialized object byte[] into the map instead of encoding it twice (encode/decode once for transmission over wire, then decode/encode for offheaping map).&lt;br /&gt;&lt;br /&gt;&quot;RestActorServer.Publish(..);&quot; is a one liner to also expose the KVActor as a webservice in addition to raw tcp:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://1.bp.blogspot.com/-7NWFVbFKaf0/VJC9gIoAWII/AAAAAAAAAZE/iDJVmcbqhxg/s1600/Screenshot%2Bfrom%2B2014-12-17%2B00%3A19%3A18.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-7NWFVbFKaf0/VJC9gIoAWII/AAAAAAAAAZE/iDJVmcbqhxg/s1600/Screenshot%2Bfrom%2B2014-12-17%2B00%3A19%3A18.png&quot; height=&quot;304&quot; width=&quot;320&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size:x-large;&quot;&gt;C like performance using flyweight wrappers / structs&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;With serialization, regular Java Objects are transformed to a byte sequence. One can do the opposite: Create &amp;nbsp;wrapper classes which read data from fixed or computed positions of an underlying byte array or native memory address. (E.g. see&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://mechanical-sympathy.blogspot.de/2012/10/compact-off-heap-structurestuples-in.html&quot;&gt;this blog post&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;By moving the base pointer its possible to access different records by just moving the the wrapper's offset. Copying such a &quot;packed object&quot; boils down to a memory copy. In addition, its pretty easy to write allocation free code this way. One downside is, that reading/writing single fields has a performance penalty compared to regular Java Objects. This can be made up for by using the Unsafe class.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-i7mNlwJPIBs/VJYpY4A7HRI/AAAAAAAAAbI/juoGEsrsygA/s1600/structs.gif&quot; style=&quot;clear:left;float:left;margin-bottom:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-i7mNlwJPIBs/VJYpY4A7HRI/AAAAAAAAAbI/juoGEsrsygA/s1600/structs.gif&quot; height=&quot;200&quot; width=&quot;169&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&quot;flyweight&quot; wrapper classes can be implemented manually as shown in the blog post cited, however as code grows this starts getting unmaintainable.&lt;br /&gt;Fast-serializaton provides a byproduct &quot;struct emulation&quot; supporting creation of flyweight wrapper classes from regular Java classes at runtime. Low level byte fiddling in application code can be avoided for the most part this way.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align:center;&quot;&gt;&lt;i&gt;How a regular Java class can be mapped to flat memory (fst-structs):&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-i7mNlwJPIBs/VJYpY4A7HRI/AAAAAAAAAbE/idSm4MQthgE/s1600/structs.gif&quot; style=&quot;clear:left;float:left;margin-bottom:1em;margin-right:1em;&quot;&gt;&lt;/a&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://1.bp.blogspot.com/-74SMGg32yEI/VJHE0i-LxBI/AAAAAAAAAZ0/PXKC2D4-PXQ/s1600/Capture.PNG&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-74SMGg32yEI/VJHE0i-LxBI/AAAAAAAAAZ0/PXKC2D4-PXQ/s1600/Capture.PNG&quot; height=&quot;208&quot; width=&quot;640&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Of course there are simpler tools out there to help reduce manual programming of encoding &amp;nbsp;(e.g.&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RichardWarburton/slab&quot;&gt;Slab&lt;/a&gt;)&amp;nbsp;which might be more appropriate for many cases and use less &quot;magic&quot;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What kind of performance can be expected using the different approaches (sad fact incoming) ?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Lets take the following struct-class consisting of a price update and an embedded struct denoting a tradable instrument (e.g. stock) and encode it using various methods:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://3.bp.blogspot.com/-GGPqggr-B40/VJDN3DK0fUI/AAAAAAAAAZU/qHO8eZZLhEc/s1600/struct.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-GGPqggr-B40/VJDN3DK0fUI/AAAAAAAAAZU/qHO8eZZLhEc/s1600/struct.png&quot; height=&quot;640&quot; width=&quot;532&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;i&gt;a 'struct' in code&lt;/i&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:left;&quot;&gt;&lt;b&gt;Pure encoding performance:&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; dir=&quot;ltr&quot; style=&quot;border-collapse:collapse;border:1px solid #ccc;font-family:arial, sans, sans-serif;font-size:13px;table-layout:fixed;&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;100&quot;&gt;&lt;col width=&quot;155&quot;&gt;&lt;col width=&quot;97&quot;&gt;&lt;col width=&quot;130&quot;&gt;&lt;col width=&quot;86&quot;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;background-color:#d9d9d9;border-left:1px solid #000000;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;Structs&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;fast-Ser (no shared refs)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;fast-Ser&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;JDK Ser (no shared)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-right:1px solid #000000;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;JDK Ser&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;border-bottom:1px solid #000000;border-left:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;26.315.000,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;7.757.000,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;5.102.000,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;649.000,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;border-right:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;644.000,00&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://4.bp.blogspot.com/-wWlqMg6sDkU/VJVbDBWfW7I/AAAAAAAAAas/oegUyK3sNyg/s1600/adv1.PNG&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-wWlqMg6sDkU/VJVbDBWfW7I/AAAAAAAAAas/oegUyK3sNyg/s1600/adv1.PNG&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;Real world test with messaging throughput:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In order to get a basic estimation of differences in a real application, i do an experiment how different encodings perform when used to send and receive messages at a high rate via &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/fast-cast&quot;&gt;reliable UDP messaging&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;The Test:&lt;/i&gt;&lt;br /&gt;&lt;i&gt;A sender encodes messages as fast as possible and publishes them using reliable multicast, a subscriber receives and decodes them.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; dir=&quot;ltr&quot; style=&quot;border-collapse:collapse;border:1px solid #ccc;font-family:arial, sans, sans-serif;font-size:13px;table-layout:fixed;&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;100&quot;&gt;&lt;col width=&quot;155&quot;&gt;&lt;col width=&quot;97&quot;&gt;&lt;col width=&quot;130&quot;&gt;&lt;col width=&quot;86&quot;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;background-color:#d9d9d9;border-left:1px solid #000000;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;Structs&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;fast-Ser (no shared refs)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;fast-Ser&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;JDK Ser (no shared)&lt;/td&gt;&lt;td style=&quot;background-color:#d9d9d9;border-right:1px solid #000000;border-top:1px solid #000000;padding:2px 3px 2px 3px;vertical-align:bottom;&quot;&gt;JDK Ser&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height:21px;&quot;&gt;&lt;td style=&quot;border-bottom:1px solid #000000;border-left:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;6.644.107,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;4.385.118,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;3.615.584,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;81.582,00&lt;/td&gt;&lt;td style=&quot;border-bottom:1px solid #000000;border-right:1px solid #000000;padding:2px 3px 2px 3px;text-align:right;vertical-align:bottom;&quot;&gt;79.073,00&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://3.bp.blogspot.com/-FVtCrYYJ8b8/VJVcCF6jOfI/AAAAAAAAAa0/1-gV5PdS-Sg/s1600/adv2.PNG&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-FVtCrYYJ8b8/VJVcCF6jOfI/AAAAAAAAAa0/1-gV5PdS-Sg/s1600/adv2.PNG&quot;/&gt;&lt;/a&gt;&lt;/div&gt;(Tests done on I7/Win8, XEON/Linux scores slightly higher, msg size ~70 bytes for structs, ~60 bytes serialization).&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://4.bp.blogspot.com/-UyPdeiSj68k/VJYrPMuxchI/AAAAAAAAAbQ/o_2dyoW0GHU/s1600/omg.gif&quot; style=&quot;clear:left;float:left;margin-bottom:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-UyPdeiSj68k/VJYrPMuxchI/AAAAAAAAAbQ/o_2dyoW0GHU/s1600/omg.gif&quot; height=&quot;120&quot; width=&quot;200&quot;/&gt;&lt;/a&gt;&lt;/div&gt;Slowest compared to fastest: factor of 82. The test highlights an issue not covered by micro-benchmarking: Encoding and Decoding should perform similar, as factual throughput is determined by Min(Encoding performance, Decoding performance). For unknown reasons JDK serialization manages to encode the message tested like 500_000 times per second, decoding performance is only 80_000 per second so in the test the receiver gets dropped quickly:&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;***** Stats for receive rate: &amp;nbsp; 80351 &amp;nbsp; per second *********&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;***** Stats for receive rate: &amp;nbsp; 78769 &amp;nbsp; per second *********&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;SUB-ud4q has been dropped by PUB-9afs on service 1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;fatal, could not keep up. exiting&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New, Courier, monospace;&quot;&gt;&quot;&lt;/span&gt;&lt;br /&gt;(Creating backpressure here probably isn't the right way to address the issue ;-) &amp;nbsp;)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a fast serialization allows for a level of abstraction in distributed applications impossible if serialization implementation is either&lt;br /&gt;- too slow&lt;br /&gt;- incomplete. E.g. cannot handle any serializable object graph&lt;br /&gt;- requires manual coding/adaptions. (would put many restrictions on actor message types, Futures, Spore's, Maintenance nightmare)&lt;/li&gt;&lt;li&gt;Low Level utilities like Unsafe enable different representations of data resulting in extraordinary throughput or guaranteed latency boundaries (allocation free main path) for particular workloads. These are impossible to achieve by a large margin with JDK's public tool set.&lt;/li&gt;&lt;li&gt;In distributed systems, communication performance is of fundamental importance. Removing Unsafe is &amp;nbsp;not the biggest fish to fry looking at the numbers above .. JSON or XML won't fix this ;-).&lt;/li&gt;&lt;li&gt;While the HotSpot VM has reached an extraordinary level of performance and reliability, CPU is wasted in some parts of the JDK like there's no tomorrow. Given we are living in the age of distributed applications and data, moving stuff over the wire should be easy to achieve (not manually coded) and as fast as possible.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Addendum: bounded latency&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;A quick &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller/fast-cast/tree/3.0/examples/src/main/java/org/nustaq/fastcast/examples/latency&quot;&gt;Ping Pong RTT latency benchmark&lt;/a&gt; showing that java can compete with C solutions easily, as long the main path is allocation free and techniques like described above are employed:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-NGkVC-b1VZs/VJMd-KHuwFI/AAAAAAAAAaE/Ee6qf1dY9w8/s1600/lat1.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-NGkVC-b1VZs/VJMd-KHuwFI/AAAAAAAAAaE/Ee6qf1dY9w8/s1600/lat1.png&quot; height=&quot;233&quot; width=&quot;640&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear:both;text-align:center;&quot;&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://4.bp.blogspot.com/--O29mfUvsaQ/VJMd-XihA-I/AAAAAAAAAaI/AuFPYFujNV0/s1600/lat2.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/--O29mfUvsaQ/VJMd-XihA-I/AAAAAAAAAaI/AuFPYFujNV0/s1600/lat2.png&quot; height=&quot;243&quot; width=&quot;640&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;i&gt;[credits: charts+measurement done with HdrHistogram]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This is an &quot;experiment&quot; rather than a benchmark (so do not read: '&lt;i&gt;Proven: Java faster than C'&lt;/i&gt;), it shows low-level-Java can compete with C in at least this low-level domain.&lt;br /&gt;Of course its not exactly &lt;i&gt;idiomatic &lt;/i&gt;Java code, however its still easier to handle, port and maintain compared to a JNI or pure C(++) solution. Low latency C(++) code won't be that idiomatic either ;-)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;About me:&lt;/b&gt; I am a solution architect freelancing at an exchange company in the area of realtime GUIs, middleware, and low latency CEP (Complex Event Processing).&lt;br /&gt;I am blogging at&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://java-is-the-new-c.blogspot.de/&quot;&gt;http://java-is-the-new-c.blogspot.de/&lt;/a&gt;,&lt;br /&gt;hacking at&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RuedigerMoeller&quot;&gt;https://github.com/RuedigerMoeller&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;em style=&quot;background-color:#fcffee;color:#222222;font-family:Verdana, Geneva, sans-serif;font-size:18px;line-height:24.6399993896484px;&quot;&gt;This post is part of the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://javaadvent.com/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Java Advent Calendar&lt;/a&gt;&amp;nbsp;and is licensed under the&amp;nbsp;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://creativecommons.org/licenses/by/3.0/&quot; style=&quot;color:#888888;text-decoration:none;&quot;&gt;Creative Commons 3.0 Attribution&lt;/a&gt;&amp;nbsp;license. If you like it, please spread the word by sharing, tweeting, FB, G+ and so on!&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=3JqUVVqxGoY:4n6qJXf6mIs:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=3JqUVVqxGoY:4n6qJXf6mIs:4cEx4HpKnUU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?i=3JqUVVqxGoY:4n6qJXf6mIs:4cEx4HpKnUU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=3JqUVVqxGoY:4n6qJXf6mIs:YwkR-u9nhCs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=YwkR-u9nhCs&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?a=3JqUVVqxGoY:4n6qJXf6mIs:qj6IDK7rITs&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/JavaAdventCalendar?d=qj6IDK7rITs&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/JavaAdventCalendar/~4/3JqUVVqxGoY&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Rüdiger Möller</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-2481158163384033132.post-4059719668015939290</guid>
         <pubDate>Mon, 22 Dec 2014 00:32:00 +0000</pubDate>
         <media:thumbnail height="72" url="http://2.bp.blogspot.com/-ko41Bd7TWxE/VI9xMGIs5_I/AAAAAAAAAYE/CW_7XOTepPs/s72-c/user.png" width="72" xmlns:media="http://search.yahoo.com/mrss/"/>
      </item>
      <item>
         <title>[sysadvent] Day 22 - Largely Unappreciated Applicability</title>
         <link>http://feedproxy.google.com/~r/sysadvent/~3/l7hPnxmlQnc/day-22-largely-unappreciated.html</link>
         <description>&lt;p&gt;Written by: John Vincent (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/lusis&quot;&gt;@lusis&lt;/a&gt;)&lt;br&gt;
Edited by: Joseph Kern (&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/josephkern&quot;&gt;@josephkern&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I have had the privilege of writing a post for SysAdvent for the past several years. In general these posts have been focused on broader cultural issues. This year I wanted to do something more technical and this topic gave me a chance to do that. It&amp;#8217;s also just REALLY cool so there&amp;#8217;s that.&lt;/p&gt;

&lt;h3&gt;Nginx&lt;/h3&gt;

&lt;p&gt;I&amp;#8217;m sure most people are familiar with Nginx but I&amp;#8217;m going to provide a short history anyway. Nginx is a webserver created by Igor Sysoev around 2002 to address the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.kegel.com/c10k.html&quot;&gt;C10K problem&lt;/a&gt;.
The C10K problem isn&amp;#8217;t really a &amp;#8220;problem&amp;#8221; anymore in the sense that is was originally. It&amp;#8217;s morphed into the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://c10m.robertgraham.com/p/manifesto.html&quot;&gt;C10M problem&lt;/a&gt;. With the rise of the sensors, we may be dealing with a Cgazillion problem before we know it.&lt;/p&gt;

&lt;p&gt;Nginx addressed this largely with an event loop (I know some folks think the event loop was invented in 2009). The dominant webserver at the time (and still), Apache, used a model of spawning a new process or a new thread for each connection. Nginx did it differently in that it spawned a master process (handles configuration, launching worker threads and the like) and a pool of workers each with their own event loop. Workers share no state between each other and select from a shared socket to process requests. This particular model works and scales very well. There&amp;#8217;s more on the history of Nginx in its section in the second edition of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.aosabook.org/en/nginx.html&quot;&gt;AOSA&lt;/a&gt;. It&amp;#8217;s a good read and while not 100% current, the basics are unchanged.&lt;/p&gt;

&lt;h3&gt;Lua&lt;/h3&gt;

&lt;p&gt;Lua is a programming language invented in 1993. The title of this article is a shout out to how underappreciated Lua is not only as a language but in its myriad uses. Most people who have heard of Lua know it as the language used for World of Warcraft plugins.&lt;/p&gt;

&lt;p&gt;Lua is an interesting language. Anyone with experience in Ruby will likely find themselves picking it up very quickly. It has a very small core language, first-class functions and coroutines. It is dynamically typed and has one native data structure - the table. When you work in Lua, you will learn to love and appreciate the power of tables. They feel a lot like a ruby hash and are the foundation of most advanced Lua. &lt;/p&gt;

&lt;p&gt;It has no classes, but they can be implemented after a fashion using tables. Since Lua has first-class functions, you can create a &amp;#8220;class&amp;#8221; by lumping data and function into a table. There&amp;#8217;s no inheritence but instead you have prototypes (There&amp;#8217;s a bit of sugar to help you out when working with these &amp;#8216;objects&amp;#8217; - &lt;em&gt;e.g calling &lt;code&gt;foo:somefunc()&lt;/code&gt; to imply self as the first argument as opposed to &lt;code&gt;foo.somefunc(self)&lt;/code&gt;&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;For a good read on the language history
- &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Lua_(programming_language)&quot;&gt;Wikipedia&lt;/a&gt;
- &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.lua.org/history.html&quot;&gt;Lua website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For some basics on the language itself, the wikipedia article has code sample and also the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.lua.org/manual/5.2/&quot;&gt;official documentation&lt;/a&gt;. There is also a section on Lua in the newest edition of the Seven Languages series - &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://pragprog.com/book/7lang/seven-more-languages-in-seven-weeks&quot;&gt;Seven More Languages in Seven Weeks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve also written a couple of modules as well (primary for use with OpenResty):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://github.com/lusis/lua-httpclient&quot;&gt;lua-httpclient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/lusis/lua-github&quot;&gt;lua-github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see an example of how the &amp;#8220;classes&amp;#8221; work with Lua, take a look at the github example and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/lusis/lua-github#straight-lua&quot;&gt;compare the usage described in the README&lt;/a&gt; with the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/lusis/lua-github/blob/master/src/github.lua#L45-L47&quot;&gt;module itself&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Combining the two&lt;/h3&gt;

&lt;p&gt;As I mentioned, Lua is an easily embeddable language. I&amp;#8217;ve been unable to find a date on when Lua support was added to Nginx but it was a very early version (~ 0.5).&lt;/p&gt;

&lt;p&gt;One of the pain points of Nginx is that it doesn&amp;#8217;t support dynamically loaded modules. All extended functionality outside the core must be compiled in. Lua support in Nginx made it so that you could add some advanced functionality to Nginx via Lua that would normally require a C module and a recompile.&lt;/p&gt;

&lt;p&gt;Much of the Nginx api itself is exposed to Lua directly and Lua can be used at multiple places in the Nginx workflow. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#ngx.req.set_header&quot;&gt;modify request&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#ngx.header.HEADER&quot;&gt;response headers&lt;/a&gt; via Lua&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua&quot;&gt;create rewrite rules via Lua&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#content_by_lua&quot;&gt;create content itself via Lua&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/lusis/sysadvent-2014/blob/master/var_nginx/conf.d/sysadvent.conf#L97-L107&quot;&gt;dynamically set redirection and proxy backends&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#log_by_lua&quot;&gt;postprocess log events in a non-blocking fashion&lt;/a&gt; (i.e. send directly to Logstash from Nginx)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these are &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua&quot;&gt;documented&lt;/a&gt; on the Nginx website. &lt;/p&gt;

&lt;p&gt;For example, if I wanted to have the response body be entirely created by Lua, I could do the following in Nginx:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;location /foo {
  content_by_lua '
  ngx.header.content_type = 'text/plain'
  local username = &amp;quot;bob&amp;quot;
  ngx.say(&amp;quot;hello &amp;quot;, username)
  ngx.exit(ngx.HTTP_OK)
  '
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example would return &lt;code&gt;hello bob&lt;/code&gt; as plain text to your browser when you requested &lt;code&gt;/foo&lt;/code&gt; from Nginx.&lt;/p&gt;

&lt;p&gt;Obviously escaping could get to be a headache here so most of the &lt;code&gt;*_by_lua&lt;/code&gt; directives (which is for inlined Lua code in the Nginx config files) can be replaced with a &lt;code&gt;*_by_lua_file&lt;/code&gt; where the Lua code is stored in an external file.&lt;/p&gt;

&lt;p&gt;Some other neat tricks you have available are using the cosocket api where you can actually open arbitrary non-blocking network connections via Lua from inside an Nginx worker.&lt;/p&gt;

&lt;p&gt;As you can see, this is pretty powerful. Additionally the Lua functionality is provided in Nginx via a project called &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://luajit.org/luajit.html&quot;&gt;LuaJIT&lt;/a&gt; which offers amazing speed and predicatable usage. By default, Lua code is cached in Nginx but this can be disabled at run-time to help speed up the development process.&lt;/p&gt;

&lt;h3&gt;Enter the OpenResty&lt;/h3&gt;

&lt;p&gt;If it wasn&amp;#8217;t clear yet, the combination of Nginx and Lua basically gives you an application server right in the Nginx core. Others have created Lua modules specifically for use within Nginx and a few years ago an enterprising soul started bundling them up into something called &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://openresty.org/#About&quot;&gt;OpenResty&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OpenResty combines checkpointed versions of Nginx, modified versions of the Lua module (largely maintained by the OpenResty folks anyway), curated versions of LuaJIT and a boatload of Nginx-specific Lua modules into a single distribution. OpenResty builds of Nginx can be used anywhere out-of-the-box that you would use a non-Lua version of Nginx. Currently OpenResty is sponsored by CloudFlare where the primary author, Yichun Zhang (who prefers to go by &amp;#8220;agentzh&amp;#8221; everywhere) is employed.&lt;/p&gt;

&lt;p&gt;OpenResty is a pretty straightforward &amp;#8220;configure/make/make install&amp;#8221; beast. There is a slightly dated omnibus project on Github &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/bakins/omnibus-nginx&quot;&gt;from my friend Brian Akins&lt;/a&gt; that we&amp;#8217;ve contributed to in the past (and will be contributing our current changes back to in the future). Much of my appreciation and knowledge of Lua and OpenResty comes directly from Brian and his omnibus packages are how I got started.&lt;/p&gt;

&lt;h3&gt;But nobody builds system packages anymore&lt;/h3&gt;

&lt;p&gt;Obviously system packages are the domain of greyhaired BOFHs who think servers are for serving. Since we&amp;#8217;re all refined and there are buzzword quotas to be maintained, you should probably just use Docker (but you have to say it like Benny says &amp;#8220;Spaceship&amp;#8221;).&lt;/p&gt;

&lt;p&gt;Seriously though, Docker as a packaging format is pretty neato and for what I wanted to do, Docker was the best route. To that end I give you &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/lusis/sysadvent-2014&quot;&gt;an OpenResty tutorial in a box (well, a container)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The purpose of this repo is to help you get your feet wet with some examples of using Lua with Nginx via the latest OpenResty build. It ships with a Makefile to wrap up all the Docker invocations and hopefully make things dead simple. It works its way up from the basics I&amp;#8217;ve described all the way to communicating between workers via a shared dictionary, making remote API calls to Github, two Slack chat websocket &amp;#8220;clients&amp;#8221; and the skeleton of a dynamic load balancer in Nginx backed by etcd:&lt;/p&gt;

&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-q5jTLYHmgog/VJb8tdqKgaI/AAAAAAAAAQg/pRlQBMI0oo8/s1600/tutorial-landing.png&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;95%&quot; src=&quot;http://2.bp.blogspot.com/-q5jTLYHmgog/VJb8tdqKgaI/AAAAAAAAAQg/pRlQBMI0oo8/s1600/tutorial-landing.png&quot;/&gt;&lt;/a&gt;

&lt;p&gt;In addition, because I know how difficult it can be to develop and troubleshoot against code running inside Nginx I&amp;#8217;ve created a web based &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&quot;&gt;repl&lt;/a&gt; for testing out and experimenting with the Nginx Lua API:&lt;/p&gt;

&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://2.bp.blogspot.com/-K5rrwcAfSwM/VJb8tKoNAbI/AAAAAAAAAQo/LsmSCXMVq-c/s1600/repl.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;95%&quot; src=&quot;http://2.bp.blogspot.com/-K5rrwcAfSwM/VJb8tKoNAbI/AAAAAAAAAQo/LsmSCXMVq-c/s1600/repl.png&quot;/&gt;&lt;/a&gt;


&lt;p&gt;To use the basic examples in the container, you can simply clone the repo and run &lt;code&gt;make all&lt;/code&gt;. This will build the container and then start OpenResty listening on port 3131 (and etcd on 5001 for one of the demos). The directory &lt;code&gt;var_nginx&lt;/code&gt; will be mounted inside the container as &lt;code&gt;/var/nginx&lt;/code&gt; and contains all the neccessary config files and Lua code for you to poke/prod/experiment with. Logs will be written to &lt;code&gt;var_nginx/logs&lt;/code&gt; so you can tail them if you&amp;#8217;d like. As you can see it also uses Bootstrap for the UI so we&amp;#8217;ve pretty much rounded out the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/codinghorror/status/347070841059692545&quot;&gt;&amp;#8220;what the hell have you built&amp;#8221; graph.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that while the repo presents some neat tricks, the code inside is not optimized by any stretch. The etcd code especially may have some blocking implications but I&amp;#8217;ve not yet confirmed that. The purpose is to teach and inspire more than &amp;#8220;take it and run it in prod&amp;#8221;.&lt;/p&gt;

&lt;h4&gt;Advanced Examples&lt;/h4&gt;

&lt;p&gt;If you&amp;#8217;d like to work with the Slack examples, you&amp;#8217;ll need to generate a slack &amp;#8220;bot&amp;#8221; integration token for use. The Makefile includes support for running an etcd container appropriate for use with the tutorial container. If you aren&amp;#8217;t a Slack user then here&amp;#8217;s a screenshot so you can see what it WOULD look like:&lt;/p&gt;

&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://3.bp.blogspot.com/-moNejBaTLKY/VJb8tQHSTQI/AAAAAAAAAQw/avSoKNqQKLo/s1600/slack.png&quot; style=&quot;margin-left:1em;margin-right:1em;&quot;&gt;&lt;img border=&quot;0&quot; width=&quot;95%&quot; src=&quot;http://3.bp.blogspot.com/-moNejBaTLKY/VJb8tQHSTQI/AAAAAAAAAQw/avSoKNqQKLo/s1600/slack.png&quot;/&gt;&lt;/a&gt;

&lt;h3&gt;Wrap up&lt;/h3&gt;

&lt;p&gt;Maybe this post has inspired you to at least take a look at OpenResty. Lua is a really neat language and very easy to pick up and add to your toolbelt. We use OpenResty builds of Nginx in many places internally from proxy servers to even powering our own internal SSO system based on Github Oauth and group memeberships.
While most people simply use Nginx as a proxy and static content service, we treat it like an application server and leverage the flexibility of not requiring another microservice to handle certain tasks (in addition to using it as a proxy and static content service).&lt;/p&gt;

&lt;p&gt;The combination of Nginx and Lua won&amp;#8217;t replace all your use cases but by learning the system better, you can better leverage the use of Nginx across the board.&lt;/p&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/sysadvent/~4/l7hPnxmlQnc&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>Christopher Webber</author>
         <guid isPermaLink="false">tag:blogger.com,1999:blog-3615332969083650973.post-3979056482626521129</guid>
         <pubDate>Mon, 22 Dec 2014 00:00:00 +0000</pubDate>
         <media:thumbnail height="72" url="http://2.bp.blogspot.com/-q5jTLYHmgog/VJb8tdqKgaI/AAAAAAAAAQg/pRlQBMI0oo8/s72-c/tutorial-landing.png" width="72" xmlns:media="http://search.yahoo.com/mrss/"/>
      </item>
      <item>
         <title>[ux] 3 Ways to Select the Perfect Method for your Research Goal</title>
         <link>http://uxmas.com/2014/3-ways-to-select-the-perfect-method-for-your-research-goal</link>
         <description>&lt;p&gt;It&amp;rsquo;s exciting to see more professionals wanting to research customers to make their services and products fit better. But there&amp;rsquo;s a lot of confusion about how to choose the most appropriate&amp;nbsp;research methods to suit your goals.&lt;/p&gt;

&lt;p&gt;So what&amp;rsquo;s the best way to discover customer motivations? How do you understand how customers feel and think? How can you probe the emotional aspects of a user&amp;rsquo;s task? These are all different questions with different goals.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s how you can decide what research to do in each case.&lt;/p&gt;

&lt;h1&gt;1. Avoid fixating on a particular method&lt;/h1&gt;

&lt;p&gt;Customer journey maps are hot right now. Journey maps usually result in appealing and informative diagrams, but if someone in your organization wants to do this kind of research, make sure he or she understands what kind of goal it serves.&lt;/p&gt;

&lt;p&gt;A customer journey map is about a particular persona type having a particular experience. Particular persona type means that you match a researched-and-well-defined audience segment to a behavioral area. For example, you might choose the, &amp;ldquo;I need a pick-me-up, so I do a little retail-therapy shopping&amp;rdquo; audience segment for the &amp;ldquo;shop for fashion&amp;rdquo; behavioral area.&lt;/p&gt;

&lt;p&gt;Another example is the, &amp;ldquo;nearly professional hobbyist photographer artist&amp;rdquo; within the &amp;ldquo;decide whether to buy new gear&amp;rdquo; behavioral area. Particular experience means a defined scope that your organization would like to improve, but which is translated to the customer&amp;rsquo;s perspective. For example, it could be the &amp;ldquo;select the right product for my situation&amp;rdquo; scope, or the &amp;ldquo;track my shipment&amp;rdquo; or &amp;ldquo;unboxing&amp;rdquo; scopes. It could even be the, &amp;ldquo;decide I need a new _____&amp;rdquo; scope.&lt;/p&gt;

&lt;h1&gt;2. Decide which research methods meet your knowledge-gathering goals&lt;/h1&gt;

&lt;p&gt;If your colleague wants to learn about the experiences of online shoppers on your ecommerce site, you need to be able to recognize what goal this represents. It&amp;rsquo;s all in the wording.&lt;/p&gt;

&lt;p&gt;When you hear or say words that identify someone as a person using your service or product, for example &amp;ldquo;shopper&amp;rdquo;, then you know that your goal is to understand how well your solution (or idea) will support that person. You can call these goals solution-focused.&lt;/p&gt;

&lt;p&gt;On the other hand, when you use a word that &amp;nbsp;does not define the way a person interacts with your organization, for example &amp;ldquo;person&amp;rdquo; or &amp;ldquo;human,&amp;rdquo; then your goal is to understand that person&amp;rsquo;s mind and heart. Call these goals person-focused. If you can be deliberate about the wording of your goal, you can be clear about which research method to use to reach that goal.&lt;/p&gt;

&lt;p&gt;You are also probably aware of the two goals for using the knowledge that research will bring:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;evaluate how well something you make works, or&lt;/li&gt;
	&lt;li&gt;generate new improvements or new ideas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are called &quot;evaluative&quot; and &quot;generative&quot; research respectively. When you make a matrix from these two research usage goals and the two internal research goals above, then you can see which methods best support the union of your particular goal at the moment.&lt;/p&gt;

&lt;p&gt;For example, the customer journey map can help you define new ideas to support the customer&amp;nbsp;so it is considered generative. And because you are using the word &amp;ldquo;customer,&amp;rdquo; it is solution-focused. Sometimes professionals use the customer journey map in an evaluative manner, but that is less common.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;http://uxmas.com/images/uploads/Indi_Image_1.png&quot; style=&quot;width:550px;height:308px;&quot;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Clarity about which methods support which of your goals makes it easier for you to know what to do. For example, Steve Portigal&amp;rsquo;s book &lt;strong&gt;Interviewing Users&lt;/strong&gt; describes the solution-focused user interview. Aga Bojko&amp;rsquo;s book &lt;strong&gt;Eye Tracking&lt;/strong&gt; covers this type of evaluative, solution-focused research.&amp;nbsp;&lt;/em&gt;&lt;em&gt;Indi&amp;nbsp;&lt;/em&gt;&lt;em&gt;Young&amp;rsquo;s book &lt;strong&gt;Practical Empathy&lt;/strong&gt; defines how to develop empathy for generative, person-focused work.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;3. Avoid pre-categorizing your results before you get them&lt;/h1&gt;

&lt;p&gt;Many UX professionals accidentally fall into this trap. They may categorize results into three stages: before purchase, during purchase&amp;nbsp;and after purchase. The danger here is that thought processes and emotions do not necessarily span all three of these pre-defined categories.&lt;/p&gt;

&lt;p&gt;This example would be better approached with a single scope from the customer&amp;rsquo;s point of view, such as &amp;ldquo;select the right product for my situation.&amp;rdquo; During a research session with a customer, inevitably the story you hear will hop back-and-forth and intertwine all of your pre-defined stages. Instead of trying to artificially separate them out, concentrate on different themes that the story brings out. For example, you could look for &lt;em&gt;emotions&lt;/em&gt; like doubt, distrust, excitement, impatience, or &lt;em&gt;behaviors&lt;/em&gt;&amp;nbsp;such as&amp;nbsp;asking friends, looking for advice, deciding&amp;nbsp;based on gut, knowing from past experience, etc. These elements will end up defining your categories if you see them appear as patterns across customers.&lt;/p&gt;

&lt;p&gt;***&lt;/p&gt;

&lt;p&gt;So give your research goal the perfect gift this Christmas. Analyse what it is you are doing and who you are doing it for. &amp;nbsp;Don&amp;rsquo;t simply choose the most popular method-du-jour, or your research goal may end up in a corner, the shiny toy that isn&amp;rsquo;t useful and is never played with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indi&amp;#39;s new book &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://rosenfeldmedia.com/books/practical-empathy/&quot;&gt;Practical Empathy&lt;/a&gt; defines how to develop empathy for generative, person-focused work.&amp;nbsp;It&amp;#39;s on pre-order at 30% off until 08-January 2015!&lt;/strong&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false"></guid>
         <pubDate>Sun, 21 Dec 2014 21:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[24ways] Naming Things</title>
         <link>http://feedproxy.google.com/~r/24ways/~3/193fWZh2LYI/</link>
         <description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://paulrobertlloyd.com&quot;&gt;Paul Lloyd&lt;/a&gt; perches his partridge in the &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; pear tree to discuss naming methodologies, ontologies and semantics. What&amp;#8217;s in a name? That which we call a cherub by any other name would smell as sweet.&lt;/p&gt;&lt;div class=&quot;feedflare&quot;&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=193fWZh2LYI:RClF8hISHFg:yIl2AUoC8zA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=yIl2AUoC8zA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=193fWZh2LYI:RClF8hISHFg:7Q72WNTAKBA&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=7Q72WNTAKBA&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=193fWZh2LYI:RClF8hISHFg:V_sGLiPBpWU&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?i=193fWZh2LYI:RClF8hISHFg:V_sGLiPBpWU&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://feeds.feedburner.com/~ff/24ways?a=193fWZh2LYI:RClF8hISHFg:dnMXMwOfBR0&quot;&gt;&lt;img src=&quot;http://feeds.feedburner.com/~ff/24ways?d=dnMXMwOfBR0&quot; border=&quot;0&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/24ways/~4/193fWZh2LYI&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
         <author>feeds@allinthehead.com (Paul Lloyd)</author>
         <guid isPermaLink="false">http://24ways.org/2014/naming-things/</guid>
         <pubDate>Sun, 21 Dec 2014 12:00:00 +0000</pubDate>
      </item>
      <item>
         <title>[perl] Beyond Grep</title>
         <link>http://perladvent.org/2014/2014-12-21.html</link>
         <description>&lt;div class='pod'&gt;&lt;p&gt;Ack is a Perl based command line utility designed to replace &amp;quot;99% uses of grep&amp;quot; which is a fancy way of saying it&amp;#39;s a much smarter version of grep designed to be used at the command line interactively rather than in scripts.&lt;/p&gt;

&lt;h3 id=&quot;The-Advantages-of-Ack&quot;&gt;The Advantages of Ack&lt;/h3&gt;

&lt;p&gt;Whenever I get started on a big new project I need to familiarize myself with the codebase. Typical questions I tend to ask are:&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;Where are the Perl source files?  The JavaScript?  The HTML, etc?&lt;/li&gt;
&lt;li&gt;What files are using this subroutine?  Where is this method defined?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used to use &lt;code&gt;grep -r&lt;/code&gt; to help me with this. But I always found it was searching in the wrong places (Inside my version control files...in big log files and images rather than inside the Perl modules...) And even when it did find the thing I was looking for in files I&amp;#39;d end up staring at the output trying to work out exactly where the bit of the string that matched was.&lt;/p&gt;

&lt;p&gt;Then I discovered &lt;code&gt;ack&lt;/code&gt;. And my life became a lot easier.&lt;/p&gt;



&lt;center&gt;&lt;img&gt;&lt;/center&gt;

&lt;p&gt;At its most basic &lt;code&gt;ack&lt;/code&gt; can be thought of a version of grep that does the right things by default. These include:&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;Highlighting the matched text&lt;/li&gt;
&lt;li&gt;Automatically ignoring common version control, scratch, and temporary files.&lt;/li&gt;
&lt;li&gt;Searching recusively in the current directory by default when a filename isn't passed and it's not being used in a pipe.&lt;/li&gt;
&lt;li&gt;Showling clearly both filenames and line numbers of each match (and optionally column numbers)&lt;/li&gt;
&lt;li&gt;Easily allowing restrictions to seaching particlar types of files&lt;/li&gt;
&lt;li&gt;Using Perl's powerful regular expression engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or to put it another way, this &lt;code&gt;grep&lt;/code&gt;:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;br /&gt;6:&amp;nbsp;&lt;br /&gt;7:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synStatement&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--exclude-dir&lt;/span&gt; .git &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;--include&lt;/span&gt; *.pl &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;--include&lt;/span&gt; *.pm &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;--include&lt;/span&gt; *,pod &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;--include&lt;/span&gt; *.t &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;--include&lt;/span&gt; *.psgi &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synSpecial&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;(foo|bar)&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; .&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Could be better written as this &lt;code&gt;ack&lt;/code&gt;:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;--perl&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;(foo|bar)&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;(And &lt;code&gt;ack&lt;/code&gt; will also do highlighting of match and group matches within a file together in a readable form!)&lt;/p&gt;

&lt;h3 id=&quot;Ack-file-types&quot;&gt;Ack file types&lt;/h3&gt;

&lt;p&gt;One of the great advantages in using ack is that ability to only search files that of a particular type. In addition to the large range of built in types you can easily add a specification for your own types to &lt;code&gt;ack&lt;/code&gt; or modify existing files by using extra command line arguments.&lt;/p&gt;

&lt;p&gt;For example, several places I have worked have had their own template system that can contain embedded Perl code, but because these files don&amp;#39;t use the standard Perl extensions of &lt;code&gt;.pl&lt;/code&gt;,&lt;code&gt;.pm&lt;/code&gt;,&lt;code&gt;.pod&lt;/code&gt;, &lt;code&gt;.t&lt;/code&gt;, or &lt;code&gt;.psgi&lt;/code&gt;, nor start with a perl shebang line, ack invoked with &lt;code&gt;--perl&lt;/code&gt; won&amp;#39;t search them. I&amp;#39;d like ack to search within the &lt;code&gt;.perlt&lt;/code&gt; files also. This can be done by adding another option to &lt;code&gt;ack&lt;/code&gt;:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;--type-add=perl:ext:perlt&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--perl&lt;/span&gt; foo&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Of course typing this every time I ran &lt;code&gt;ack&lt;/code&gt; would be extremely tiresome. For this reason I copy this arguments into my &lt;code&gt;.ackrc&lt;/code&gt; where &lt;code&gt;ack&lt;/code&gt; reads them in each time ack is invoked so I always have my perlt search available.&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synStatement&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt; &lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;--type-add=perl:ext:perlt&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt; &lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ackrc&lt;br /&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;--perl&lt;/span&gt; foo&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&amp;#39;re not limited to file extensions here; For example, I can tell ack that any file that starts with &lt;code&gt;{&lt;/code&gt; on the first line should be considered JSON:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;ack &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;--type-add=json:firstlinematch:/^&amp;#92;s*&amp;#92;{/&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--json&lt;/span&gt; foo&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&quot;Ack-power-use&quot;&gt;Ack power use&lt;/h3&gt;

&lt;p&gt;The above should probably be enough to convince you to switch to using ack on a day to day basis for interactive file grepping. But what about some of the really crazy powerful things you can do with ack?&lt;/p&gt;

&lt;h4 id=&quot;Find-all-files-of-a-particular-type&quot;&gt;Find all files of a particular type&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ack&lt;/code&gt; is pretty smart about working out what files it should ignore, including things like version control files, editor backup files, and even things like minified versions of JavaScript.&lt;/p&gt;

&lt;p&gt;This makes it a good choice for simply getting a list of particular files of a given type in a project:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synComment&quot;&gt;# find all un-minified JavaScript files in your file tree&lt;/span&gt;&lt;br /&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--js&lt;/span&gt;&lt;br /&gt;bootstrap/js/bootstrap.js&lt;br /&gt;js/main.js&lt;br /&gt;js/jquery.js&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;(This uses &lt;code&gt;-f&lt;/code&gt; to just print the filename that would be searched rather than actually searching the file and &lt;code&gt;--js&lt;/code&gt; to specify that we want JavaScript extensions)&lt;/p&gt;

&lt;p&gt;Once you&amp;#39;ve got a list of files like this you can start doing interesting things with them by using utilities like &lt;code&gt;xargs&lt;/code&gt;:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synComment&quot;&gt;# delete all php code!&lt;/span&gt;&lt;br /&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--php&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--print0&lt;/span&gt; | xargs &lt;span class=&quot;synConstant&quot;&gt;-0&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-f&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This works the same as the previous example but uses the &lt;code&gt;--print0&lt;/code&gt; argument to &lt;code&gt;ack&lt;/code&gt; and &lt;code&gt;-0&lt;/code&gt; argument to &lt;code&gt;xargs&lt;/code&gt; (so that the two communicate the filenames across the pipe delimited by a null character rather than whitespace preventing problems with filenames with whitespace in their names.)&lt;/p&gt;

&lt;p&gt;Replacing &lt;code&gt;-f&lt;/code&gt; with &lt;code&gt;-l&lt;/code&gt; means we will also search the files with our passed regex, and only list those files that match (but not show how we match like in traditional output.) Combining this with &lt;code&gt;xargs&lt;/code&gt; again we can do even more powerful things:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synComment&quot;&gt;# commit all the code that have &amp;quot;use strict&amp;quot;&lt;/span&gt;&lt;br /&gt;bash$ ack &lt;span class=&quot;synSpecial&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--perl&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;--print0&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; | xargs &lt;span class=&quot;synConstant&quot;&gt;-0&lt;/span&gt; git add&lt;br /&gt;bash$ git commit &lt;span class=&quot;synSpecial&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;add strictures&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h4 id=&quot;Using-ack-to-highlight-things-in-a-file&quot;&gt;Using ack to highlight things in a file&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ack&lt;/code&gt; can be used just to highlight a string in a file. For example, everywhere that &lt;code&gt;$jolly&lt;/code&gt; is used:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;--passthru&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-Q&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;$jolly&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; lib/Santa.pm &lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The &lt;code&gt;--passthru&lt;/code&gt; option tells &lt;code&gt;ack&lt;/code&gt; to display all lines, matching or not. The &lt;code&gt;-Q&lt;/code&gt; tells ack to treat the string we&amp;#39;re highlighting as a literal pattern rather than a regexp.&lt;/p&gt;

&lt;p&gt;We can even use this technique in a tail. For example to highlight the string &amp;quot;Error&amp;quot; in our logfile:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;synStatement&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-n0&lt;/span&gt; &lt;span class=&quot;synSpecial&quot;&gt;-f&lt;/span&gt; /tmp/log | ack &lt;span class=&quot;synSpecial&quot;&gt;--passthru&lt;/span&gt; Error&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;



&lt;center&gt;&lt;img&gt;&lt;/center&gt;

&lt;h4 id=&quot;Custom-Output&quot;&gt;Custom Output&lt;/h4&gt;

&lt;p&gt;Ack allows you to modify the output from the default &lt;i&gt;matching line with match highlighted&lt;/i&gt; output to something custom. If we want to get a list of all the subroutines in our file tree we can easily do that: We search for all the &lt;code&gt;sub &lt;i&gt;something&lt;/i&gt;&lt;/code&gt; but only display the &lt;code&gt;&lt;i&gt;something&lt;/i&gt;&lt;/code&gt; not the leading &lt;code&gt;sub&lt;/code&gt;. By using &lt;code&gt;--output&lt;/code&gt; we can pass a Perl string that ack will &lt;code&gt;eval&lt;/code&gt; after each match and use the result for the output:&lt;/p&gt;



&lt;center&gt;&lt;img&gt;&lt;/center&gt;

&lt;p&gt;With a little imagination this can be used to very powerful things. For example, the size of the URLs mentioned in a file:&lt;/p&gt;



&lt;table class='code-listing'&gt;&lt;tr&gt;&lt;td class='line-numbers'&gt;&lt;br /&gt;&lt;code&gt;1:&amp;nbsp;&lt;br /&gt;2:&amp;nbsp;&lt;br /&gt;3:&amp;nbsp;&lt;br /&gt;4:&amp;nbsp;&lt;br /&gt;5:&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='code'&gt;&lt;br /&gt;&lt;code&gt;ack &lt;span class=&quot;synSpecial&quot;&gt;--output=&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;$&amp;amp;: @{[ eval &amp;quot;use LWP::Simple; 1&amp;quot; &amp;amp;&amp;amp; length LWP::Simple::get($&amp;amp;) ]} bytes&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;synStatement&quot;&gt;&amp;#92;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;synConstant&quot;&gt;https?://&amp;#92;S+&lt;/span&gt;&lt;span class=&quot;synStatement&quot;&gt;'&lt;/span&gt; list.txt&lt;br /&gt;http://google.com/: &lt;span class=&quot;synConstant&quot;&gt;19529&lt;/span&gt; bytes&lt;br /&gt;http://metacpan.org/: &lt;span class=&quot;synConstant&quot;&gt;7560&lt;/span&gt; bytes&lt;br /&gt;http://www.perladvent.org/: &lt;span class=&quot;synConstant&quot;&gt;5562&lt;/span&gt; bytes&lt;/code&gt;&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;However the smartest thing I&amp;#39;ve ever used the custom output for is to generate lines that look just like Perl error messages:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   ack --no-filename --no-group &amp;#92;
       --output &amp;#39;at $filename line $line_no$/$line$/&amp;#39; &amp;#92;
       &amp;#39;sub new&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why is this so helpful? Because I use the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/2shortplanks/PerlErrorSublime.popclipext&quot;&gt;PerlErrorSublime.popclipext&lt;/a&gt; PopClip extension to allow me to highlight any perl-error like string in my terminal and open that line in Sublime Text:&lt;/p&gt;



&lt;center&gt;&lt;img&gt;&lt;/center&gt;

&lt;h3 id=&quot;Conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Hopefully I&amp;#39;ve convinced you now not only that ack can be used as a basic replacement for grep, but also there&amp;#39;s some very formidable things you can do with it if you take a little time to learn some of the more powerful options.&lt;/p&gt;

&lt;h2 id=&quot;See-Also&quot;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://metacpan.org/module/App::ack&quot;&gt;App::ack&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beyondgrep.com/&quot;&gt;http://beyondgrep.com/&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</description>
         <author>Mark Fowler</author>
         <guid isPermaLink="false">http://perladvent.org/2014/2014-12-21.html</guid>
         <pubDate>Sun, 21 Dec 2014 05:00:00 +0000</pubDate>
      </item>
   </channel>
</rss>
<!-- fe6.yql.bf1.yahoo.com compressed/chunked Thu Oct  1 21:00:12 UTC 2015 -->
