<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Stephen Mallette</title>
 <link href="http://spmallette.github.com/atom.xml" rel="self"/>
 <link href="http://spmallette.github.com/"/>
 <updated>2015-04-02T12:26:58+00:00</updated>
 <id>http://spmallette.github.com/</id>
 <author>
   <name>Stephen Mallette</name>
   <email>spmva@genoprime.com</email>
 </author>

 
 <entry>
   <title>Using Gremlin Java in TinkerPop 2.x</title>
   <link href="http://spmallette.github.com/2015/04/02/using-gremlin-java-in-tp2.html"/>
   <updated>2015-04-02T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2015/04/02/using-gremlin-java-in-tp2</id>
   <content type="html">&lt;p&gt;Some organizations are single-minded in their choice of programming language.  They are &amp;#8220;Java shops&amp;#8221; or &amp;#8220;Python shops&amp;#8221; and there is no room for anything in between.  This choice often places developers in a position where they find new technology that would be useful in achieving their goals, but they are unable to use it because it uses a non-approved technology.  Gremlin, as it stands in TinkerPop 2.x, is best used in its Groovy form, as the syntatic sugar of Groovy helps form a simple and concise &lt;span class=&quot;caps&quot;&gt;DSL&lt;/span&gt; for traversing graphs.  Unfortunately, Groovy is not always on the list of approved technology at these organizations that define themselves as a &amp;#8220;Java Shop&amp;#8221;.  As such, developers in these organizations look to use Gremlin in its Java form.&lt;/p&gt;
&lt;p&gt;Unfortunately, Gremlin Java is quite verbose, which is largely a function of the way Java itself works.  Developers tend to have a hard time understanding the method in which their Gremlin Groovy converts to Java and, as a result, there tend to be many questions about the best way to go about doing this.&lt;/p&gt;
&lt;p&gt;I recently provided an answer to &lt;a href=&quot;http://stackoverflow.com/q/29409219/1831717&quot;&gt;this question&lt;/a&gt; on StackOverflow where someone was trying to understand just how to do this.  I went into some detail on this topic and hopefully provided a nice tutorial for those who have this problem.  I think that in many ways, &lt;a href=&quot;http://stackoverflow.com/a/29411662/1831717&quot;&gt;this answer&lt;/a&gt; will become the reference that we point people to who have this problem.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Article - Powers of Ten Series</title>
   <link href="http://spmallette.github.com/2014/06/02/powers-of-ten-post.html"/>
   <updated>2014-06-02T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2014/06/02/powers-of-ten-post</id>
   <content type="html">&lt;p&gt;One of the most common questions that people seem to have when getting started with graph databases is how to best load their data.  As is the case with most technological things, a one size fits all answer isn&amp;#8217;t really applicable.  While there are some general patterns that can be followed, there are definitely different strategies to apply depending on the size of the data.&lt;/p&gt;
&lt;p&gt;To identify the common patterns and address the different strategies at different sizes issue, I worked with &lt;a href=&quot;https://twitter.com/dkuppitz&quot;&gt;Daniel Kuppitz&lt;/a&gt; to author the &lt;em&gt;Powers of Ten&lt;/em&gt; series, a two part article on bulk loading data into the &lt;a href=&quot;titan.thinkaurelius.com&quot;&gt;Titan&lt;/a&gt; graph database.  &lt;a href=&quot;http://thinkaurelius.com/2014/05/29/powers-of-ten-part-i/&quot;&gt;Part I&lt;/a&gt; of the series focused on datasets that contained millions to tens of millions of edges and &lt;a href=&quot;http://thinkaurelius.com/2014/06/02/powers-of-ten-part-ii/&quot;&gt;Part II&lt;/a&gt; focused on hundreds of millions of edges to billions.&lt;/p&gt;
&lt;p&gt;I think that these posts are very useful resources for those getting started with Titan.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Deconstruct Gremlin Paths</title>
   <link href="http://spmallette.github.com/2014/04/09/deconstruct-gremlin-paths.html"/>
   <updated>2014-04-09T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2014/04/09/deconstruct-gremlin-paths</id>
   <content type="html">&lt;p&gt;I mentioned to someone recently that to be great at &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt;, you have to be great at &lt;a href=&quot;http://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt;.  There is too much syntactic sugar and shorthand in Groovy to just ignore.  In my previous post, I demonstrated the &lt;a href=&quot;http://stephen.genoprime.com/2014/02/28/use-collate-to-batch-gremlin-results.html&quot;&gt;use of collate&lt;/a&gt; in batching Gremlin results.  In this post, I present another bit of Groovy goodness in relation to Gremlin and it lies in Groovy&amp;#8217;s ability to destructure lists into variables:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; (x,y,z) = [10,20,30]
==&amp;gt;10
==&amp;gt;20
==&amp;gt;30
gremlin&amp;gt; y
==&amp;gt;20
gremlin&amp;gt; x + y + z
==&amp;gt;60&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This ability to do &lt;a href=&quot;http://groovy.codehaus.org/Multiple+Assignment&quot;&gt;multiple assignment&lt;/a&gt; ends up presenting opportunity for some nice Gremlin usage with respect to the use of the &lt;code&gt;path&lt;/code&gt; step:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g = TinkerGraphFactory.createTinkerGraph()
==&amp;gt;tinkergraph[vertices:6 edges:6]
gremlin&amp;gt; g.v(1).outE.inV.path.collect{it[0].name + &amp;quot;:&amp;quot; + it[1].weight + &amp;quot;:&amp;quot; + it[2].name} 
==&amp;gt;marko:0.5:vadas
==&amp;gt;marko:1.0:josh
==&amp;gt;marko:0.4:lop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the above code, we traverse out from &lt;code&gt;g.v(1)&lt;/code&gt; and then grab the path.  The path is a &lt;code&gt;List&lt;/code&gt; of the elements that made up the traversal.  In this case, the item in the first postion is &lt;code&gt;g.v(1)&lt;/code&gt;, the item in the second position is the out edge and item in the third position is the in-vertex.  As the path is a &lt;code&gt;List&lt;/code&gt;, we must reference the items in it by index.  It works, but is a bit difficult to read.  The alternative is to destructure the list into variables:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g.v(1).outE.inV.path.collect{marko,outE,inV-&amp;gt;&amp;quot;${marko.name}:${outE.weight}:${inV.name}&amp;quot;}        
==&amp;gt;marko:0.5:vadas
==&amp;gt;marko:1.0:josh
==&amp;gt;marko:0.4:lop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With named variables for the items in the path, the intent of the &lt;code&gt;collect&lt;/code&gt; closure can be more clearly understood at a glance.  While &amp;#8220;multiple assignment&amp;#8221; has a nice use case with the Gremlin &lt;code&gt;path&lt;/code&gt; step, it is quite useful for other tasks where accessing objects in a list by position can get overly-complicated.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Use Collate to Batch Gremlin Results</title>
   <link href="http://spmallette.github.com/2014/02/28/use-collate-to-batch-gremlin-results.html"/>
   <updated>2014-02-28T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2014/02/28/use-collate-to-batch-gremlin-results</id>
   <content type="html">&lt;p&gt;Groovy has many great functions and syntax that can expand the capabilities and flexibility of the Gremlin programming language.  A recent &lt;a href=&quot;http://thinkaurelius.com/2013/02/04/polyglot-persistence-and-query-with-gremlin/&quot;&gt;polyglot query&lt;/a&gt; I came across, highlighted how important it can be to know Groovy as well as you know Gremlin.&lt;/p&gt;
