<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Sean Glover</title>
    <description>Open Source Software Engineer
</description>
    <link>https://seanglover.com/</link>
    <atom:link href="https://seanglover.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 27 Nov 2025 20:05:57 +0000</pubDate>
    <lastBuildDate>Thu, 27 Nov 2025 20:05:57 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>How Alpakka Uses Flow Control Optimizations In Apache Kafka 2.4</title>
        <description>&lt;h4 id=&quot;original-post-on-lightbends-blog-archived-pdf&quot;&gt;&lt;a href=&quot;https://www.lightbend.com/blog/alpakka-kafka-flow-control-optimizations&quot;&gt;Original post on Lightbend’s blog&lt;/a&gt;, &lt;a href=&quot;/assets/How%20Alpakka%20Uses%20Flow%20Control%20Optimizations%20In%20Apache%20Kafka%202.4%20_%20Lightbend.pdf&quot;&gt;Archived PDF&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;This blog post begins with details about how the Kafka Consumer and &lt;a href=&quot;https://github.com/akka/alpakka-kafka&quot;&gt;Alpakka Kafka&lt;/a&gt; internals are designed to facilitate asynchronous polling and back-pressure. We’ll discuss how the Consumer’s flow control mechanisms were improved in &lt;a href=&quot;https://issues.apache.org/jira/browse/KAFKA-7548&quot;&gt;KAFKA-7548&lt;/a&gt; to provide better performance. We conclude with some benchmarks that demonstrate the performance improvements before and after the new Consumer is used.&lt;/p&gt;
</description>
        <pubDate>Sun, 26 Jan 2020 00:00:00 +0000</pubDate>
        <link>https://seanglover.com/blog/2020/01/alpakka-kafka-using-kafka-240-flow-control-improvements/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2020/01/alpakka-kafka-using-kafka-240-flow-control-improvements/</guid>
        
        <category>alpakka</category>
        
        <category>kafka</category>
        
        <category>akka-streams</category>
        
        
        <category>Alpakka Kafka</category>
        
        <category>Apache Kafka</category>
        
        <category>Akka Streams</category>
        
      </item>
    
      <item>
        <title>Monitor Kafka Consumer Group Latency with Kafka Lag Exporter</title>
        <description>&lt;h4 id=&quot;original-post-on-lightbends-blog-archived-pdf&quot;&gt;&lt;a href=&quot;https://www.lightbend.com/blog/monitor-kafka-consumer-group-latency-with-kafka-lag-exporter&quot;&gt;Original post on Lightbend’s blog&lt;/a&gt;, &lt;a href=&quot;/assets/Monitor%20Kafka%20Consumer%20Group%20Latency%20with%20Kafka%20Lag%20Exporter%20_%20Lightbend.pdf&quot;&gt;Archived PDF&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;A blog post introducing &lt;a href=&quot;https://github.com/lightbend/kafka-lag-exporter&quot;&gt;Kafka Lag Exporter&lt;/a&gt;, a tool to make it easy to view consumer group metrics using Kubernetes, Prometheus, and Grafana. Kafka Lag Exporter can run anywhere, but it provides features to run easily on Kubernetes clusters against Strimzi Kafka clusters using the Prometheus and Grafana monitoring stack.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate>
        <link>https://seanglover.com/blog/2019/05/monitor-kafka-consumer-group-latency-and-lag/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2019/05/monitor-kafka-consumer-group-latency-and-lag/</guid>
        
        <category>kafka-lag-exporter</category>
        
        <category>kafka</category>
        
        <category>strimzi</category>
        
        <category>kubernetes</category>
        
        <category>grafana</category>
        
        <category>monitoring</category>
        
        
        <category>Kafka Lag Exporter</category>
        
        <category>Apache Kafka</category>
        
        <category>Helm</category>
        
        <category>Strimzi</category>
        
        <category>Kubernetes</category>
        
      </item>
    
      <item>
        <title>Exactly Once Streams - Exactly Once Streaming in Kafka</title>
        <description>&lt;h4 id=&quot;link-to-report-on-github&quot;&gt;&lt;a href=&quot;https://github.com/seglo/exactly-once-streams/blob/master/README.md&quot;&gt;Link to report on GitHub&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;An engineering report and a set of PoC’s that demonstrate “Exactly Once” message delivery semantics in &lt;a href=&quot;https://kafka.apache.org/&quot;&gt;Apache Kafka&lt;/a&gt; using Kafka base clients, Kafka Streams, and &lt;a href=&quot;https://doc.akka.io/docs/alpakka-kafka/current/home.html&quot;&gt;Alpakka Kafka&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Sun, 16 Jul 2017 00:00:00 +0000</pubDate>
        <link>https://seanglover.com/blog/2017/07/exactly-once-streams/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2017/07/exactly-once-streams/</guid>
        
        <category>kafka</category>
        
        <category>streams</category>
        
        <category>alpakka</category>
        
        <category>report</category>
        
        
        <category>Apache Kafka</category>
        
        <category>Streaming</category>
        
        <category>Exactly Once</category>
        
      </item>
    
      <item>
        <title>Technology and Politics - David Graham</title>
        <description>&lt;p&gt;This week I was proud to learn that &lt;a href=&quot;https://en.wikipedia.org/wiki/David_de_Burgh_Graham&quot;&gt;David de Burge Graham&lt;/a&gt; was elected as a Member of Parliament of Quebec Canada’s Laurentides–Labelle riding. As far as I know, David is one of our country’s first real technology enthusiasts in the house of commons.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/davidelected.png&quot; alt=&quot;David Graham&quot; style=&quot;width:400px;border:1px solid&quot; /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.cbc.ca/news2/interactives/results-2015/&quot;&gt;CBC 2015 Interactive Election Results&lt;/a&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;I met David online nearly 8 years ago. Like many of my peers in technology, I grew up in the 90’s during the Personal Computing revolution.  I’ve met thousands of people online through a text-only chat technology known as Internet Relay Chat (IRC).  Some of those people I went on to meet in person, but for the most part my digital and “meatspace” life have remained separate.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/oftc.png&quot; alt=&quot;OFTC - Open and Free Technology Community&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;In 2007 I became a Network Representative for the &lt;a href=&quot;http://www.oftc.net/&quot;&gt;Open and Free Technology Community (OFTC)&lt;/a&gt;.  I made a number of new online friends of the OFTC staff.  At the time David was &lt;a href=&quot;http://www.oftc.net/ElectionResults/2008/&quot;&gt;recently elected as Ombudsman&lt;/a&gt; of the network and when he found out I was a fellow Canadian we began getting to know one another.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/debian_linux_spi.png&quot; alt=&quot;Debian, SPI, Linux&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;When I joined OFTC’s staff I learned a little about David’s history.  I’ll leave it for someone else who was closer to David during this time to tell the story in detail, but I can summarize.  He was a core member of the OFTC community since its beginnings in the early 2000’s.  He was elected as chairman a number of times in OFTC’s yearly staff elections.  He’s known as cdlu on OFTC (a Canadian Debian Linux User), and is still involved with the network in an advisory capacity.&lt;/p&gt;

&lt;p&gt;David’s a command line jockey.  Many of his websites ran on a web framework he created using nothing more than the filesystem and bash scripts!  He was employed as an editor for &lt;a href=&quot;http://www.linux.com/&quot;&gt;Linux.com&lt;/a&gt; for a number of years and he was a regular in the official IRC channel for the Debian Linux distribution. David has held senior positions with the &lt;a href=&quot;http://www.spi-inc.org/&quot;&gt;Software in the Public Interest (SPI)&lt;/a&gt; organization.  SPI was created to help other organizations (such as OFTC and Debian) develop and distribute open hardware and software.  In short, David gets Linux and the merits of free software.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;a href=&quot;https://xkcd.com/1181/&quot;&gt;
&lt;img src=&quot;/assets/pgp.png&quot; style=&quot;border:0&quot; /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;small&gt;&lt;i&gt;If you want to be extra safe, check that there&apos;s a big block of jumbled characters at the bottom.&lt;/i&gt;&lt;/small&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;I’ve only met David once in meatspace.  At the time he was living in Guelph and needed to take a trip to Toronto.  We met at a local pub called the &lt;a href=&quot;http://www.thebistros.ca/&quot;&gt;Bistro on Avenue&lt;/a&gt; and enjoyed a dish of nachos and wings.  During the meeting we took the opportunity to expand our &lt;a href=&quot;https://www.gnupg.org/&quot;&gt;GPG&lt;/a&gt; web of trust by signing each others public encryption key.  What is GPG you ask?  Well, it’s a way to securely communicate with someone over the Internet.  Each person generates their own public and private key.  When you want to send a message to someone else, that only the recipient can read, you encrypt the message with your private key and the recipients public key.&lt;/p&gt;