&lt;p&gt;Consider a situation where you want to write some Gremlin to pull some data from the TinkerPop toy graph to then pass to a query sent to a MySQL database.  It might look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g  = TinkerGraphFactory.createTinkerGraph()
==&amp;gt;tinkergraph[vertices:6 edges:6]
gremlin&amp;gt; g.V.name.gather.transform{
             sql.rows(&amp;quot;SELECT * FROM toy WHERE n IN (&amp;#39;&amp;quot; + it.join(&amp;quot;&amp;#39;,&amp;#39;&amp;quot;) + &amp;quot;&amp;#39;)&amp;quot;)}.next()
==&amp;gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the code above gets the &lt;code&gt;name&lt;/code&gt; property from each vertex, uses &lt;code&gt;gather&lt;/code&gt; to pull them all into a &lt;code&gt;List&lt;/code&gt; and then transforms that &lt;code&gt;List&lt;/code&gt; by using it as parameters to an &lt;code&gt;IN&lt;/code&gt; clause of a &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement.  That works nicely with the toy graph because it is small (only six vertices).  In a larger graph, it&amp;#8217;s possible that the set of returned vertices might exceed the capability of the &lt;code&gt;IN&lt;/code&gt; expression or otherwise cause the query to not perform well.  In this case, it might be better to batch the results to the &lt;code&gt;IN&lt;/code&gt; clause so that they could be executed in smaller bits.&lt;/p&gt;
&lt;p&gt;Groovy provides a very succinct way to do this in the form of the &lt;code&gt;collate&lt;/code&gt; function.  Consider the following Gremlin session, which still uses the toy graph for demonstration purposes:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g.V.name.gather                                             
==&amp;gt;[lop, vadas, marko, peter, ripple, josh]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output above shows that a &lt;code&gt;List&lt;/code&gt; of names is being passed to the &lt;code&gt;transform&lt;/code&gt; function shown in the first block of code.  To batch that list, replace &lt;code&gt;gather&lt;/code&gt; with &lt;code&gt;collate&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g.V.name.toList().collate(2)
==&amp;gt;[lop, vadas]
==&amp;gt;[marko, peter]
==&amp;gt;[ripple, josh]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using &lt;code&gt;collate&lt;/code&gt;, the names are placed in batches of two, where each batch will be iterated into the &lt;code&gt;transform&lt;/code&gt; effectively creating a batched approach to issuing the &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; query.  In this case, three separate queries would be executed, each representing one small chunk of the total data to be retrieved.  The following code shows the modified code using &lt;code&gt;collate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g.V.name.toList().collate(2).transform{
             sql.rows(&amp;quot;SELECT * FROM toy WHERE n IN (&amp;#39;&amp;quot; + it.join(&amp;quot;&amp;#39;,&amp;#39;&amp;quot;) + &amp;quot;&amp;#39;)&amp;quot;)}.scatter.toList()
==&amp;gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the end of the statement changed as well, where the use of &lt;code&gt;scatter&lt;/code&gt; unrolls the rows returned from the database into a &lt;code&gt;List&lt;/code&gt;.  This part effectively reassembles the result data to a single &lt;code&gt;List&lt;/code&gt;, just as would have been done in the single &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; request in the original traversal.&lt;/p&gt;
&lt;p&gt;Groovy has many useful functions.  Some are better known than others, but every once in a while a lesser known one might be just what is needed to get the job done.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Use has() Over filter()</title>
   <link href="http://spmallette.github.com/2013/11/20/use-has-over-filter.html"/>
   <updated>2013-11-20T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/11/20/use-has-over-filter</id>
   <content type="html">&lt;p&gt;There&amp;#8217;s been some discussion on the Aurelius &lt;a href=&quot;https://groups.google.com/forum/#!forum/aureliusgraphs&quot;&gt;mailing list&lt;/a&gt; regarding the advantages of using a single `filter` with a complex closure over usage of multiple `has` steps.  You can read more about the discussion &lt;a href=&quot;https://groups.google.com/forum/#!topic/aureliusgraphs/nhn9IBsWIYw&quot;&gt;here&lt;/a&gt;.  The core of the discussion is about realizing that &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt; will compile `has` steps down to query objects that can be used by the underlying graph store to &lt;a href=&quot;https://github.com/tinkerpop/gremlin/wiki/Traversal-Optimization#query-optimization&quot;&gt;optimize the traversal&lt;/a&gt;, whereas a `filter` is merely a function that evaluates an item in the pipeline.  Therefore, using `has` is generally better than using `filter`.&lt;/p&gt;
&lt;p&gt;In midst of the discussion, I decided to try a small experiment.  I wanted to show that two `has` steps were no slower than a single `filter` operation that performed the same function, even when no query optimizations were performed by the underlying store.  &lt;a href=&quot;http://titan.thinkaurelius.com&quot;&gt;Titan&lt;/a&gt; does perform these optimizations, so I decided to utilize a &lt;a href=&quot;https://github.com/tinkerpop/blueprints/wiki/TinkerGraph&quot;&gt;TinkerGraph&lt;/a&gt; instead.  TinkerGraph utilizes &lt;a href=&quot;https://github.com/tinkerpop/blueprints/blob/master/blueprints-core/src/main/java/com/tinkerpop/blueprints/util/DefaultQuery.java&quot;&gt;DefaultQuery&lt;/a&gt; to process `has` operations.  `DefaultQuery` is used by all Blueprints implementations that do not implement their own optimizations, so the results of this experiment should carry across all Blueprints implementations that don&amp;#8217;t optimize.&lt;/p&gt;
&lt;p&gt;To do the experiment, I opened a Gremlin &lt;span class=&quot;caps&quot;&gt;REPL&lt;/span&gt; and constructed a graph with a half-million vertices with some random property values.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g = new TinkerGraph()                                                                        
==&amp;gt;tinkergraph[vertices:0 edges:0]
gremlin&amp;gt; r = new Random()                                                                             
==&amp;gt;java.util.Random@4841a34
gremlin&amp;gt; (0..&amp;lt;500000).each{g.addVertex([i:it,r:r.nextLong().toString().padLeft(21,&amp;quot;0&amp;quot;)])};null      
==&amp;gt;null
gremlin&amp;gt; g.v(0).map
==&amp;gt;{r=001842268616820437679, i=0}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then wrote two queries.  The first used `filter` with two property evaluations to determine whether they met the restriction or not and the second used two `has` operations one for each property being evaluated.  I ensured that both queries returned the same number of vertices.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; g.V.filter{it.r&amp;gt;=&amp;quot;00000000000&amp;quot; &amp;amp;&amp;amp; it.i&amp;gt;=200000}.count()                               
==&amp;gt;150211
gremlin&amp;gt; g.V.has(&amp;quot;r&amp;quot;,T.gte,&amp;quot;00000000000&amp;quot;).has(&amp;quot;i&amp;quot;,T.gte,200000).count()                        
==&amp;gt;150211&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once assured that I was returning the same data for both traversals, I timed the results.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; s=System.currentTimeMillis();g.V.has(&amp;quot;r&amp;quot;,T.gte,&amp;quot;00000000000&amp;quot;).has(&amp;quot;i&amp;quot;,T.gte,200000)
         .iterate();System.currentTimeMillis()-s
==&amp;gt;95
gremlin&amp;gt; s=System.currentTimeMillis();g.V.filter{it.r&amp;gt;=&amp;quot;00000000000&amp;quot; &amp;amp;&amp;amp; it.i&amp;gt;=200000}
         .iterate();System.currentTimeMillis()-s       
==&amp;gt;5521&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, I was quickly reminded that I wasn&amp;#8217;t using `getProperty` in my `filter` which balanced the numbers considerably:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gremlin&amp;gt; s=System.currentTimeMillis();g.V.has(&amp;quot;r&amp;quot;,T.gte,&amp;quot;00000000000&amp;quot;).has(&amp;quot;i&amp;quot;,T.gte,200000)
         .iterate();System.currentTimeMillis()-s
==&amp;gt;95
gremlin&amp;gt; s=System.currentTimeMillis();g.V.filter{
            it.getProperty(&amp;quot;r&amp;quot;)&amp;gt;=&amp;quot;00000000000&amp;quot; &amp;amp;&amp;amp; it.getProperty(&amp;quot;i&amp;quot;)&amp;gt;=200000
          }.iterate();System.currentTimeMillis()-s       
==&amp;gt;150&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The use of reflection to get the property value is very expensive and something I don&amp;#8217;t use in production code (I shouldn&amp;#8217;t have missed that).&lt;/p&gt;
&lt;p&gt;The results show a traversal with two `has` steps performs somewhat better than a single `filter` step.  What&amp;#8217;s interesting about this finding, is the fact that TinkerGraph is not optimizing the query when processing the `has`.  The results basically mean that finding a way to use `has` instead of `filter` will generally result in better traversal performance even for Blueprints implementations that don&amp;#8217;t support query optimizations.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Lein Uberjar with Titan Dependency</title>
   <link href="http://spmallette.github.com/2013/11/14/uberjar-with-titan-dependency.html"/>
   <updated>2013-11-14T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/11/14/uberjar-with-titan-dependency</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re working with &lt;a href=&quot;http://titan.thinkaurelius.com&quot;&gt;Titan&lt;/a&gt; in &lt;a href=&quot;http://clojure.org&quot;&gt;Clojure&lt;/a&gt; there&amp;#8217;s a good chance you&amp;#8217;re using &lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;Lein&lt;/a&gt; and if you are there&amp;#8217;s also a chance that you are building a &amp;#8220;jar with dependencies&amp;#8221; via &lt;code&gt;lein uberjar&lt;/code&gt;.  I was doing just that yesterday, when I was suddenly tossed into a point of deep frustration.  I watched happily as my code ran perfectly in my local environment with &lt;code&gt;lein run&lt;/code&gt;, but after doing a &lt;code&gt;lein uberjar&lt;/code&gt; and pushing my fat jar to a server instance in EC2 I got this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Caused by: java.lang.IllegalArgumentException: A SPI class of type org.apache.lucene.codecs.
  PostingsFormat with name &amp;#39;Lucene41&amp;#39; does not exist. You need to add the corresponding JAR 
  file supporting this SPI to your classpath.The current classpath supports the 
  following names: [Pulsing41, SimpleText, Memory, BloomFilter, Direct]
	at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:109)
	at org.apache.lucene.codecs.PostingsFormat.forName(PostingsFormat.java:100)
	at org.elasticsearch.index.codec.postingsformat.PostingFormats.&amp;lt;clinit&amp;gt;(
	  PostingFormats.java:76)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I ended up unlocking the solution to the problem by noticing an &lt;a href=&quot;https://github.com/elasticsearch/elasticsearch/issues/3350&quot;&gt;issue&lt;/a&gt; in the ElasticSearch GitHub Repo named &amp;#8220;Conflicting &lt;span class=&quot;caps&quot;&gt;META&lt;/span&gt;-&lt;span class=&quot;caps&quot;&gt;INF&lt;/span&gt; between elasticsearch &amp;amp; lucene-core/lucene-codecs for packaging into standalone binary&amp;#8221;.  At that point, I realized that Lein was overwriting these files over and over again in the &lt;code&gt;uberjar&lt;/code&gt; process:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;META-INF/services/org.apache.lucene.codecs.Codec
META-INF/services/org.apache.lucene.codecs.DocValuesFormat
META-INF/services/org.apache.lucene.codecs.PostingsFormat&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For my &amp;#8220;jar with dependencies&amp;#8221; to be functional, I would need those files to merge with one another as opposed to simply performing an overwrite.  In Maven, you would likely use the &lt;a href=&quot;http://maven.apache.org/plugins/maven-shade-plugin/&quot;&gt;Shade Plugin&lt;/a&gt; configured to do a &lt;a href=&quot;http://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html&quot;&gt;resource trasformation&lt;/a&gt;.  Up until yesterday, I wasn&amp;#8217;t aware of how to do that with Lein, but after some research realized that a recently added feature to Lein (as of 2.3.3) provided a similar feature set.  I simply added the following snippet to my &lt;code&gt;project.clj&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;:uberjar-merge-with {#&amp;quot;org\.apache\.lucene\.codecs\.*&amp;quot; [slurp str spit]}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which merged those various files together instead of writing one over the other.  At that point, my &amp;#8220;jar with dependencies&amp;#8221; was good to go.  You can read more about &lt;code&gt;uberjar-merge-with&lt;/code&gt; &lt;a href=&quot;https://github.com/technomancy/leiningen/blob/2.3.3/sample.project.clj#L342&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Article - Developing a Domain Specific Language in Gremlin</title>
   <link href="http://spmallette.github.com/2013/08/26/developing-dsl-gremlin-post.html"/>
   <updated>2013-08-26T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/08/26/developing-dsl-gremlin-post</id>
   <content type="html">&lt;p&gt;The &lt;a href=&quot;https://groups.google.com/forum/#!forum/gremlin-users&quot;&gt;gremlin-users&lt;/a&gt; mailing list always has questions asking how to &lt;em&gt;productionalize&lt;/em&gt; &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt;.  In a recent blog post for &lt;a href=&quot;http://www.thinkaurelius.com&quot;&gt;Aurelius&lt;/a&gt;, entitled &lt;a href=&quot;http://thinkaurelius.com/2013/07/25/developing-a-domain-specific-language-in-gremlin/&quot;&gt;Developing a Domain Specific Language in Gremlin&lt;/a&gt;, I describe some common patterns for working Gremlin into a production environment.  The patterns all relate to the concept of writing a &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;Domain Specific Language&lt;/a&gt; (&lt;span class=&quot;caps&quot;&gt;DSL&lt;/span&gt;) on top of Gremlin to allow the language of the domain to traverse the graph.  The &lt;span class=&quot;caps&quot;&gt;DSL&lt;/span&gt; approach to Gremlin yields many benefits and should make development and maintenance of Gremlin code much more straightforward.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>New GremlinDocs.com Logo</title>
   <link href="http://spmallette.github.com/2013/07/05/gremlin-docs-logo.html"/>
   <updated>2013-07-05T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/07/05/gremlin-docs-logo</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://gremlindocs.com&quot;&gt;GremlinDocs&lt;/a&gt; is a learn-by-example tutorial for the &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt; graph traversal language.  &lt;a href=&quot;http://ketrinadrawsalot.tumblr.com/&quot;&gt;Ketrina Yim&lt;/a&gt; who produces the wonderful and fantastical characters of &lt;a href=&quot;http://tinkerpop.com&quot;&gt;TinkerPop&lt;/a&gt; has brought some new life to the GremlinDocs web site.  She has illustrated a new logo that brings a unique look to the site and brings some character to something that would otherwise just be a bunch of words and code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.github.com/tinkerpop/gremlin/master/doc/images/gremlindocs-logo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I see a very simple story in that picture:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When not traversing graphs, Gremlin takes some of his free moments to write his autobiography.  Quill and scroll are his writing implements of choice, producing characters of sweeping grace that whimsically flow together to tell stories of graph exploration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These stories are &lt;em&gt;GremlinDocs&lt;/em&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Shortest Path With Gremlin</title>
   <link href="http://spmallette.github.com/2013/06/07/shortest-path-with-gremlin.html"/>
   <updated>2013-06-07T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/06/07/shortest-path-with-gremlin</id>
   <content type="html">&lt;p&gt;There has been a fair amount of discussion on finding shortests paths using Gremlin both in the &lt;a href=&quot;https://groups.google.com/forum/?fromgroups#!forum/gremlin-users&quot;&gt;Gremlin Users&lt;/a&gt; mailing list and on StackOverflow.  The questions asked sent me into a fair bit of depth on the subject, allowing for a better understanding of how best to implement such traversals in Gremlin.&lt;/p&gt;
&lt;p&gt;The result of this effort are as follows:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;An answer to &lt;a href=&quot;http://stackoverflow.com/questions/16849737/gremlin-how-to-get-more-than-1-shortest-path-with-same-number-of-edges&quot;&gt;Gremlin: How to get more than 1 shortest path with the same number of edges?&lt;/a&gt; on StackOverflow&lt;/li&gt;
	&lt;li&gt;A Gremlin-based answer to &lt;a href=&quot;http://stackoverflow.com/questions/16812679/is-it-possible-to-get-the-shortest-path-with-traversal-cost-by-using-cypher-or-g/16872807&quot;&gt;Is it possible to get the shortest path with traversal cost by using Cypher or Gremlin&lt;/a&gt; on StackOverflow.&lt;/li&gt;
	&lt;li&gt;An update to the GremlinDocs &lt;a href=&quot;http://gremlindocs.com/#recipes/shortest-path&quot;&gt;Shortest Path Recipe&lt;/a&gt; that provides much greater details on the topic (received some help from Daniel Kuppitz in this regard).&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Article - Polyglot Persistence and Query with Gremlin</title>
   <link href="http://spmallette.github.com/2013/02/06/polyglot-persistence-and-query-with-gremlin.html"/>
   <updated>2013-02-06T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2013/02/06/polyglot-persistence-and-query-with-gremlin</id>
   <content type="html">&lt;p&gt;On a recent trip, where I hung around with &lt;a href=&quot;http://http://markorodriguez.com/&quot;&gt;Marko Rodriguez&lt;/a&gt;, we came to a realization that &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt; has a wider applicability than often thought of.  Gremlin can be used in a variety of ways to work with disparate data sources that center around graphs.  From those thoughts, this blog post, &lt;a href=&quot;http://thinkaurelius.com/2013/02/04/polyglot-persistence-and-query-with-gremlin/&quot;&gt;Polyglot Persistence and Query with Gremlin&lt;/a&gt;, was written.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>GremlinDocs - Gremlin by Example</title>
   <link href="http://spmallette.github.com/2012/09/23/gremlin-by-example.html"/>
   <updated>2012-09-23T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2012/09/23/gremlin-by-example</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working with &lt;a href=&quot;http://clojure.org&quot;&gt;clojure&lt;/a&gt; for some time now, mostly using it for small, fast development efforts so that I could become more familiar with it.  In that time, I came to really like the format of &lt;a href=&quot;http://clojuredocs.org&quot;&gt;ClojureDocs&lt;/a&gt;.  It provides code snippets as samples for each function which clearly demonstrate how it works.&lt;/p&gt;
&lt;p&gt;I started thinking that &lt;a href=&quot;http://gremlin.tinkerpop.com&quot;&gt;Gremlin&lt;/a&gt; would benefit from that kind of documentation.  With that in mind, I created &lt;a href=&quot;http://gremlindocs.com&quot;&gt;GremlinDocs.com&lt;/a&gt;.  GremlinDocs is meant to be a companion to the Gremlin wiki, a reference for both beginners and advanced Gremlin users alike.  It is a quick reference to the functions that Gremlin has with examples taken from the Gremlin &lt;span class=&quot;caps&quot;&gt;REPL&lt;/span&gt; to demonstrate those functions.&lt;/p&gt;
&lt;p&gt;GremlinDocs is actually a GitHub repository where all the content for it is contained within a single &lt;code&gt;README.md&lt;/code&gt; file, with the idea that the repository could be forked and community contributions would help further improve the documentation.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>.NET Client for Kafka Checkpoint</title>
   <link href="http://spmallette.github.com/2012/07/28/dotnet-client-for-kafka-endgame.html"/>
   <updated>2012-07-28T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2012/07/28/dotnet-client-for-kafka-endgame</id>
   <content type="html">&lt;p&gt;I&amp;#8217;d written several posts in the past for some work I did for &lt;a href=&quot;https://github.com/apache/kafka/&quot;&gt;Kafka&lt;/a&gt;, which is a distributed publish/subscribe messaging system.  Here&amp;#8217;s a conclusive list of those posts from some months back:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://stephen.genoprime.com/2011/03/01/dotnet-client-for-kafka.html&quot;&gt;.&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; Client for Kafka&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://stephen.genoprime.com/2011/03/11/dotnet-client-for-kafka-checkpoint.html&quot;&gt;.&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; Client for Kafka Checkpoint&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://stephen.genoprime.com/2011/03/28/dotnet-client-for-kafka-multi-request.html&quot;&gt;.&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; Client for Kafka Multi-request&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After getting a message, which asked about my specific work with the C# client and mentioned some dead links to its location, I realized that I should probably close out this part of the story.  I no longer maintain the C# client for Kafka which is available &lt;a href=&quot;https://github.com/apache/kafka/tree/trunk/clients/csharp&quot;&gt;here&lt;/a&gt;.  Maintenance was picked up by someone external to the Kafka project, who made a number of enhancements to my original work and was then contributed back to Kafka.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Custom Graph Configuration In Rexster</title>
   <link href="http://spmallette.github.com/2012/05/03/graph-configuration-in-rexster.html"/>
   <updated>2012-05-03T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2012/05/03/graph-configuration-in-rexster</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://rexster.tinkerpop.com&quot;&gt;Rexster&lt;/a&gt; is a graph server that is capable of exposing any &lt;a href=&quot;http://blueprints.tinkerpop.com&quot;&gt;Blueprints&lt;/a&gt; enabled graph through different interfaces, such as &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;.  Rexster is &amp;#8220;packaged&amp;#8221; with the common Blueprints implementations that are maintained by &lt;a href=&quot;http://tinkerpop.com&quot;&gt;TinkerPop&lt;/a&gt;.  At this time, given Rexster 0.8, those implementations include:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://wiki.github.com/tinkerpop/gremlin/tinkergraph&quot;&gt;TinkerGraph&lt;/a&gt; in-memory graph&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://neo4j.org/&quot;&gt;Neo4j&lt;/a&gt; graph database&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.orientechnologies.com/&quot;&gt;OrientDB&lt;/a&gt; graph database&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.sparsity-technologies.com/dex&quot;&gt;&lt;span class=&quot;caps&quot;&gt;DEX&lt;/span&gt;&lt;/a&gt; graph database&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.openrdf.org&quot;&gt;Sesame 2.0&lt;/a&gt; compliant &lt;span class=&quot;caps&quot;&gt;RDF&lt;/span&gt; stores&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Outside of these implementations, there are others that are not maintained by TinkerPop, such as the one from &lt;a href=&quot;http://www.infinitegraph.com/&quot;&gt;InfiniteGraph&lt;/a&gt;.  There is also the recently submitted &lt;a href=&quot;https://github.com/tinkerpop/blueprints/pull/238&quot;&gt;pull request&lt;/a&gt; that implements Blueprints over &lt;a href=&quot;http://datomic.com/&quot;&gt;Datomic&lt;/a&gt;, which, as of today, has not yet been merged.  In addition, one might find themselves in a scenario where they have some sort of &amp;#8220;private&amp;#8221; Blueprints implementation over some other data store.  Even though Rexster doesn&amp;#8217;t have explicit, native understanding of these externalized implementations, it is capable of serving them if configured properly to do so.&lt;/p&gt;
&lt;p&gt;Rexster is configured via its &lt;code&gt;rexster.xml&lt;/code&gt; file.  A typical configuration of a TinkerGraph looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;graphs&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-name&amp;gt;&lt;/span&gt;mygraph&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-name&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-type&amp;gt;&lt;/span&gt;tinkergraph&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-type&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graphs&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This configuration could also be written as:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;graphs&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-name&amp;gt;&lt;/span&gt;mygraph&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-name&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-type&amp;gt;&lt;/span&gt;com.tinkerpop.rexster.config.TinkerGraphGraphConfiguration&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-type&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graphs&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;&amp;lt;graph-type&amp;gt;&lt;/code&gt; is now pointing to a specific &lt;code&gt;com.tinkerpop.rexster.config.GraphConfiguration&lt;/code&gt; implementation.  The &lt;code&gt;GraphConfiguration&lt;/code&gt; interface looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GraphConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;configureGraphInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GraphConfigurationException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Classes that implement this interface are responsible for constructing a Blueprints graph for Rexster, thereby allowing Rexster to extend itself to serve any Blueprints graph.  To implement the &lt;code&gt;configureGraphInstance&lt;/code&gt; method, simply construct a new graph using the &lt;code&gt;properties&lt;/code&gt; passed to it.  The &lt;code&gt;properties&lt;/code&gt; are just the root level key/values within the &lt;code&gt;&amp;lt;graph&amp;gt;&lt;/code&gt; element.  For example, TinkerGraph configuration in Rexster allows for a &lt;graph-location&gt; parameter, as in:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;graph&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-name&amp;gt;&lt;/span&gt;gratefulgraph&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-name&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-type&amp;gt;&lt;/span&gt;com.tinkerpop.rexster.config.TinkerGraphGraphConfiguration&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-type&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;graph-location&amp;gt;&lt;/span&gt;data/graph-example-2&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph-location&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/graph&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code extracts that value from the &lt;code&gt;properties&lt;/code&gt;, returning &lt;code&gt;null&lt;/code&gt; if it does not exist in the &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; configuration:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graphFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;graph-location&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key/value pairs are great, but &lt;code&gt;properties&lt;/code&gt; can also handle more complex parameters.  A good example of that is shown in the &lt;a href=&quot;https://github.com/tinkerpop/rexster/blob/master/rexster-server/src/main/java/com/tinkerpop/rexster/config/Neo4jGraphConfiguration.java&quot;&gt;Neo4jGraphConfiguration&lt;/a&gt; where an arbitrary set of sub-properties are passed to the &lt;code&gt;GraphConfiguration&lt;/code&gt; implementation, which in turn is passed to the &lt;code&gt;Neo4jGraph&lt;/code&gt; instance.&lt;/p&gt;
&lt;p&gt;To expose the custom configuration to Rexster, the process is the same as a &lt;a href=&quot;https://github.com/tinkerpop/rexster/wiki/Extensions&quot;&gt;Rexster Extensions&lt;/a&gt;. Simple copy the compiled &lt;span class=&quot;caps&quot;&gt;JAR&lt;/span&gt; containing the custom configuration in the &lt;code&gt;REXSTER_HOME/ext&lt;/code&gt; directory.  It will then be possible to reference the class within &lt;code&gt;rexster.xml&lt;/code&gt;.  While the built-in configurations for Rexster have short-hand configuration options, such as &lt;code&gt;tinkergraph&lt;/code&gt; or &lt;code&gt;neo4jgraph&lt;/code&gt; for the &lt;code&gt;&amp;lt;graph-type&amp;gt;&lt;/code&gt;, it is not possible to alias a custom implementation.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Blog Post - Multitenant Graph Applications</title>
   <link href="http://spmallette.github.com/2012/04/09/multitenant-graph-post.html"/>
   <updated>2012-04-09T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2012/04/09/multitenant-graph-post</id>
   <content type="html">&lt;p&gt;I co-authored this &lt;a href=&quot;http://thinkaurelius.com/2012/04/06/multitenant-graph-applications/&quot;&gt;blog post&lt;/a&gt; on multitenancy in systems backed by graph databases.  Multitenancy is actually easily achieved using TinkerPop Blueprints (as of version 1.2) and its &lt;a href=&quot;https://github.com/tinkerpop/blueprints/wiki/Partition-Implementation&quot;&gt;PartitionGraph&lt;/a&gt; graph wrapper.  The running example we used follows the healthcare industry, specifically a multitenant &lt;span class=&quot;caps&quot;&gt;EHR&lt;/span&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>IIS Configuration Behind Elastic Load Balancer With SSL</title>
   <link href="http://spmallette.github.com/2012/01/01/aws-elb-ssl-with-iis.html"/>
   <updated>2012-01-01T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2012/01/01/aws-elb-ssl-with-iis</id>
   <content type="html">&lt;p&gt;I wanted to set up an Amazon Elastic Load Balancer(&lt;span class=&quot;caps&quot;&gt;ELB&lt;/span&gt;) with &lt;span class=&quot;caps&quot;&gt;SSL&lt;/span&gt; in front of a set of &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt; servers, where the &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt; servers simply served over port 80.  I further wanted it to work such that requests to port 80 forwarded to the &lt;span class=&quot;caps&quot;&gt;SSL&lt;/span&gt; port on 443. Basically, the &lt;span class=&quot;caps&quot;&gt;ELB&lt;/span&gt; port forwarding looks like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;ELB&lt;/span&gt; forwards requests on port 443 to port 80 of &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;ELB&lt;/span&gt; forwards requests on port 80 to port 80 of &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found that this could be peformed pretty easily with the &lt;a href=&quot;http://www.iis.net/download/urlrewrite&quot;&gt;&lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; Rewrite Module&lt;/a&gt; with the following configuration:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
    ...
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;rewrite&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xdt:Transform=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Insert&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;rules&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;rule&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;HTTPs Redirect&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;stopProcessing=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;match&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;url=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;conditions&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;add&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;{ALL_HTTP}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;matchType=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Pattern&amp;quot;&lt;/span&gt; 
                         &lt;span class=&quot;na&quot;&gt;pattern=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;HTTP_X_FORWARDED_PROTO:https&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ignoreCase=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;negate=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/conditions&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Redirect&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;url=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;https://{HTTP_HOST}/{R:1}&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/rules&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/rewrite&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The key is knowing that the &lt;span class=&quot;caps&quot;&gt;ELB&lt;/span&gt; passes the &lt;code&gt;X_FORWARDED_PROTO&lt;/code&gt; request header.  By checking if the request did not originate as &lt;code&gt;https&lt;/code&gt;, the client can be redirected to their requested &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; with &lt;span class=&quot;caps&quot;&gt;SSL&lt;/span&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>But the Tests Ran...</title>
   <link href="http://spmallette.github.com/2011/09/24/but-the-tests-ran.html"/>
   <updated>2011-09-24T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/09/24/but-the-tests-ran</id>
   <content type="html">&lt;p&gt;I write this as a bit of a penance and a reminder after a difficult day as a software engineer.  A great set of automated tests are critical to building great software.  For a test suite to be considered &amp;#8220;great&amp;#8221; it should likely extend beyond just some quantitative metric like the total number of tests or code coverage percentages.  Greatness is additionally defined by the quality of the test set as determined by those who know the code and the features.&lt;/p&gt;
&lt;p&gt;Greatness can breed confidence.  Confidence to refactor.  Confidence to release and deploy.&lt;/p&gt;
&lt;p&gt;With all this confidence around, it&amp;#8217;s easy to make a different kind of mistake that all that greatness can&amp;#8217;t protect you from: a poor or misunderstood design choice.  We sometimes choose the less than optimal path purposely and stow it away as accepted technical debt.  Other times, the sub-optimal choice occurs without intention and it&amp;#8217;s a problem than lies in wait for someone to uncover it.  In either case, these kinds of choices can produce scenarios that poke holes in the &amp;#8220;great&amp;#8221; test suite and the confidence you have because of the &amp;#8220;great&amp;#8221; test suite won&amp;#8217;t allow you to see the side effects coming.  The end results are bugs in the next release and your wondering how the test suite passed without you uncovering the problem before the release date.&lt;/p&gt;
&lt;p&gt;The general warning here is to not become so reliant on your tests that you use them as the ultimate truth as to the quality of what you are doing.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Jersey - "charset" in Content-Type</title>
   <link href="http://spmallette.github.com/2011/05/29/jersey-charset-in-content-type.html"/>
   <updated>2011-05-29T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/05/29/jersey-charset-in-content-type</id>
   <content type="html">&lt;p&gt;In working with &lt;a href=&quot;http://jersey.java.net/&quot;&gt;Jersey&lt;/a&gt; for &lt;a href=&quot;http://rexster.tinkerpop.com&quot;&gt;Rexster&lt;/a&gt;, the issue arose some time ago that the character set was not being established in the &lt;code&gt;Content-Type&lt;/code&gt; of the response.  Therefore, the &lt;code&gt;Content-Type&lt;/code&gt; was being set this way:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Content-Type:application/json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;as opposed to&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Content-Type:application/json;charset=ISO-8859-1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While the omission of the &lt;code&gt;charset&lt;/code&gt; did not prevent &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; from being served from Rexster, it did create some problems with certain clients that expected that value to be set.  Moreover, the default &lt;code&gt;charset&lt;/code&gt; of &lt;span class=&quot;caps&quot;&gt;ISO&lt;/span&gt;-8859-1 created problems for some users who had unicode in their data and needed the &lt;code&gt;charset&lt;/code&gt; established to &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8.&lt;/p&gt;
&lt;p&gt;One way to solve the problem within Jersey is to append the &lt;code&gt;charset&lt;/code&gt; programmatically into the header:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resultList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;application/json;charset=UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aside from the fact that the inline coding of the &lt;code&gt;Content-Type&lt;/code&gt; left no option for multiple output formats (as described in this &lt;a href=&quot;http://java.net/jira/browse/JERSEY-318&quot;&gt;Jersey Issue&lt;/a&gt; and the subsequentally created &lt;a href=&quot;http://java.net/jira/browse/JSR311-101&quot;&gt;&lt;span class=&quot;caps&quot;&gt;JAX&lt;/span&gt;-RS Specification&lt;/a&gt; ), it also isn&amp;#8217;t a terribly elegant solution.  It means that you have to ensure that every service method established has that bit of code appended to it when the response object is returned.  I thought that it would be nice to centralize that functionality a bit within Rexster, attempting several solutions, until I came up with one that worked.&lt;/p&gt;
&lt;p&gt;Rexster implements a Jersey &lt;code&gt;ContainerResponseFilter&lt;/code&gt;.  The simplified code for this filter is shown in the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.sun.jersey.spi.container.ContainerRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.sun.jersey.spi.container.ContainerResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.sun.jersey.spi.container.ContainerResponseFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.ws.rs.core.MediaType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CharsetResponseFilter&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContainerResponseFilter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContainerResponse&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ContainerRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContainerResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;MediaType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contentType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMediaType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHttpHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putSingle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;;charset=UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This filter is then plugged into Jersey through &lt;code&gt;rexster.xml&lt;/code&gt;.  Of course, other applications using Jersey would simply add it through the configuration of the Jersey servlet or programmatically as in:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;ServletAdapter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jerseyAdapter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServletAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jerseyAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addInitParameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;com.sun.jersey.spi.container.ContainerResponseFilters&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;com.my.package.MyResponseFilter&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously the &lt;code&gt;CharsetResponseFilter&lt;/code&gt; shown above is overly simplified.  Rexster does some basic checks to see if the &lt;code&gt;charset&lt;/code&gt; is already established prior to overriding the settings.  This allows individual service methods to be ultimately in charge of setting that value.  This is useful for &lt;a href=&quot;https://github.com/tinkerpop/rexster/wiki/Extensions&quot;&gt;Rexster Extensions&lt;/a&gt; where returned media types can be disparate.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Avoid Preemptive Branching</title>
   <link href="http://spmallette.github.com/2011/05/01/avoid-preemptive-branching.html"/>
   <updated>2011-05-01T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/05/01/avoid-preemptive-branching</id>
   <content type="html">&lt;p&gt;I really like this &lt;a href=&quot;http://blogs.agilefaqs.com/2011/04/18/preemptively-branching-a-release-candidate-and-splitting-teams-considered-harmful/&quot;&gt;blog post&lt;/a&gt; on the dangers of preemptive branching.  It basically points out that the act of branching for a release candidate should be performed as late as possible (if at all) and that the hardening process should utilize the entire team.  This approach helps to avoid a series of problems which will hamper the project and the team with complexity and sub-optimal conditions. In the end, rather than getting value from splitting team effort, a preemptive branch actually diminishes the ability of the team to deliver.  Some of the ugly results will be decreases in code quality, over-specialization and knowledge centralization of individual team members, general failure to meet the goals that the branch was supposed to help solve in the first place, increased technical debt, and overall reduction in agility.&lt;/p&gt;
&lt;p&gt;The author lists a number of reasons why preemptive branching is problematic.  I find this one to be quite damaging:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Increases the work-in-progress and creates a lot of planning, management, version-control, testing, etc. overheads.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The daily challenge of playing traffic cop to a team of committers under pressure to be &amp;#8220;done&amp;#8221; can be quite time consuming and frustrating.  Consider some of the annoyances:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Every individual on the team needs to understand where they need to do their work.  You might have a &lt;em&gt;hardening team&lt;/em&gt; working in the release branch, but there is a good chance that these team members are also the &amp;#8220;most trusted and knowledgeable&amp;#8221; members of your team.  As such, there will be cases where they will be needed to split their time between the release branch and mainline.  While what needs to be communicated is typically simple (eg. Bug Fix A goes in mainline and Bug Fix B goes in the release branch), doing it in an effective way requires process and takes time.&lt;/li&gt;
	&lt;li&gt;Even if the team has overcome the hardship above, there is always the inevitable realization that a change that went to mainline was something that the release branch depended on for hardening.  Those changes then need to be recreated manually in the release branch, which inevitably create merge conflicts when going back to mainline.&lt;/li&gt;
	&lt;li&gt;The longer a release branch lives, the greater the chance that the merge path among branches can become complex or in the worst case impossible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to the reasoning of the author against a preemptive branch, I also see the following risks:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;All the merging and branching strategy that I describe above can easily become overly centralized such that only one person knows what is going on in source control.&lt;/li&gt;
	&lt;li&gt;The goal of just hardening a release is sometimes lost the longer the release branch exists.  As the release remains in hardening mode past its expected delivery date, the demand for additional features promised can pressure the team into sneaking some of those features into the release branch.&lt;/li&gt;
	&lt;li&gt;The release branch may fail to ever truly harden.  This failure could be a result of the previously described feature-sneak, but may also be the result of too much technical debt.&lt;/li&gt;
	&lt;li&gt;The sum negative impact of a preemptive branch chips away at the team&amp;#8217;s agility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can&amp;#8217;t seem to think of any easy ways out of a release branch started too early, especially once the project is weakened by several cycles of this type of branching.  Preventing future preemptive release branches is likely the best thing to do, though that may only be possible after accepting delays in the release schedule.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>.NET Client for Kafka Multi-Request</title>
   <link href="http://spmallette.github.com/2011/03/28/dotnet-client-for-kafka-multi-request.html"/>
   <updated>2011-03-28T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/03/28/dotnet-client-for-kafka-multi-request</id>
   <content type="html">&lt;p&gt;I made some enhancements to the .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; client for &lt;a href=&quot;https://github.com/kafka-dev/kafka&quot;&gt;Kafka&lt;/a&gt; that were recently accepted into the project mainline.  Aside from some basic namespacing reorganization and some improved error handling, I added two major bits: Multi-produce and Multi-fetch batch operations.&lt;/p&gt;
&lt;p&gt;The Multi-produce and Multi-fetch operations provide for a way to group up multiple ProducerRequest or FetchRequest objects and send them to Kafka in batch.  The Multi-produce works like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producerRequests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;topic-a&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;1: &amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UtcNow&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;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;topic-b&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;2: &amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UtcNow&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;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;topic-z&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;3: &amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UtcNow&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;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;zopic-z&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;4: &amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UtcNow&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;n&quot;&gt;MultiProducerRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producerRequest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MultiProducerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producerRequests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Producer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9092&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producerRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the list of producerRequests pushes messages to three different topics and within one of those topic (topic-z), pushes to two different partitions.  While the example above pushes a different message to each topic, it would not be hard to imagine a scenario where one might utilize this batching approach to send the same message to multiple topics and/or partitions.&lt;/p&gt;
&lt;p&gt;The Multi-fetch works in a similar fashion:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9092&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MultiFetchRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MultiFetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;topic-a&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;topic-b&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;tobic-z&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FetchRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;tobic-z&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&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;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Consume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The important bit to note in this example is that the Consume method returns a List of a List of Message objects.  I&amp;#8217;ll refer to that &amp;#8220;inner&amp;#8221; list as the &amp;#8220;message set&amp;#8221;.  In the example above, there would be four message sets (one for each request), where the index of the request sent to Kafka in the batch, matches to the position in the List of message sets.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>.NET Client for Kafka Checkpoint</title>
   <link href="http://spmallette.github.com/2011/03/11/dotnet-client-for-kafka-checkpoint.html"/>
   <updated>2011-03-11T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/03/11/dotnet-client-for-kafka-checkpoint</id>
   <content type="html">&lt;p&gt;I finished enough of the .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; client for &lt;a href=&quot;https://github.com/kafka-dev/kafka&quot;&gt;Kafka&lt;/a&gt; that I wrote about in my &lt;a href=&quot;http://stephen.genoprime.com/2011/03/01/dotnet-client-for-kafka.html&quot;&gt;last post&lt;/a&gt; to feel comfortable in sending out a pull request to the Kafka team.  I just received notification moments ago that it was accepted into the project and merged into mainline.&lt;/p&gt;
&lt;p&gt;The client covers basic Producer and Consumer operations.  The Producer can send both synchronous and asynchronous messages.  The Consumer can retrieve messages and offsets from Kafka, but at the moment, unlike other client consumers that were developed, it does not yet have a mechanism for polling.  I hesitantly left that bit out as I was concerned with &amp;#8220;completeness&amp;#8221; of the client &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, but my primary need was related to sending messages to Kafka through .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; environments and not necessarily consuming them, so it was lower priority for me.  Perhaps that will be a later addition to the client.  You can read more about the client &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; in the &lt;a href=&quot;https://github.com/kafka-dev/kafka/blob/master/clients/csharp/README.md&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;.md&lt;/a&gt; for the client.&lt;/p&gt;
&lt;p&gt;While the demand for a .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; client is arguably low, given the Kafka target domain and environment, there might be a few progressive .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; minds who could find some value in what I&amp;#8217;ve contibuted.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>.NET Client for Kafka</title>
   <link href="http://spmallette.github.com/2011/03/01/dotnet-client-for-kafka.html"/>
   <updated>2011-03-01T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/03/01/dotnet-client-for-kafka</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s a bit early stage, but I forked the &lt;a href=&quot;https://github.com/kafka-dev/kafka&quot;&gt;Kafka&lt;/a&gt; project on GitHub today to add a .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; client.  Kafka is a distributed publish/subscribe messaging system and looks very promising.  It is aimed at capturing activity stream data in the vein of Facebook&amp;#8217;s &lt;a href=&quot;https://github.com/facebook/scribe&quot;&gt;Scribe&lt;/a&gt; and Cloudera&amp;#8217;s &lt;a href=&quot;https://github.com/cloudera/flume&quot;&gt;Flume&lt;/a&gt;.  I&amp;#8217;ve never look to deeply into Scribe, but was very interested in Flume to the very close point of forking it to try to add some features. When I came across Kafka I made an immediate connection to its architecture (probably due to the simple publish/subscribe model) and thought of an area where I might make use of it.&lt;/p&gt;
&lt;p&gt;The area where I might make use of it, involves a bit of .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; so I needed a .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; client that would communicate with Kafka for me.  Since I couldn&amp;#8217;t find anyone who was doing that, I figured I&amp;#8217;d strike a few lines of code and get it done.&lt;/p&gt;
&lt;p&gt;I executed the first commit to &lt;a href=&quot;https://github.com/spmallette/kafka&quot;&gt;my fork&lt;/a&gt; which contained basic support for a .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; message producer.  The basic approach to sending off one or more messages looks something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;kafka 1.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payloadData1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payloadData1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;kafka 2.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payloadData2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payloadData2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Producer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;192.168.50.201&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9092&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I need to get a basic consumer working next and then think about some more advanced features for the library.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Beyond Arbitrary Versioning</title>
   <link href="http://spmallette.github.com/2011/02/10/beyond-arbitrary-versioning.html"/>
   <updated>2011-02-10T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/02/10/beyond-arbitrary-versioning</id>
   <content type="html">&lt;p&gt;While reading more about &lt;a href=&quot;http://zombie.labnotes.org/&quot;&gt;Zombie.js&lt;/a&gt; and looking at javascript unit testing options, I came across &lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.js&lt;/a&gt;.  I liked the look of both and am quite interested to see how they might help on the various projects I&amp;#8217;m associated with at the moment.  Unit testing javascript and browser testing can be a missing link in even the most complete test suites and I&amp;#8217;m quite interested in understanding how to fill that gap.&lt;/p&gt;
&lt;p&gt;Before I got terribly far in my research, however, I noted a link at the bottom of the &lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.js&lt;/a&gt; web site.  It read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sinon uses &lt;a href=&quot;http://semver.org/&quot;&gt;Semantic versioning&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Semantic Versioning site is little more than a single page that describes a simple specification for how to increment version numbers of releases for purpose of more clearly conveying the meaning of a change to a public &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.  Attaching a defined meaning to the version number, takes away the somewhat arbitrary method in which version numbers can be assigned.  Even when version numbering strategies are not necessarily arbitrary, and definitions exist within the project for version number increments, adhering to a documented public standard makes it easier for users to understand the meaning of change.&lt;/p&gt;
&lt;p&gt;As the manifesto states quite clearly, Semantic Versioning &amp;#8220;is not a new or revolutionary idea&amp;#8221;.  As developers, we think in these versioning terms all the time.  I think that I found it so interesting because Semantic Versioning creates an opportunity to not only think in these terms all the time, but to think in the &lt;em&gt;same&lt;/em&gt; terms all the time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>I Guess This is Me</title>
   <link href="http://spmallette.github.com/2011/01/21/i-guess-this-is-me.html"/>
   <updated>2011-01-21T00:00:00+00:00</updated>
   <id>http://spmallette.github.com/2011/01/21/i-guess-this-is-me</id>
   <content type="html">&lt;p&gt;I was asked to create an avatar for use on the &lt;a href=&quot;http://tinkerpop.com&quot;&gt;tinkerpop&lt;/a&gt; web site.  It is debatable as to whether or not I&amp;#8217;ve captured my likeness in any way, shape or form, but it&amp;#8217;s close enough for purposes of the exercise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.gravatar.com/avatar/65f4574b28165676ebb4bf7b644489ff?s=80&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A reasonable facsimile&amp;#8230;I guess.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