&lt;p&gt;One problem with this process is that at the end of the day you still don’t know if the recipient of your message is who they say they are.  Establishing a “web of trust” is a way for people to validate each others identity.  Typically two individuals will meet in person with their printed public keys and proof of identity.  Then from that point forward you can trust that the person who’s key you signed will be the only recipient of your message, assuming their private key is never compromised.  This may hurt my geek cred slightly, but to this day, David is the only person I’ve properly validated identity with for GPG.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/seriesoftubes.jpg&quot; alt=&quot;The Internet, it&apos;s a series of tubes!&quot; style=&quot;width:350px&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;If you’re a technologist like me then you really cringe when you see politicians bungle a technology issue. Whether it’s comparing the &lt;a href=&quot;http://knowyourmeme.com/memes/series-of-tubes&quot;&gt;internet to a series of tubes&lt;/a&gt; or thinking open source will hurt commercial interests, there are plenty of examples of technology issues that are handled poorly by politicians. The root cause of this is of course ignorance of how technology works. With technology ruling nearly every facet our lives, this ignorance can have serious consequences for our society.  Many politicians are alarmingly impressionable by biased parties, such as lobbyists paid for by capitalistic entities looking out for their own best interests. I have high hopes that David, already a technology enthusiast, will be able implicitly understand many technology issues and help advise his colleagues accordingly.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/david1.jpg&quot; alt=&quot;David Graham&quot; style=&quot;text-align: center;border:1px solid&quot; /&gt;
&lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;David and I aren’t really close, but I consider him a friend.  I was really proud of him when he started working in politics and I gave him my support when he ran for office in the 2015 election.  You’re not going to find many people like him in office.  Not only does he understand and embrace technology, but he’s an advocate for free and open source software.  He knows how to use a Linux command line and he has some experience in programming.  Now that he’s an elected official I hope that he continues to champion open technology initiatives at the highest levels of government.  I encourage fellow Canadian technology enthusiasts to write to David to congratulate him on his victory.. and if you ever get a chance to meet him in person, make sure to bring along some ID and your public key to join his web of trust!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pgp.mit.edu/pks/lookup?op=vindex&amp;amp;search=0x851A0EA9D5F45889&quot;&gt;You’ll find David’s public key below&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: pgp.mit.edu

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
=Mr30
-----END PGP PUBLIC KEY BLOCK-----
&lt;/pre&gt;
</description>
        <pubDate>Thu, 22 Oct 2015 09:00:52 +0000</pubDate>
        <link>https://seanglover.com/blog/2015/04/tech-and-politics-david-graham/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2015/04/tech-and-politics-david-graham/</guid>
        
        <category>politics</category>
        
        <category>technology</category>
        
        <category>canada</category>
        
        <category>david graham</category>
        
        
        <category>Politics</category>
        
        <category>Technology</category>
        
        <category>Canada</category>
        
      </item>
    
      <item>
        <title>New features in connect-prism 0.4.0</title>
        <description>&lt;p&gt;Prism has had an abundance of new features since I first released it about a month ago.  This post discusses the rationale behind some of those features as well as a peak of &lt;a href=&quot;#roadmap&quot;&gt;what&apos;s next&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Prism is a library to record, mock, and proxy HTTP traffic.  Check out my &lt;a href=&quot;http://randonom.com/blog/2014/06/record-mock-and-proxy-http-requests-with-grunt-connect-prism/&quot;&gt;previous post to learn more&lt;/a&gt; about its core functionality.  Also checkout the github repo&apos;s for &lt;a href=&quot;https://github.com/seglo/connect-prism&quot;&gt;connect-prism&lt;/a&gt;, &lt;a href=&quot;https://github.com/seglo/grunt-connect-prism&quot;&gt;grunt-connect-prism&lt;/a&gt;, and &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism-sample-project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;New features:&lt;/p&gt;
&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#gulp&quot;&gt;gulp support &amp;amp; core library usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#delay&quot;&gt;delay - simulate real world latency for mocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#404&quot;&gt;404 stubbing - create mocks for endpoints that don&apos;t exist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rewrite&quot;&gt;URL rewriting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mockrecord&quot;&gt;mock &amp;amp; record mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;gulp&quot;&gt;gulp&lt;/h2&gt;
&lt;p&gt;Prism started out as a grunt plugin, but shortly after its début I started receiving requests for a gulp equivalent.  Not having much experience with gulp I investigated how to develop gulp plugins and eventually discovered their &lt;a href=&quot;https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/guidelines.md&quot;&gt;writing a plugin guidelines&lt;/a&gt;.  It&apos;s a really interesting read.  The gulp community is a lot more strict about what makes a good plugin than the grunt community.  Among various suggestions, requests, and outright demands, the number 1 requirement on their list is:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Your plugin should not do something that can be done easily with an existing node module.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;If you&apos;re familiar with grunt this should strike a chord as there are thousands of grunt plugins that do nothing but wrap existing functionality of a core library.  Whether this was intended from grunt&apos;s beginnings or not, I&apos;m not sure, but one positive that has come out of it is that it has opened the door for less nodejs savvy developers to use popular libraries within their grunt configuration.&lt;/p&gt;
&lt;p&gt;The gulp community appears to pride itself on its succinctness of a deployment pipeline through their file streaming operations.  If your plugin isn&apos;t specifically integrating something else into the streaming pipline then it has no business being a plugin in the first place.&lt;/p&gt;
&lt;p&gt;This inspired me to factor out the core functionality of grunt-connect-prism into a new simple to use core library called &lt;a href=&quot;https://github.com/seglo/connect-prism&quot;&gt;connect-prism&lt;/a&gt;.  I&apos;ve updated my &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism sample project&lt;/a&gt; to include &lt;a href=&quot;https://github.com/seglo/prism-sample-project/blob/master/gulpfile.js&quot;&gt;an example of its usage within a gulpfile.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To use with gulp you simply add the prism middleware to your connect declaration and then instantiate 1 or more instances of prism.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prism&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connect-prism&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connect-livereload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35729&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prism&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.tmp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/bower_components&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./bower_components&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
 
&lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listening&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Started connect web server on http://localhost:9000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
 
&lt;span class=&quot;nx&quot;&gt;prism&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9090&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rewrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;^/api/bookauthors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api/authors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;delay&quot;&gt;delay&lt;/h2&gt;
&lt;p&gt;The delay option is 1 of 2 features contributed by &lt;a href=&quot;https://github.com/MilosMosovsky&quot;&gt;Miloš Mošovský&lt;/a&gt;.  In many cases you probably want to use prism to eliminate latency of your API, but in some cases it&apos;s useful to see how your app behaves when it exists.  The delay option has several different options that let you generate this delay when you mock requests.&lt;/p&gt;
&lt;p&gt;You can define a time in milliseconds or choose one of three modes that generates random delays within a range.  To learn more about how to configure this feature see the &lt;a href=&quot;https://github.com/seglo/connect-prism#delay&quot;&gt;delay option&lt;/a&gt; section in the connect-prism README.&lt;/p&gt;
&lt;p&gt;In the prism sample project I use the &apos;auto&apos; mode of delay which will generate random delays between 500 and 1,750 milliseconds.  Below is a screenshot of the chrome debugger&apos;s network tab showing the 3 calls made to prism.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/assets/connect-prism-delay.png&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-473&quot; src=&quot;/assets/connect-prism-delay.png&quot; alt=&quot;connect-prism-delay&quot; width=&quot;857&quot; height=&quot;416&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;404&quot;&gt;404 stubbing&lt;/h2&gt;
&lt;p&gt;The second feature by Milos enables prism to generate stubs in your mocks directory when you&apos;re in &lt;strong&gt;mock&lt;/strong&gt; mode (in record mode it would simply record a 404 response from your server).  If your API doesn&apos;t have an endpoint implemented then prism will create a hashed file like it normally does, but the file will have a .404 extension and will have an empty data property value.  If you choose to use the mock then customize the response data, status code, and content type (but NOT the request URL).  To use the mock just drop the .404 file extension so it&apos;s in the standard requestHash.json filename format.&lt;/p&gt;
&lt;p&gt;If you keep an eye on the STDOUT you&apos;ll see that prism lets you know when it creates a 404 stub:&lt;/p&gt;
&lt;pre&gt;Serialized empty 404 response for /api/newendpoint to mocks/serve/d36d19f9d90fa6e1fc1755463d7c3a70616539af.json.404&lt;/pre&gt;
&lt;p&gt;This lets you know which file to inspect in your mocks directory:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;seglo@bit:~/source/prism-sample-project&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;mocks/serve/
0b956737b1a9660f2c555f9328db1191f6f2a050.json
2723f866830446c640c9cc9942fed2988e0a2c1a.json
6654ad4d1d494222ce02c656386e6955575c17ed.json
d36d19f9d90fa6e1fc1755463d7c3a70616539af.json.404
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Default state of the .404 file.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;requestUrl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/api/newendpoint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;application/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;rewrite&quot;&gt;URL rewriting&lt;/h2&gt;
&lt;p&gt;This is your standard, run of the mill URL rewriting functionality. It was copied in wholesale from the grunt-connect-proxy plugin. When a request matches a context that prism is configured for then it will modify the request URL to the matched URL replacement.&lt;/p&gt;
&lt;p&gt;This could be useful for rerouting many same requests to one mock. For example, since prism creates and matches mocks given a whole request URL, if you have query parameters they are included as part of the hash. To ignore all query parameters to /api/authors you could create a rewrite rule like the following.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;rewrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;^/api/authors&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;??.*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api/authors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;mockrecord&quot;&gt;Mock &amp;amp; Record mode&lt;/h2&gt;
&lt;p&gt;While in record you may not always record every request you intended to. If you miss a use case then while you&apos;re in mock mode it will simply return 404&apos;s (and create stubs as mentioned above) when there may well be a valid endpoint it could have used. I created a new mode you can run the plugin that combines both mocking and recording.&lt;/p&gt;
&lt;p&gt;When prism intercepts a request it will first check if a mock response exists. If it does not, instead of the usual behaviour of stubbing out a response it will attempt to proxy &amp;amp; record the response from your actual server.&lt;/p&gt;
&lt;p&gt;This is useful while developing if you&apos;ve want to move to a new area of development (that triggers new requests) without switching to and from record mode.&lt;/p&gt;
&lt;p&gt;It&apos;s also helpful to use during automated testing so you don&apos;t have to remember to record mocks every time new tests are added to your suite; the next test run will generate them and then subsequent test runs will use the mocks.&lt;/p&gt;
&lt;p&gt;This mode can be used with the &apos;mockrecord&apos; setting for the &apos;mock&apos; property of the configuration. See the &lt;a href=&quot;https://github.com/seglo/connect-prism#mode&quot;&gt;mode setting&lt;/a&gt; in the connect-prism README for more details.&lt;/p&gt;
&lt;h1 id=&quot;roadmap&quot;&gt;What&apos;s next?&lt;/h1&gt;
&lt;h2&gt;Runtime configuration override&lt;/h2&gt;
&lt;p&gt;This is a candidate feature request submitted by &lt;a href=&quot;https://github.com/cthrax&quot;&gt;Myles Bostwick&lt;/a&gt; several days ago.  Myles proposed a feature where you could override the options of prism at run time with custom HTTP headers.  This would allow you to override options like the prism name to use (i.e. in VCR-speak, use another cassette) in order to test a different response.  This would be useful in test suites where you want to test how your app behaves under several different use cases, but not have to restart your test server or prism to do it.&lt;/p&gt;
&lt;h1&gt;Keep the suggestions coming&lt;/h1&gt;
&lt;p&gt;Since releasing this library it&apos;s been enhanced extensively through pull requests and suggestions from the community.  I&apos;m not really sure where it&apos;s headed.  This is my first forray into open source worth mentioning and I&apos;m thrilled by the feedback I&apos;m receiving.&lt;/p&gt;
</description>
        <pubDate>Mon, 14 Jul 2014 01:57:16 +0000</pubDate>
        <link>https://seanglover.com/blog/2014/07/new-features-in-connect-prism-0-4-0/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2014/07/new-features-in-connect-prism-0-4-0/</guid>
        
        <category>delay</category>
        
        <category>grunt</category>
        
        <category>gulp</category>
        
        <category>mocking</category>
        
        <category>prism</category>
        
        
        <category>connect-prism</category>
        
        <category>Grunt</category>
        
        <category>Node.js</category>
        
        <category>User Acceptance Testing</category>
        
      </item>
    
      <item>
        <title>Record, mock, and proxy HTTP requests with grunt-connect-prism</title>
        <description>&lt;img width=&quot;636&quot; height=&quot;227&quot; src=&quot;/assets/prism.jpg&quot; class=&quot;attachment-post-thumbnail wp-post-image&quot; alt=&quot;Not actually a prism, LOL.&quot; border=&quot;0&quot;&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;EDIT 26/6/14: I&apos;ve had a lot of great feedback from everyone.  &lt;a href=&quot;https://github.com/seglo/grunt-connect-prism/issues/2&quot;&gt;Gulp support is in experimental mode right now&lt;/a&gt;, but if there&apos;s anything else you would like to see then I encourage you to post an issue on &lt;a href=&quot;https://github.com/seglo/grunt-connect-prism/issues&quot;&gt;my repo&apos;s issue tracker&lt;/a&gt;.  Thanks everyone! :)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/seglo/grunt-connect-prism&quot;&gt;grunt-connect-prism&lt;/a&gt; is a new grunt plugin I&apos;ve written to help make developing a Single Page Application (SPA) easier. If you&apos;re a RoR aficionado then you&apos;ve probably heard of the project &lt;a href=&quot;https://github.com/vcr/vcr&quot;&gt;VCR&lt;/a&gt;, which is the inspiration for Prism.&lt;/p&gt;
&lt;p&gt;The purpose of this plugin is to provide an easy way for you to record HTTP responses returned by your backend API (or some other remote web resource).  After recording you can then replay the responses when requested and disconnect from the actual backend.  It allows you to work independently of the backend.  It&apos;s like an HTTP cache that persists cached responses to the disk and is only active when you explicitly turn it on.&lt;/p&gt;
&lt;p&gt;I&apos;ve written a sample project that uses the &lt;a href=&quot;https://github.com/seglo/grunt-connect-prism&quot;&gt;grunt-connect-prism&lt;/a&gt; project. The rest of this blog post will cite examples that are demonstrated in &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism-sample-project&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why would I want to use it?&lt;/h2&gt;
&lt;h3&gt;Speed up development time&lt;/h3&gt;
&lt;p&gt;Prism is most useful for mocking complex &amp;amp; high latency API calls during development.  Setting up a full stack for your web app can be costly and time consuming.  The backend introduces a number of different variables to your development practices.  In extreme cases, you may not even host it locally or have access to change anything.  Having a way to record &amp;amp; mock calls to the backend can eliminate a lot of troubleshooting cycles and complexity from your development of a modern front end Single Page Application.&lt;/p&gt;
&lt;h3&gt;Speed up client side end to end and integration tests&lt;/h3&gt;
&lt;p&gt;Instead of taking the time to setup mocking infrastructure on your front end you can simply record 3rd party calls your e2e testsuite makes and then mock them out during future test runs.  This allows you to avoid the complexity of testing a fully integrated application.  It makes your test suite less brittle and has the potential to speed up test runs tremendously.&lt;/p&gt;
&lt;h2&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;Prism works by adding a middleware for the &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-connect&quot;&gt;grunt-contrib-connect&lt;/a&gt; plugin.  It operates in much the same manner as &lt;a href=&quot;https://github.com/drewzboto/grunt-connect-proxy&quot;&gt;grunt-connect-proxy&lt;/a&gt;, in fact by default it works the exact same way and lets you proxy traffic through your development connect server.&lt;/p&gt;
&lt;p&gt;While in record mode you perform all the actions that trigger requests to your backend that you would like to record responses for. In record mode prism acts as proxy, but with the added capability of recording the proxied response. Prism will capture the request URL, including query parameters, content type, HTTP response status, and the data itself.  If the response type happens to be JSON then it will pretty print it in the response file for easier inspection.  For any other content-type it will fallback to a string.&lt;/p&gt;
&lt;p&gt;An example response file in &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism-sample-project&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;./mocks/serve/6654ad4d1d494222ce02c656386e6955575c17ed.json&lt;/pre&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;requestUrl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/api/users&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;application/json; charset=utf-8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;john&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fave_genre&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;science fiction&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last_book_purchased&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;the light of other days&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;genevieve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fave_genre&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fantasy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last_book_purchased&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;game of thrones: a dance with dragons&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;zach&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fave_genre&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;non-fiction&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last_book_purchased&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;freakonomics&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The filename is a SHA1 hash of the request URL in order to [almost] guarantee a unique filename for easy lookup in the future. After recording some responses you can switch to mock prism mode. When you launch your application and begin making the same requests you did before then instead of proxying your request, prism will intercept it, hash the request URL, and attempt to find a matching response in the appropriate directory. &lt;/p&gt;
&lt;p&gt;If a response file can&apos;t be found then a 404 will be returned.&lt;/p&gt;
&lt;h2&gt;How do I use it in development?&lt;/h2&gt;
&lt;p&gt;The project homepage discusses pre-requisites and configuration in detail, but I&apos;ll summarize below. You must be using the &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-connect&quot;&gt;grunt-contrib-connect&lt;/a&gt; plugin. If you use the Yeoman Angular.js generator (&lt;a href=&quot;https://github.com/yeoman/generator-angular&quot;&gt;generator-angular&lt;/a&gt;) then this has already been done for you. Install the latest grunt-connect-prism package from NPM&lt;/p&gt;
&lt;pre&gt;npm install grunt-connect-prism --save-dev&lt;/pre&gt;
&lt;p&gt;Add the middleware to the appropriate target in your Gruntfile.js connect configuration section.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Change this to &apos;0.0.0.0&apos; to access the server from outside.&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;livereload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35729&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;livereload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;grunt-connect-prism/lib/events&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handleRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.tmp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/bower_components&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./bower_components&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Next create a prism configuration object. You must specify a context of your server that prism will listen for requests on. Ex) http://localhost:9000/api/ would be the context of /api. You must specify the hostname, port, scheme configuration of where this resource is actually located. This constitutes the minimum configuration required to get up and running. Below is taken from the &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism-sample-project&lt;/a&gt;. For a full example see &lt;a href=&quot;https://github.com/seglo/prism-sample-project/blob/master/Gruntfile.js&quot;&gt;that projects Gruntfile.js&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;prism&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* optional */&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mocksPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./mocks&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* optional */&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;localhost&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9090&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* optional */&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* optional */&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;e2e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Inject prism into your serve call. This is a modified version of what the yeoman &lt;a href=&quot;https://github.com/yeoman/generator-angular&quot;&gt;generator-angular&lt;/a&gt; creates for you.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Compile then start a connect web server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;prism:serve&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clean:server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;wiredep&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;concurrent:server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;autoprefixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;express:api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* my example backend server running on port 9090 */&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connect:livereload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The prism task can be called like any other grunt plugin: {pluginName}:{target}. Prism has an extra argument called &quot;mode&quot;. This optional argument allows you to specify the prism mode without having to reconfigure the prism configuration in the Gruntfile.js each time. In the case of the above example, when you run `grunt serve` it will run the prism:serve target by default. If you have not configured this prism target&apos;s mode then it will default to proxy.&lt;/p&gt;
&lt;pre&gt;grunt serve&lt;/pre&gt;
&lt;p&gt;To enter a different mode then simply pass in the appropriate mode value when you call grunt serve.&lt;/p&gt;
&lt;pre&gt;grunt serve:record
grunt serve:mock&lt;/pre&gt;
&lt;h2&gt;How do I use it with end to end testing?&lt;/h2&gt;
&lt;p&gt;Using prism for end to end testing involves much the same configuration as for development. You must add the middleware to the connect target you&apos;re using in e2e testing (i.e. connect:test) then call the prism task when you execute your e2e tests.&lt;/p&gt;
&lt;p&gt;For this example I&apos;m using &lt;a href=&quot;https://github.com/angular/protractor&quot;&gt;protractor&lt;/a&gt;, &lt;a href=&quot;https://github.com/teerapap/grunt-protractor-runner&quot;&gt;grunt-protractor-runner&lt;/a&gt; (installed with prism-sample-project), and the standalone selenium server to run my e2e tests for my Angular.js project. I created a custom task to launch my tests with grunt.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;e2e&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Run end to end tests&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;prism:e2e&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;:mock&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
  &lt;span class=&quot;c1&quot;&gt;// start the backend API if we&apos;re in record or proxy mode. this is probably&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// not applicable if you don&apos;t launch your backend server with grunt&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prismMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;express:api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clean:server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;wiredep&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;concurrent:server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;autoprefixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prismTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connect:test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;protractor:e2e&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The e2e task is configured to mock responses when you run `grunt e2e`. &lt;/p&gt;
&lt;pre&gt;grunt e2e&lt;/pre&gt;
&lt;p&gt;In order to record responses, or simply just let your e2e tests proxy to a real server then you can pass the prism mode into the e2e task in the same fashion as with the grunt serve task&lt;/p&gt;
&lt;pre&gt;grunt e2e:record
grunt e2e:proxy&lt;/pre&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;I hope that this blog post in conjunction with the README&apos;s of the plugin and sample project will provide you with enough information to get started with prism. Please see the &lt;a href=&quot;https://github.com/seglo/grunt-connect-prism&quot;&gt;grunt-connect-prism README.md&lt;/a&gt; for more information on the plugin and the &lt;a href=&quot;https://github.com/seglo/prism-sample-project&quot;&gt;prism-sample-project&lt;/a&gt; for a working example.&lt;/p&gt;
&lt;p&gt;This is my first released open source and Node.js project. I would love feedback of any kind (pull requests, ideas, bug reports, critisicms, etc). Thanks!&lt;/p&gt;
</description>
        <pubDate>Mon, 23 Jun 2014 12:15:45 +0000</pubDate>
        <link>https://seanglover.com/blog/2014/06/record-mock-and-proxy-http-requests-with-grunt-connect-prism/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2014/06/record-mock-and-proxy-http-requests-with-grunt-connect-prism/</guid>
        
        <category>grunt</category>
        
        <category>plugin</category>
        
        <category>prism</category>
        
        <category>testing</category>
        
        <category>vcr</category>
        
        
        <category>Grunt</category>
        
        <category>Node.js</category>
        
        <category>Selenium</category>
        
        <category>User Acceptance Testing</category>
        
      </item>
    
      <item>
        <title>Technology Change: .NET to Scala</title>
        <description>&lt;img width=&quot;628&quot; height=&quot;103&quot; src=&quot;/assets/scala_at_empathica2.png&quot; class=&quot;attachment-post-thumbnail wp-post-image&quot; alt=&quot;Scala @ Empathica&quot;&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;In our careers as software developers we&apos;re frequently pigeonholed to one particular language &amp;amp; framework. Often times these specializations go even further and before you know it you&apos;ll find yourself being the front end guy, the datalayer girl, or in my case: the person who gets saddled with anything that has to do with deployment and devops work in general :). This is a story about how Empathica as an organization transformed itself from being a Microsoft .NET shop to a Scala one. It didn&apos;t happen overnight, and this is definitely not a howto guide on how to achieve similar change somewhere else.  If you&apos;re looking for a side by side comparison of Scala and C#/.NET, you won&apos;t find it here.  This is just an account of how the change itself unfolded.  Since a transformation of this kind is thus far unique in my career I wanted to share it with the community and hopefully provide some wisdom for other teams deciding to take a similar plunge into Scala or some other open source technology.&lt;/p&gt;
&lt;h2&gt;The stage&lt;/h2&gt;
&lt;p&gt;Empathica was almost exclusively a Microsoft shop as late as the end of summer 2012. There was some legacy infrastructure in Java, but it had remained largely untouched since the company formed in the early 2000&apos;s. For all intents and purposes, Empathica embraced using Microsoft technologies throughout the entire stack. Everything was written in C#, all servers ran on Windows Server, OLTP and OLAP databases were SQL Server and Analysis Services. It wasn&apos;t until &lt;a title=&quot;Simon Palmer&apos;s blog&quot; href=&quot;http://simonpalmer.com/&quot;&gt;Simon Palmer&lt;/a&gt; joined the company as CTO that anyone in the development department gave the technology stack a hard look. After all, once you&apos;re fully invested in Microsoft it can be quite difficult to break away.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As an aside I would like to mention that in recent years Microsoft has made great strides in supporting the OSS community.  They&apos;ve open sourced large parts of the CLR, open sourced big projects like Entity Framework and ASP.NET MVC, and have even &lt;a href=&quot;http://msopentech.com/blog/2013/10/14/net-team-makes-portable-class-library-pcl-available-platforms/&quot;&gt;provided a portable class library license that can be run on platforms other than Windows&lt;/a&gt;. There are lots of new Microsoft OSS initiatives as indicated by their &lt;a title=&quot;OpenTech Projects&quot; href=&quot;http://msopentech.com/projects/&quot;&gt;OpenTech&lt;/a&gt; division.  However, I think it will still be some time (if ever) that we see widespread support and adoption of Microsoft works into the larger open source community.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When Simon came onboard it represented a sea change for Empathica&apos;s development department. At a higher level it changed the company from being services orientated to products based.  The development process was switched nearly immediately to XP. Consultants were brought in from &lt;a title=&quot;Berteig Consulting&quot; href=&quot;http://www.berteigconsulting.com/&quot;&gt;Berteig Consulting&lt;/a&gt; to help with the transformation. Internal political red tape was cut and development teams were empowered to do their own project planning, track their own progress, and self organize with as little direct supervision from the management team as possible. Members of the development team were encouraged to challenge their existing beliefs about how to build software.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;EDIT 25/10/13: I want to elaborate a bit about when our new CTO came onboard.  At the time, Empathica&apos;s products were stagnant, we were beginning to lose big clients, and something needed to be done.  Simon was brought on to give the company more effective technical direction because up until then there were a few people wearing CTO-type hats, but not one voice in particular.  Simon brought a wealth of software development leadership to the organization.  He&apos;s incredibly tech savvy, a serial entrepreneur, and has a great deal of experience applying Agile practices and principles to large development teams.  One of the first changes Simon made was to bring Agile to Empathica.  It&apos;s my opinion that that change is what set the stage for developers to try new technologies like Scala.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As usually happens with change, it didn&apos;t resonate with everybody. A lot of the existing development staff weren&apos;t too keen on what was happening to the department.  There was a slow exodus of technical staff who left to seek new opportunities. This gave the management team the opportunity to hire a new team of smart and passionate developers, product managers, and user experience people that were onboard with the new direction. It was around this time that I was fortunate to be offered a developer position at Empathica in July 2011.&lt;/p&gt;
&lt;p&gt;The new team was challenged to reimagine our space (Customer Experience Management) by developing a new line of products.  XP gave us lots of flexibility to operate as we saw fit.  Teams were flat; the most junior developer had as much of a voice during an iteration planning session as a veteran of the craft.  I had more input into the development process and product direction at Empathica than I did as a Team Lead and Development Manager in my past positions.  &lt;strong&gt;I credit this open and collaborative culture as the main reason that we were able to try new technologies like Scala in the first place.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Why Scala?&lt;/h2&gt;
&lt;p&gt;Now that the stage is set, I&apos;ll elaborate on what exactly got the ball rolling to try Scala. Before every development project we have a &quot;technology discussion&quot;. We&apos;re always open to trying new things, but for the most part new projects chose a base technology stack of C#, ASP.NET MVC, etc. We kicked off a number of new projects around August of 2012. One of these projects turned into a Scala project that I&apos;ll affectionately refer to as BeetleJuice for the remainder of this post. The kickoff for BeetleJuice started off as a &quot;Hey, wouldn&apos;t be cool if we had something like this to compete with competitor X?&quot; In fact BeetleJuice initial requirements were so scarce we didn&apos;t even know if it would be something we would release to our clients. It was an experiment; a grandiose software spike into an area of the business we never fully explored before. This gave us an enormous amount of liberty to try a new language and framework because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The project wasn&apos;t overly complex&lt;/li&gt;
&lt;li&gt;As with most software spikes there was an implicit permission to fail and to try new things&lt;/li&gt;
&lt;li&gt;At the end of the day it didn&apos;t really matter what language or framework we chose for our application server because of its simple nature&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It was then I challenged the rest of the team to honestly consider other technologies. &quot;This is our chance to try something new. Let&apos;s take it.&quot; I said. Personally, I had had some experience with Python and Django, but I was also interested in Ruby and the Rails framework, so I proposed both. Another colleague tossed Node.js into the ring. And finally, one of our newest hires at the time, &lt;a title=&quot;Steven Skelton&apos;s blog&quot; href=&quot;http://stevenskelton.ca/&quot;&gt;Steven Skelton&lt;/a&gt; proposed Scala.&lt;/p&gt;
&lt;p&gt;I didn&apos;t know much about Scala. I gave myself the weekend to read up on it and I quickly appreciated its elegance and concise syntax. I recognized the opportunity that since it is JVM based we implicitly gained awesome platform interoperability and native OSS library support.  Scala is statically typed, which seemed refreshing to me given the mainstream&apos;s infatuation with dynamic languages like Ruby, Python, and JavaScript over the past 10 years.  It has a reputation as being a great language to write highly performant concurrent systems in.  We were sold and in the next iteration the BeetleJuice team decided to give Scala a try.&lt;/p&gt;
&lt;h2&gt;The experiment&lt;/h2&gt;
&lt;p&gt;We created a &lt;a title=&quot;Play! Framework&quot; href=&quot;http://www.playframework.com/&quot;&gt;Play! 2&lt;/a&gt; web project. It was an easy transition from ASP.NET MVC from a framework perspective.  We started developing BeetleJuice and it wasn&apos;t long before we knew that we could deliver a functioning Scala web application with a minimal hit on productivity.&lt;/p&gt;
&lt;p&gt;Once we began demonstrating our progress at weekly iteration demo&apos;s it became clear that BeetleJuice was evolving out of its experimentation phase and into something that had real business value. When this became apparent, the management team decided to take a closer look at our technology choice and started asking tough questions like &quot;How do we deploy this in a production environment?&quot; and &quot;Will this framework and language be around next year?&quot; and inevitably &quot;Am I going to be able to find people to support this technology in 1, 3, and 5 years?&quot; I started investigating the maturity of Play! and to my delight found that it had an great list of endorsements from tech companies around the world (LinkedIn, Klout, theguardian, to name a few). The Play! 2 framework was still new when we first began using it, but its version 1 had been available to the community for some time. From Play! we soon learned more about the &lt;a title=&quot;Typesafe&quot; href=&quot;http://typesafe.com/&quot;&gt;Typesafe&lt;/a&gt; stack and services. We came to the conclusion that due to Typesafe&apos;s inclusion of Play! into its stack and the successful history of the project itself, that we had picked a winner.&lt;/p&gt;
&lt;p&gt;It was also becoming clear that Scala was being heavily adopted in the industry based on data from job sites like Indeed.com, Typesafe&apos;s impressive client list, the number of native Scala OSS projects available, and more anecdotal information like the number of recruiters contacting me on LinkedIn! &lt;a title=&quot;Indeed.com comparison of JVM languages&quot; href=&quot;http://www.indeed.com/jobanalytics/jobtrends?q=scala%2C+groovy%2C+clojure%2C+jruby%2C+jython&amp;amp;l=&quot;&gt;This chart on Indeed.com&lt;/a&gt; shows that in early 2013 employers looking for developers with Scala experience for the first time outpaced the demand for those with Clojure experience or any other JVM language other than Java itself.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;EDIT 26/10/13: I felt it important to only compare 2nd generation JVM languages.  IMO it&apos;s not fair to include the Java language itself because it dwarfs adoption of 2nd gen languages due to its omnipresence in the industry for over 20 years.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/assets/indeed_job_trends.png&quot;&gt;&lt;img class=&quot;size-full wp-image-331 alignnone&quot; src=&quot;/assets/indeed_job_trends.png&quot; alt=&quot;indeed_job_trends&quot; width=&quot;548&quot; height=&quot;309&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Simon and some of our other technical management began dabbling with learning Scala themselves. I remember Simon telling me that the power of the language is obvious, but that it would be easy misuse it and get yourself in trouble. Why of course. &lt;em&gt;With great power comes great responsibility&lt;/em&gt;.  This reminded me of that old programmer humour post &lt;a title=&quot;How to Shoot Yourself in the Foot in Any Programming Language&quot; href=&quot;http://www.fullduplex.org/humor/2006/10/how-to-shoot-yourself-in-the-foot-in-any-programming-language/&quot;&gt;&quot;How to Shoot Yourself in the Foot in Any Programming Language&quot;&lt;/a&gt; by Mike Walker.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Scala: you stare at your foot for 3 days without any sleep, you then figrue &lt;/em&gt;[sic]&lt;em&gt; out how to shoot yourself in the foot with one line of code… recursively.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Granted, this addition came from a commenter about 7 years after the original post, but I think the author described Scala perfectly within the context of the meme!&lt;/p&gt;
&lt;h2&gt;Legacy integration&lt;/h2&gt;
&lt;p&gt;Integration with the rest of our Microsoft platform and products was a concern from the start. It was time to start investing in backend API&apos;s.  Not only to integrate with our .NET projects, but because of a separate long term goal to abstract away our persistence layer so we could change it in the future.&lt;/p&gt;
&lt;p&gt;Our API initiative began with serving only the data needs of BeetleJuice. We started a spike on different API technologies. The first was a tomcat based web service that let you abstract queries based on an &lt;a title=&quot;ANTLR&quot; href=&quot;http://www.antlr.org/&quot;&gt;ANTLR&lt;/a&gt; domain specific language. You could craft HTTP requests that contained projections, filters, and joins (like SQL) and it would return a JSON representation of the data. It worked, but it was quite complicated to use and the queries looked a whole lot like our data access queries themselves.&lt;/p&gt;
&lt;p&gt;Our second API implementation was written by Steven and based &lt;a title=&quot;Apache Thrift&quot; href=&quot;http://thrift.apache.org/&quot;&gt;Apache Thrift&lt;/a&gt; and &lt;a title=&quot;Finagle&quot; href=&quot;http://twitter.github.io/finagle/&quot;&gt;Twitter&apos;s Finagle&lt;/a&gt;. The API endpoints had methods you could call much in the same way as a traditional RPC service. Thrift/Finagle gave us the capability to generate native C# and Scala code so we didn&apos;t need to manually write our own data transfer objects, clients, and services.  &lt;a title=&quot;Finagle&quot; href=&quot;http://twitter.github.io/finagle/&quot;&gt;Finagle&lt;/a&gt; has a ton of functionality out of the box such as easy horizontal scaling with &lt;a title=&quot;ZooKeeper&quot; href=&quot;http://zookeeper.apache.org/&quot;&gt;ZooKeeper&lt;/a&gt;, excellent stats using &lt;a title=&quot;Ostrich&quot; href=&quot;https://github.com/twitter/ostrich&quot;&gt;Ostrich&lt;/a&gt;, concurrency made easy with Twitter&apos;s library of threadpooling logic, and an easy way to instantiate servers and client connections.  Thrift/Finagle is an excellent choice to write API&apos;s in.   &lt;a title=&quot;Steven Skelton&apos;s blog&quot; href=&quot;http://stevenskelton.ca/&quot;&gt;Steven has blogged about Thrift and Finagle extensively&lt;/a&gt; and even gave a short talk at a local &lt;a title=&quot;Toronto Scala Meetup&quot; href=&quot;http://www.meetup.com/Scala/Toronto-CA/&quot;&gt;Toronto Scala Meetup&lt;/a&gt;. You can &lt;a title=&quot;Transitioning C# to Scala using Thrift&quot; href=&quot;http://stevenskelton.ca/files/2013/09/TransitioningCSharpToScalaUsingThrift.pdf&quot;&gt;find his slides here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once we had a Thrift API ready and in production we were able to get BeetleJuice and our other .NET projects to connect to it and start consuming data.&lt;/p&gt;
&lt;h2&gt;A moment of doubt&lt;/h2&gt;
&lt;p&gt;BeetleJuice and our new API were proving to be a success. It wasn&apos;t long before a large new project, Grail, was on the table and a new technology discussion began. This discussion was different than those past because we now had some actual Scala experience on the team.  We even hired top Scala talent such as the likes of &lt;a title=&quot;Becipe&quot; href=&quot;http://www.becipe.com/&quot;&gt;Katrin Shechtman&lt;/a&gt; (who runs a cool startup on the side called &lt;a title=&quot;Becipe&quot; href=&quot;http://www.becipe.com/&quot;&gt;Becipe&lt;/a&gt; that runs on a Scala, Play! Mongo and Heroku stack). I&apos;ll admit that I had my reservations about the language and I thought it was my responsibility to contrast some of the Scala evangelization that had been growing on the team and play devil&apos;s advocate.&lt;/p&gt;
&lt;p&gt;My main argument against Scala was a common complaint about the tooling. The compiler&apos;s slow, the IDE&apos;s are buggy and lacking in features, the preferred build and dependency management framework, SBT, has a tremendous learning curve. I was seriously questioning whether or not the rest of the developers on our team were going to get onboard with Scala knowing that using it would mean taking a productivity hit at first. I made my arguments, but ultimately it was decided it was worth the risk. I was relieved that management and my developer colleagues were onboard despite the drawbacks. It was at this time that I decided to make it a priority to really embrace Scala and find new ways to cope with the different development practices and toolchain from what I was used to in .NET.&lt;/p&gt;
&lt;h2&gt;An endorsement of Open Source technology&lt;/h2&gt;
&lt;p&gt;After Grail had been humming along for a few weeks, Simon made an official announcement to the development department that endorsed the use of Scala, Linux, and other open source tools and technologies. This was a critical moment in our organization because up until then C#, .NET, and the Microsoft stack were our default choices.  This was &lt;a title=&quot;Simon Palmer&apos;s blog&quot; href=&quot;http://www.simonpalmer.com&quot;&gt;Simon&apos;s&lt;/a&gt; announcement outlining our long term technical strategy.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;&lt;strong&gt;To: Empathica Developers&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #808080;&quot;&gt; &lt;em&gt;&lt;strong&gt;Subject: Technical Strategy&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Folks,&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;I seem to have set the Scala cat among the C# pigeons yesterday, so I wanted to lay out my view of our long-term technical strategy in the hope that it will allay some fears and clear up any ambiguity that I may have caused.  And I’d like to apologise if anyone felt disenfranchised, or as though there were important decisions being made without their input.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;First, some principles:&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;We make a point of recruiting the brightest technical people we can find and our expectation is that you will be comfortable working in whatever technology is required for the job at hand.  I think you all fit into this category and I hope that you feel the same way, but if you are working for a long time in a single technology a rut can look a lot like a groove.&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;The job at hand will require different technologies depending on the need, and we will not be bound to any single technology.  A technology choice will be made appropriately for the needs as we see them.  The choice of technology is one of the hardest because it happens early and is somewhat irreversible.  It also has many dimensions, some of which are hard to discern at the start of a project.&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;We have to balance our agile rapidity against good architecture.  It is one of the core criticisms of agile, and particularly XP, that you too easily ignore architecture as you ricochet from one user driven feature to the next.  This point is particularly relevant to us now as we are embarking on two significant architectural changes, one being a core data model change, the other inserting an API layer.&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;There’s never a good time to make a large architectural shift and you will always be balancing tactical commitments against long-term aspirations, as we are right now.  Furthermore you never get given the time to do it.  A data API is one of the key missing components in our platform.  What we have done with the &lt;/em&gt;[API]&lt;em&gt; is an excellent example of how to start to insert a formal tier in the architecture, and what we are contemplating for &lt;/em&gt;[Grail]&lt;em&gt; and &lt;/em&gt;[MultiPass]&lt;em&gt; access is a good natural extension.  The success of any future revolution in our data tier will be contingent on us having done the &lt;/em&gt;[API]&lt;em&gt; work well.&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;A profusion of service endpoints has a somewhat bad architectural smell.  You should have good reasons to fragment your APIs into many pieces and expedience is rarely a good reason.  A single endpoint may not be the answer either, but there should be a good architectural reason to split it apart.&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;With these in mind here is what I would like to see us move towards in the medium to long term:&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Minimal dependence on Microsoft, both O/S and data stores&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Increased infrastructure in “the cloud”&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Horizontal scalability as a fundamental architectural principle&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;As a consequence this probably means:&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Less C#/.Net, more Scala/Java/Open Source and&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Less SQLServer/OLAP Services, more NoSQL/Columnar Storage/Mongo/Vertica&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Less Windows, more Linux&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Less cabinets/pizza boxes, more AWS/Private cloud&lt;/em&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Taking a leaf from the agile manifesto wording, I mean: “while I see value in the things on the left, I see more long-term value in the things on the right”.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;So, no hard decision has been made about our future languages or technologies, and there are no rules that all new development must happen in Scala.  Instead I want us all to align on the principles and then make the right decisions as we balance our short-term needs against our long-term aspirations.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;If you have any further questions please feel free to come and find me.  I am stuck at home today because the four snowmen of the snowpocalypse arrived in Oakville this morning, but I’ll gladly take a phone call.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;a title=&quot;Simon Palmer&apos;s blog&quot; href=&quot;http://www.simonpalmer.com&quot;&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&lt;em&gt;Simon Palmer&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #808080;&quot;&gt; &lt;em&gt; Chief Technology Officer&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #808080;&quot;&gt; &lt;em&gt; Empathica Inc&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;- &lt;a title=&quot;Simon Palmer&apos;s blog&quot; href=&quot;http://www.simonpalmer.com&quot;&gt;Simon Palmer&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Dealing with technology change&lt;/h2&gt;
&lt;p&gt;Not everybody was pleased with the transition to Scala. Giving up years of experience with one particular language and framework just to be a &quot;beginner&quot; with a new one can be a tough pill for some people to swallow.  Most people inherently don&apos;t like change. For a programmer, changing technologies can have a profound impact on your productivity and in some cases your mental stability!  In our industry you have to fight to overcome these innate reactions.&lt;/p&gt;
&lt;p&gt;In the technology world there are no excuses for people who don&apos;t adapt.  Software development doesn&apos;t have a deep body of knowledge like some engineering practices do (I know calling software development an engineering discipline is a slippery slope, but please indulge me).  For example, the know-how and best practices for building a bridge have been known for thousands of years.  What we consider software engineering may have been around for close to 50 to 80 years, depending on how liberal your definition of what defined the beginning of software engineering is.  It could be decades or even centuries before we reach some kind of steady state of technological development.  Until that time people in the software industry need to learn to adapt and embrace what&apos;s new or be left behind.&lt;/p&gt;
&lt;p&gt;A good carpenter finds the right tool for the job. This analogy easily extends to software, especially when the tools and jobs themselves change at such an astonishing pace! Compiled, scripted, imperative, or functional. Pick something the community ascribes to to get the job done. Haven&apos;t used it yet? Try it out!  Those who don&apos;t strive to learn new languages and technologies are in for a rude awakening when the years of experience they have with &lt;a title=&quot;The Blub Paradox&quot; href=&quot;http://www.paulgraham.com/avg.html&quot;&gt;Blub&lt;/a&gt; don&apos;t count for anything with employers.&lt;/p&gt;
&lt;h2&gt;A data renaissance through API&apos;s&lt;/h2&gt;
&lt;p&gt;There became a need to extend our Scala Thrift/Finagle API as Grail was being developed. It was decided that when there were data needs for new projects they would be put behind our API. This began a data renaissance of sorts; not only did we put Grail&apos;s needs behind an API, but as we identified overlapping needs of our existing products, we retrofitted them to make use of the API as well. This had a snowball effect of establishing API&apos;s for the remainder of our legacy projects that were still under active development.&lt;/p&gt;
&lt;p&gt;A significant allocation of our development team was refactoring projects to use Thrift while at the same time establishing data contracts for API&apos;s. For a number of months we checked off boxes on our API wishlist. An incredible amount of code was written, refactored, rewritten, or simply not needed any more. Our product middle tiers shrank down to a token of their former sizes. Introducing an API layer forced us to establish clear lines between our apps and their data. This separation of concerns was a huge boon to the distributed architecture of our entire infrastructure and in line with the sentiments Simon made in his technical strategy.&lt;/p&gt;
&lt;p&gt;We started thinking a lot about concurrency and distributed systems.  We started investigating new data access technologies to standardize across our API layer such as &lt;a title=&quot;Typesafe Slick&quot; href=&quot;http://slick.typesafe.com/&quot;&gt;Slick&lt;/a&gt; for RDBMS and &lt;a title=&quot;Couchbase&quot; href=&quot;http://www.couchbase.com/&quot;&gt;Couchbase&lt;/a&gt; for caching.  We had already been using Mongo for parts of our infrastructure, but we also started planning an overhaul of the rest of our RDBMS infrastructure from SQL Server to cheaper and ironically, more scalable solutions like &lt;a title=&quot;Vertica&quot; href=&quot;http://www.vertica.com/&quot;&gt;Vertica&lt;/a&gt; (a columnar relational database) and &quot;No SQL&quot; databases.  All of these decisions were made that much easier because of the introduction of our API layer and the myriad of library choices available in the Scala and Java OSS ecosystem.&lt;/p&gt;
&lt;h2&gt;Training and education&lt;/h2&gt;
&lt;p&gt;A lot of Empathica developers were interested in using Scala.  Unfortunately, other than those that had been working on BeetleJuice, Grail, and our API, there weren&apos;t a ton of people with experience in the language.  We entertained the thought of bringing in instructors from Typesafe or their &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co/&quot;&gt;Canadian Scala training partner, tindr.co&lt;/a&gt; (more on them later), but in the beginning we looked to &lt;a title=&quot;Coursera&quot; href=&quot;https://www.coursera.org/&quot;&gt;Coursera&lt;/a&gt; and their growing catalogue of Massive Open Online Course&apos;s (MOOC&apos;s).&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Functional Programming Principles in Scala at Coursera&quot; href=&quot;https://www.coursera.org/course/progfun&quot;&gt;&lt;img src=&quot;/assets/fun_prog_scala.png&quot; alt=&quot;Functional Programming Principles in Scala&quot; width=&quot;633&quot; height=&quot;145&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Martin Odersky, the inventor of Scala and a key figure in the Java community, provided video lectures for the &lt;a title=&quot;Functional Programming Principles in Scala&quot; href=&quot;https://www.coursera.org/course/progfun&quot;&gt;Functional Programming Principles in Scala&lt;/a&gt; course on Coursera.  This course has been wildly popular and is regarded as one of the most successful software programming MOOC&apos;s ever.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;We had more than 50,000 registered students— an unfathomably large number in the context of traditional teaching. While large, that number doesn’t tell the whole story; as is typical for a MOOC, a statistical majority of those students participate no further beyond watching a couple of videos to find out what the course is about. Of the 50,000, about 21,000 students participated in the interactive in-video quizzes that are part of the lectures, and a remarkable 18,000 unique students attempted at least one programming assignment. A whopping 9,593 students successfully completed the course and earned a certificate of completion— that’s an incredible 20% of students, which blows the average 10% rate of completion for MOOCs out of the water.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;- &lt;a title=&quot;Functional Programming Principles in Scala: Impressions and Statistics&quot; href=&quot;http://docs.scala-lang.org/news/functional-programming-principles-in-scala-impressions-and-statistics.html&quot;&gt;Functional Programming Principles in Scala: Impressions and Statistics&lt;/a&gt; By Heather Miller and Martin Odersky&lt;/p&gt;
&lt;p&gt;With the blessing of the management team we decided to allocate one day a week for the length of the course to watching video lectures and working on weekly assignments.  On Thursday morning we would meet together in a room, discuss last week&apos;s assignment and watch the lectures for the week.  We often paused and attempted to solve in-lecture exercises and to discuss the concepts being taught.&lt;/p&gt;
&lt;p&gt;Some of us had doubts of how useful a functional programming course would be in day-to-day work at Empathica, but with the explosion of LISP dialects in recent years and the need for side-effect free code that can run concurrently there&apos;s been a huge demand in the industry to apply these skills to new systems.  The course exercises do involve a lot of algorithms and basic data structures, but it&apos;s also an excellent introduction to Scala syntax such as pattern matching, for comprehensions, Scala&apos;s collection types, and much more.  I would strongly recommend this course to anyone interested in learning Scala, functional programming, or both!&lt;/p&gt;
&lt;p&gt;As I mentioned earlier, there are many vendors that offer a variety of Scala training options.  &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co/&quot;&gt;tindr.co&lt;/a&gt; not only &lt;a title=&quot;tindr Scala Training&quot; href=&quot;http://tindr.co/scala-training/&quot;&gt;runs training courses based on Typesafe curriculum&lt;/a&gt;, but they&apos;ve also introduced a new program called the &lt;a title=&quot;Scala Developer Factory&quot; href=&quot;http://tindr.co/scala-developer-factory/&quot;&gt;Scala Developer Factory&lt;/a&gt;; a rigorous training course that promises to deliver skilled and productive Scala developers!  I&apos;ve kept a line of communication open with Mike and Eric at &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co/&quot;&gt;tindr.co&lt;/a&gt; to discuss possible future on-site training options for the developers at Empathica.&lt;/p&gt;
&lt;h2&gt;Embracing the Scala community&lt;/h2&gt;
&lt;p&gt;Toronto has an active Scala community.  Several meetups are planned each year and are usually hosted at software shops that have adopted Scala into their organizations.  The &lt;a title=&quot;Toronto Scala Meetup&quot; href=&quot;http://www.meetup.com/Scala/Toronto-CA/&quot;&gt;Toronto Scala Meetup&lt;/a&gt; has run meetups for a few years.  &lt;a title=&quot;Chris Dinn&apos;s twitter&quot; href=&quot;https://twitter.com/chrisdinn&quot;&gt;Chris Dinn&lt;/a&gt; has often organized these events.  Speakers from the community are invited to present on any Scala related subject they like.  Representatives from Typesafe and &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co/&quot;&gt;tindr.co&lt;/a&gt; often show up as well.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/assets/scala_at_empathica2.png&quot;&gt;&lt;img class=&quot;size-medium wp-image-341 alignnone&quot; src=&quot;/assets/scala_at_empathica2-300x49.png&quot; alt=&quot;Scala @ Empathica&quot; width=&quot;300&quot; height=&quot;49&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Becipe&quot; href=&quot;http://www.becipe.com/&quot;&gt;Katrin&lt;/a&gt; proposed the idea that we host a meetup at Empathica&apos;s downtown office.  At the time, our office was a dingy top floor on Peter St. atop an infamous night club in Toronto&apos;s entertainment district called &quot;Time&quot;.  Plans to host the meetup were shelved until we setup shop in our new digs on Spadina ave.   With renewed vigor, &lt;a title=&quot;Becipe&quot; href=&quot;http://www.becipe.com/&quot;&gt;Katrin&lt;/a&gt; began preparing a schedule.  Our RSVP list grew.  &lt;a title=&quot;Toronto Scala Meetup September 19th 2013&quot; href=&quot;http://www.meetup.com/Scala/Toronto-CA/917882/&quot;&gt;We ran the event with 3 speakers&lt;/a&gt; and representatives from both Typesafe and &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co&quot;&gt;tindr.co&lt;/a&gt;.  Empathica provided the space plus refreshments and the folks at &lt;a title=&quot;tindr.co&quot; href=&quot;http://tindr.co&quot;&gt;tindr.co&lt;/a&gt; were kind enough to buy pizza&apos;s for a group of roughly 50 people.  It was a huge success and the social gathering after the talks allowed for lots of networking and prompted many interesting discussions.  I can safely say on behalf of the devs at Empathica that we&apos;re psyched to continue to attend, contribute, and host these events in the future.&lt;/p&gt;
&lt;div style=&quot;width: 100%; margin: auto;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;/assets/image_4.jpeg&quot;&gt;&lt;img class=&quot;size-medium wp-image-360 alignleft&quot; style=&quot;border: 1px solid black;&quot; src=&quot;/assets/image_4-300x224.jpeg&quot; alt=&quot;Empathica Toronto Scala Meetup - Intro&quot; width=&quot;300&quot; height=&quot;224&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;/assets/image_6.jpeg&quot;&gt;&lt;img class=&quot;size-medium wp-image-362&quot; style=&quot;border: 1px solid black;&quot; src=&quot;/assets/image_6-300x224.jpeg&quot; alt=&quot;Toronto Scala Meetup - Steven&quot; width=&quot;300&quot; height=&quot;224&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/assets/toronto_scala_meetup_pan.jpeg&quot;&gt;&lt;img class=&quot;wp-image-363&quot; style=&quot;border: 1px solid black;&quot; src=&quot;/assets/toronto_scala_meetup_pan-1024x253.jpeg&quot; alt=&quot;Toronto Scala Meetup - Panorama&quot; width=&quot;627&quot; height=&quot;162&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Reflection&lt;/h2&gt;
&lt;p&gt;There are now several dev teams at Empathica working on Scala projects.  Tool chains are being developed.  Coding standards are being established and enforced.  Libraries are being standardized across our projects.  It&apos;s starting to return to a comfortable pace of software development for everyone.&lt;/p&gt;
&lt;p&gt;That&apos;s it.  I&apos;m known for being verbose so I apologize for the lengthy read, but I wanted to get this story out in its entirety if for no other reason then for Empathica&apos;s own posterity.  It wasn&apos;t an easy transition.  Looking back, there are things I probably would have done differently, but I think with the information available we did a pretty good job.  I hope that for those of you thinking about a technology change that our experiences help you come up with a plan to bring about that change.  I&apos;m sure there are also some people reading that have gone through such a change and I welcome your input in the comments whether good or bad.&lt;/p&gt;
&lt;p&gt;If I were involved in a significant technology change again I would definitely take a different tack both in its proposition and implementation.  Some things I would do differently and some things I would not.  I&apos;ve compiled a summary of what I think are the most important matters to address.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consensus building.  Get the whole development team&apos;s input and suggestions.  Be as accommodating as you can, but don&apos;t expect unanimity.  It&apos;s important to get input from everyone you work with on a daily basis because they will all be affected by the decision.&lt;/li&gt;
&lt;li&gt;Start with something small that has potential to grow it into something big.&lt;/li&gt;
&lt;li&gt;Budget for training in your iteration/sprint/project plan.  Some people prefer learning on their own by reading a book, some like the classroom environment, and some just want to start writing code.  See who falls into what group and try to accommodate them all.&lt;/li&gt;
&lt;li&gt;Ask hiring prospects how they would feel if they worked with a different technology than one they have experience with.&lt;/li&gt;
&lt;li&gt;Include OSS experience as part of your hiring criteria.  Either experience contributing to specific projects or experience working with open source languages and frameworks.&lt;/li&gt;
&lt;li&gt;Be patient.  Significant technology changes don&apos;t happen over night.  But with the right people and the right attitude amazing things can happen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;ll conclude this post with a link to a little bit of internet history.  This video made the rounds in 2010 and although it does not specifically endorse Scala it&apos;s still a harrowing story about leaving the Microsoft nest and embracing open source technologies. Plus it co-stars the lovely Scala Johansson :)&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/kLO1djacsfg&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;(&lt;strong&gt;NSFW&lt;/strong&gt;, depending on where you work!)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;EDIT 08/09/14: If you would like to know more about our transition on .NET to Scala then check out my follow up post: &lt;a href=&quot;http://randonom.com/blog/2014/09/net-to-scala-developer-qa-with-typesafe/&quot;&gt;.NET to Scala developer Q&amp;amp;A with Typesafe&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 24 Oct 2013 14:15:11 +0000</pubDate>
        <link>https://seanglover.com/blog/2013/10/technology-change-net-to-scala/</link>
        <guid isPermaLink="true">https://seanglover.com/blog/2013/10/technology-change-net-to-scala/</guid>
        
        <category>.net</category>
        
        <category>csharp</category>
        
        <category>leadership</category>
        
        <category>scala</category>
        
        <category>thrift</category>
        
        
        <category>Scala</category>
        
        <category>Technology Change</category>
        
      </item>
    
  </channel>
</rss>
