<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
 <title>www.thoughtworks.com aggregator</title>
 <link>http://www.thoughtworks.com/blogs/alumni</link>
 <description>www.thoughtworks.com - aggregated feeds in category ThoughtWorks Alumni</description>
 <language>en</language>
<item>
 <title>Patrick Farley: Getting The very best Offer When Shopping Online</title>
 <link>http://klankboomklang.com/getting-best-offer-shopping-online/</link>
 <description>&lt;p&gt;Whether you have to get a vehicle or some groceries, anything can be purchased through the Web it appears. You are likewise able to patronize a brand name&amp;#8217;s website, merchant sites, and auctions online. New or utilized, you can purchase almost everything at a discount rate. Follow this info to discover and benefit from good deals online.&lt;/p&gt;
&lt;p&gt;A terrific suggestion to keep in mind when you&amp;#8217;re considering &lt;a title=&quot;You Can Discover Online Deals With These Tips&quot; href=&quot;http://klankboomklang.com/can-discover-online-deals-tips/&quot;&gt;online shopping&lt;/a&gt; is to ensure the website is official. You do not wish to be providing your charge card info away to somebody who might possibly rip-off you. Constantly take a look at the website to inform if it&amp;#8217;s expert and safe to utilize.&lt;/p&gt;
&lt;p&gt;Try to find discount coupons prior to buying an item online. Many online establishments constantly have some advertising offers going on. If you do not discover any details about existing offers on the website of the online establishment, view other websites. Clients often share their voucher codes on message boards or couponning blog sites.&lt;/p&gt;
&lt;p&gt;Make sure where you send your charge card details. When you are going shopping online, constantly utilize safe and secure websites. These are websites that have actually taken steps to secure your important info. A protected web site will certainly start with HTTPS instead of the basic HTTP. There will certainly likewise be a locked icon, either in your address or condition bar, depending upon which browser you make use of.&lt;/p&gt;
&lt;p&gt;If you intend on buying a product that you could wish to return, patronize a shop that provides totally free returns or exchanges. Lots of online shops desire your company so they will certainly provide things like totally free returns or exchanges. This alternative is fantastic if you are not sure if a product will certainly fit your requirements.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re paying too much with expedited shipping online, attempt to be client by utilizing basic shipping. The speed of conventional shipping simply may shock you. Plus, you conserve a lot cash by waiting simply a couple days more.&lt;/p&gt;
&lt;p&gt;If an offer appears too great to be real, it is. Remember that any individual can introduce an online establishment and not all establishments all trustworthy. Do more study on various establishments prior to choosing where you wish to acquire your items from. Do pass by a really inexpensive item if it is offered by an establishment with a bad credibility and reputation.&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;//www.youtube.com/embed/QCxKcHfZj80?rel=0&quot; width=&quot;640&quot; height=&quot;360&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Just store at online retail websites that you trust. It is all too simple for somebody to simply produce a store on the internet with some item info to offer product. Do some study on the seller&amp;#8217;s credibility and reputation prior to you supply any charge card details. This will certainly assist you prevent any frauds out there.&lt;/p&gt;
&lt;p&gt;Keep in mind to think about not just the product&amp;#8217;s real expense, however likewise just how much will certainly be charged for shipping. A product could cost a couple of dollars more at one website, however if they provide totally free shipping, it may wind up being cheaper total. If shipping costs aren&amp;#8217;t provided in advance, you can examine them by starting the checkout procedure. The shipping expense will certainly be revealed prior to the order is full.&lt;/p&gt;
&lt;p&gt;In order to minimize shipping costs, it is best to obtain everything you require in one order. If you do refrain it by doing this, you will certainly need to pay a different shipping cost for each order you make. This will certainly wind up costing you a fortune in the long run.&lt;/p&gt;
&lt;p&gt;Pick online shops which provide a live chat alternative. Live chat is a quicker, easier method to deal with a concerns or concerns you may have. In addition, you might be able to work out a much better offer using Live Chat. Numerous websites provide such discount rates or totally free shipping if you make your order right then, as opposed to waiting.&lt;/p&gt;
&lt;p&gt;When we go to the establishment to acquire a product, we typically end up leaving with a couple of impulse purchases also. These products can swiftly build up and take a toll on your checking account! Purchasing things online can be an exceptional method to reduce the quantity of impulse purchases that you make.&lt;/p&gt;
&lt;p&gt;Purchasing presents and vacation shopping can be made a lot simpler using the web. You can acquire a product and have it delivered to the recipient without ever laving your house. You can likewise decide to purchase a gift-card to a site that you understand has products that they will certainly such as. This can conserve you money and time and guarantee that the recipient will certainly enjoy your present and consideration.&lt;/p&gt;
&lt;p&gt;If you lead a busy way of life, or work odd hours, it can frequently be tough to make it to the establishment prior to they close. Online shopping, nevertheless, is something that you can do at any hour of the day (or night!), and might for that reason be a more practical option for you.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rebelmouse.com/swirlio/swirlio-buy-now-and-get-good-a-797362148.html&quot;&gt;Swirlio&lt;/a&gt; desert maker. Buy now&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s constantly brand-new techniques to discover, no matter how skilled a consumer you are. A little details can make a huge distinction in the kind of offer you have the ability to discover. Read this short article and others like it if you wish to discover brand-new and interesting strategies to refine your strategy to online shopping.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://amazon.com&quot;&gt;Amazon.com&lt;/a&gt; best online store&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The post &lt;a rel=&quot;nofollow&quot; href=&quot;http://klankboomklang.com/getting-best-offer-shopping-online/&quot;&gt;Getting The very best Offer When Shopping Online&lt;/a&gt; appeared first on &lt;a rel=&quot;nofollow&quot; href=&quot;http://klankboomklang.com&quot;&gt;Save Big Online Shopping&lt;/a&gt;.&lt;/p&gt;</description>
 <pubDate>Wed, 10 Dec 2014 13:15:38 +0000</pubDate>
</item>
<item>
 <title>Trisha Gee: New Blog Post: New Year, New Adventures</title>
 <link>http://mechanitis.blogspot.com/2014/12/new-blog-post-new-year-new-adventures.html</link>
 <description>&lt;a href=&quot;http://trishagee.github.io/post/new_year_new_adventures/&quot;&gt;New Blog Post: New Year, New Adventures&lt;/a&gt;</description>
 <pubDate>Wed, 10 Dec 2014 11:16:00 +0000</pubDate>
</item>
<item>
 <title>Brian Oxley: Java validation</title>
 <link>http://binkley.blogspot.com/2013/10/signing-maven-releases-with-gpg-while.html</link>
 <description>&lt;p&gt;Martin Fowler posted &lt;a href=&quot;http://martinfowler.com/articles/replaceThrowWithNotification.html&quot; title=&quot;Replacing Throwing Exceptions with Notification in Validations&quot;&gt;&lt;cite&gt;Replacing Throwing Exceptions with Notification in Validations&lt;/cite&gt;&lt;/a&gt; discussing alternatives to data validation than throwing exceptions.  There are off-the-shelf solutions such as &lt;a href=&quot;http://commons.apache.org/proper/commons-validator/&quot; title=&quot;Commons Validator&quot;&gt;Commons Validator&lt;/a&gt; (XML driven) or &lt;a href=&quot;http://beanvalidation.org/&quot; title=&quot;Bean Validation&quot;&gt;Bean Validation&lt;/a&gt; (annotation driven) which are complete frameworks.&lt;/p&gt; &lt;p&gt;There is more to these frameworks than I suggest, but to explore Fowler&#039;s post better I quickly coded up my own simple-minded approach:&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;public final class ValidationMain {
    public static void main(final String... args) {
        final Notices notices = new Notices();
        notices.add(&quot;Something went horribly wrong %d time(s)&quot;, 1);
        try {
            foo(null);
        } catch (final Exception e) {
            notices.add(e);
        }
        notices.forEach(err::println);
        notices.fail(IllegalArgumentException::new);
    }

    public static String foo(final Object missing) {
        return missing.toString();
    }
}&lt;/pre&gt; &lt;p&gt;Output on stderr:&lt;/p&gt; &lt;pre&gt;lab.Notices$Notice@27f8302d
lab.Notices$Notice@4d76f3f8
Exception in thread &quot;main&quot; java.lang.IllegalArgumentException: 2 notices:
 Something went horribly wrong 1 time(s)
 at lab.ValidationMain.main(ValidationMain.java:21)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:483)
 at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
 Suppressed: java.lang.IllegalArgumentException: Only 1 reason(s)
  at lab.ValidationMain.main(ValidationMain.java:14)
 Suppressed: java.lang.IllegalArgumentException
  at lab.ValidationMain.main(ValidationMain.java:18)
 Caused by: java.lang.NullPointerException
  at lab.ValidationMain.foo(ValidationMain.java:25)
  at lab.ValidationMain.main(ValidationMain.java:16)&lt;/pre&gt; &lt;p&gt;And the &lt;code&gt;Notices&lt;/code&gt; class: &lt;pre class=&quot;code&quot;&gt;public final class Notices
        implements Iterable&amp;lt;Notice&amp;gt; {
    private final List&amp;lt;Notice&amp;gt; notices = new ArrayList&amp;lt;&amp;gt;(0);

    public void add(final String reason, final Object... args) {
        // Duplicate code so stack trace keeps same structure
        notices.add(new Notice(null, reason, args));
    }

    public void add(final Throwable cause) {
        // Duplicate code so stack trace keeps same structure
        notices.add(
                new Notice(cause, null == cause ? null : cause.getMessage()));
    }

    public void add(final Throwable cause, final String reason,
            final Object... args) {
        // Duplicate code so stack trace keeps same structure
        notices.add(new Notice(cause, reason, args));
    }

    public &amp;lt;E extends Exception&amp;gt; void fail(
            final BiFunction&amp;lt;String, Throwable, E&amp;gt; ctor)
            throws E {
        final E e = ctor.apply(toString(), null);
        notices.forEach(n -&amp;gt; e.addSuppressed(n.as(ctor)));
        final List&amp;lt;StackTraceElement&amp;gt; frames = asList(e.getStackTrace());
        // 2 is the magic number: lambda, current
        e.setStackTrace(frames.subList(2, frames.size())
                .toArray(new StackTraceElement[frames.size() - 2]));
        throw e;
    }

    @Override
    public Iterator&amp;lt;Notice&amp;gt; iterator() {
        return unmodifiableList(notices).iterator();
    }

    @Override
    public String toString() {
        if (notices.isEmpty())
            return &quot;0 notices&quot;;
        final String sep = lineSeparator() + &quot;\t&quot;;
        return notices.stream().
                map(Notice::reason).
                filter(Objects::nonNull).
                collect(joining(sep,
                        format(&quot;%d notices:&quot; + sep, notices.size()), &quot;&quot;));
    }

    public static final class Notice {
        // 4 is the magic number: Thread, init, init, addError, finally the
        // user code
        private final StackTraceElement location = currentThread()
                .getStackTrace()[4];
        private final Throwable cause;
        private final String reason;
        private final Object[] args;

        private Notice(final Throwable cause, final String reason,
                final Object... args) {
            this.cause = cause;
            this.reason = reason;
            this.args = args;
        }

        public Throwable cause() {
            return cause;
        }

        public String reason() {
            return null == reason ? null : format(reason, args);
        }

        private &amp;lt;E extends Exception&amp;gt; E as(
                final BiFunction&amp;lt;String, Throwable, E&amp;gt; ctor) {
            final E e = ctor.apply(reason(), cause);
            e.setStackTrace(new StackTraceElement[]{location});
            return e;
        }
    }
}&lt;/pre&gt; &lt;p&gt;Comments:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;I manipulate the stack traces to focus on the caller&#039;s point of view.  This is the opposite of, say, Spring Framework.&lt;/li&gt; &lt;li&gt;I haven&#039;t decided on what an intelligent &lt;code&gt;toString()&lt;/code&gt; should look like for &lt;code&gt;Notice&lt;/code&gt;&lt;/li&gt; &lt;li&gt;Java 8 lambdas really shine here.  Being able to use exception constructors as method references is a win.&lt;/li&gt;&lt;/ul&gt;</description>
 <pubDate>Tue, 09 Dec 2014 21:54:00 +0000</pubDate>
</item>
<item>
 <title>Mark Needham: R: Cleaning up and plotting Google Trends data</title>
 <link>http://feedproxy.google.com/~r/MarkNeedham/~3/toNd4uQ-WQY/</link>
 <description>&lt;p&gt;
I recently came across an excellent article written by Stian Haklev in which he describes &lt;a href=&quot;http://reganmian.net/blog/2014/10/14/starting-data-analysiswrangling-with-r-things-i-wish-id-been-told/&quot;&gt;things he wishes he&amp;#8217;d been told before starting out with R&lt;/a&gt;, one being to &lt;strong&gt;do all data clean up in code&lt;/strong&gt; which I thought I&amp;#8217;d give a try.
&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
My goal is to leave the raw data completely unchanged, and do all the transformation in code, which can be rerun at any time. &lt;/p&gt;
&lt;p&gt;While I&amp;#8217;m writing the scripts, I&amp;#8217;m often jumping around, selectively executing individual lines or code blocks, running commands to inspect the data in the REPL (read-evaluate-print-loop, where each command is executed as soon as you type enter, in the picture above it&amp;#8217;s the pane to the right), etc. &lt;/p&gt;
&lt;p&gt;But I try to make sure that when I finish up, the script is runnable by itself.
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;
I thought the &lt;a href=&quot;http://www.google.com/trends/explore#q=neo4j&quot;&gt;Google Trends data set&lt;/a&gt; would be an interesting one to play around with as it gives you a CSV containing several different bits of data of which I&amp;#8217;m only interested in &amp;#8216;interest over time&amp;#8217;.
&lt;/p&gt;
&lt;p&gt;
It&amp;#8217;s not very easy to automate the download of the CSV file so I did that bit manually and automated everything from there onwards.
&lt;/p&gt;
&lt;p&gt;
The first step was to read the CSV file and explore some of the rows to see what it contained:
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; library(dplyr)
&amp;nbsp;
&amp;gt; googleTrends = read.csv(&amp;quot;/Users/markneedham/Downloads/report.csv&amp;quot;, row.names=NULL)
&amp;nbsp;
&amp;gt; googleTrends %&amp;gt;% head()
##                   row.names Web.Search.interest..neo4j
## 1 Worldwide; 2004 - present                           
## 2        Interest over time                           
## 3                      Week                      neo4j
## 4   2004-01-04 - 2004-01-10                          0
## 5   2004-01-11 - 2004-01-17                          0
## 6   2004-01-18 - 2004-01-24                          0
&amp;nbsp;
&amp;gt; googleTrends %&amp;gt;% sample_n(10)
##                   row.names Web.Search.interest..neo4j
## 109 2006-01-08 - 2006-01-14                          0
## 113 2006-02-05 - 2006-02-11                          0
## 267 2009-01-18 - 2009-01-24                          0
## 199 2007-09-30 - 2007-10-06                          0
## 522 2013-12-08 - 2013-12-14                         88
## 265 2009-01-04 - 2009-01-10                          0
## 285 2009-05-24 - 2009-05-30                          0
## 318 2010-01-10 - 2010-01-16                          0
## 495 2013-06-02 - 2013-06-08                         79
## 28  2004-06-20 - 2004-06-26                          0
&amp;nbsp;
&amp;gt; googleTrends %&amp;gt;% tail()
##                row.names Web.Search.interest..neo4j
## 658        neo4j example                   Breakout
## 659 neo4j graph database                   Breakout
## 660           neo4j java                   Breakout
## 661           neo4j node                   Breakout
## 662           neo4j rest                   Breakout
## 663       neo4j tutorial                   Breakout&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We only want to keep the rows which contain (week, interest) pairs so the first thing we&amp;#8217;ll do is rename the columns:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;names(googleTrends) = c(&amp;quot;week&amp;quot;, &amp;quot;score&amp;quot;)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
Now we want to strip out the rows which don&amp;#8217;t contain (week, interest) pairs. The easiest way to do this is to look for rows which don&amp;#8217;t contain date values in the &amp;#8216;week&amp;#8217; column.
&lt;/p&gt;
&lt;p&gt;First we need to split the start and end dates in that column by using the &lt;cite&gt;strsplit&lt;/cite&gt; function.&lt;/p&gt;
&lt;p&gt;I found it much easier to apply the function to each row individually rather than passing in a list of values so I created a dummy column with a row number in to allow me to do that (a trick &lt;a href=&quot;https://twitter.com/tonkouts&quot;&gt;Antonios&lt;/a&gt; showed me):&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; googleTrends %&amp;gt;% 
    mutate(ind = row_number()) %&amp;gt;% 
    group_by(ind) %&amp;gt;%
    mutate(dates = strsplit(week, &amp;quot; - &amp;quot;),
           start = dates[[1]][1] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character(),
           end =   dates[[1]][2] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;%
    head()
## Source: local data frame [6 x 6]
## Groups: ind
## 
##                        week score ind    dates      start        end
## 1 Worldwide; 2004 - present     1   1 &amp;lt;chr[2]&amp;gt;         NA         NA
## 2        Interest over time     1   2 &amp;lt;chr[1]&amp;gt;         NA         NA
## 3                      Week    90   3 &amp;lt;chr[1]&amp;gt;         NA         NA
## 4   2004-01-04 - 2004-01-10     3   4 &amp;lt;chr[2]&amp;gt; 2004-01-04 2004-01-10
## 5   2004-01-11 - 2004-01-17     3   5 &amp;lt;chr[2]&amp;gt; 2004-01-11 2004-01-17
## 6   2004-01-18 - 2004-01-24     3   6 &amp;lt;chr[2]&amp;gt; 2004-01-18 2004-01-24&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now we need to get rid of the rows which have an NA value for &amp;#8216;start&amp;#8217; or &amp;#8216;end&#039;:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; googleTrends %&amp;gt;% 
    mutate(ind = row_number()) %&amp;gt;% 
    group_by(ind) %&amp;gt;%
    mutate(dates = strsplit(week, &amp;quot; - &amp;quot;),
           start = dates[[1]][1] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character(),
           end =   dates[[1]][2] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;%
    filter(!is.na(start) | !is.na(end)) %&amp;gt;% 
    head()
## Source: local data frame [6 x 6]
## Groups: ind
## 
##                      week score ind    dates      start        end
## 1 2004-01-04 - 2004-01-10     3   4 &amp;lt;chr[2]&amp;gt; 2004-01-04 2004-01-10
## 2 2004-01-11 - 2004-01-17     3   5 &amp;lt;chr[2]&amp;gt; 2004-01-11 2004-01-17
## 3 2004-01-18 - 2004-01-24     3   6 &amp;lt;chr[2]&amp;gt; 2004-01-18 2004-01-24
## 4 2004-01-25 - 2004-01-31     3   7 &amp;lt;chr[2]&amp;gt; 2004-01-25 2004-01-31
## 5 2004-02-01 - 2004-02-07     3   8 &amp;lt;chr[2]&amp;gt; 2004-02-01 2004-02-07
## 6 2004-02-08 - 2004-02-14     3   9 &amp;lt;chr[2]&amp;gt; 2004-02-08 2004-02-14&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
Next we&amp;#8217;ll get rid of &amp;#8216;week&amp;#8217;, &amp;#8216;ind&amp;#8217; and &amp;#8216;dates&amp;#8217; as we aren&amp;#8217;t going to need those anymore:
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; cleanGoogleTrends = googleTrends %&amp;gt;% 
    mutate(ind = row_number()) %&amp;gt;% 
    group_by(ind) %&amp;gt;%
    mutate(dates = strsplit(week, &amp;quot; - &amp;quot;),
           start = dates[[1]][1] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character(),
           end =   dates[[1]][2] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;%
    filter(!is.na(start) | !is.na(end)) %&amp;gt;%
    ungroup() %&amp;gt;%
    select(-c(ind, dates, week))
&amp;nbsp;
&amp;gt; cleanGoogleTrends %&amp;gt;% head()
## Source: local data frame [6 x 3]
## 
##   score      start        end
## 1     3 2004-01-04 2004-01-10
## 2     3 2004-01-11 2004-01-17
## 3     3 2004-01-18 2004-01-24
## 4     3 2004-01-25 2004-01-31
## 5     3 2004-02-01 2004-02-07
## 6     3 2004-02-08 2004-02-14
&amp;nbsp;
&amp;gt; cleanGoogleTrends %&amp;gt;% sample_n(10)
## Source: local data frame [10 x 3]
## 
##    score      start        end
## 1      8 2010-09-26 2010-10-02
## 2     73 2013-11-17 2013-11-23
## 3     52 2012-07-01 2012-07-07
## 4      3 2005-06-19 2005-06-25
## 5      3 2004-12-12 2004-12-18
## 6      3 2009-09-06 2009-09-12
## 7     71 2014-09-14 2014-09-20
## 8      3 2004-12-26 2005-01-01
## 9     62 2013-03-03 2013-03-09
## 10     3 2006-03-19 2006-03-25
&amp;nbsp;
&amp;gt; cleanGoogleTrends %&amp;gt;% tail()
## Source: local data frame [6 x 3]
## 
##   score      start        end
## 1    80 2014-10-19 2014-10-25
## 2    80 2014-10-26 2014-11-01
## 3    84 2014-11-02 2014-11-08
## 4    81 2014-11-09 2014-11-15
## 5    83 2014-11-16 2014-11-22
## 6     2 2014-11-23 2014-11-29&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
Ok now we&amp;#8217;re ready to plot. This was my first attempt:
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; library(ggplot2)
&amp;gt; ggplot(aes(x = start, y = score), data = cleanGoogleTrends) + 
    geom_line(size = 0.5)
## geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;div&gt;
&lt;img src=&quot;http://www.markhneedham.com/blog/wp-content/uploads/2014/12/2014-12-09_17-57-49.png&quot; alt=&quot;2014 12 09 17 57 49&quot; title=&quot;2014-12-09_17-57-49.png&quot; border=&quot;0&quot; width=&quot;511&quot; height=&quot;501&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;As you can see, not too successful! The first mistake I&amp;#8217;ve made is not telling ggplot that the &amp;#8216;start&amp;#8217; column is a date and so it can use that ordering when plotting:
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; cleanGoogleTrends = cleanGoogleTrends %&amp;gt;% mutate(start =  as.Date(start))
&amp;gt; ggplot(aes(x = start, y = score), data = cleanGoogleTrends) + 
    geom_line(size = 0.5)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;&lt;img src=&quot;http://www.markhneedham.com/blog/wp-content/uploads/2014/12/2014-12-09_18-00-03.png&quot; alt=&quot;2014 12 09 18 00 03&quot; title=&quot;2014-12-09_18-00-03.png&quot; border=&quot;0&quot; width=&quot;510&quot; height=&quot;507&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;My next mistake is that &amp;#8216;score&amp;#8217; is not being treated as a continuous variable and so we&amp;#8217;re ending up with this very strange looking chart. We can see that if we call the &lt;cite&gt;class&lt;/cite&gt; function:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; class(cleanGoogleTrends$score)
## [1] &amp;quot;factor&amp;quot;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s fix that and plot again:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; cleanGoogleTrends = cleanGoogleTrends %&amp;gt;% mutate(score = as.numeric(score))
&amp;gt; ggplot(aes(x = start, y = score), data = cleanGoogleTrends) + 
    geom_line(size = 0.5)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;&lt;img src=&quot;http://www.markhneedham.com/blog/wp-content/uploads/2014/12/2014-12-09_18-02-39.png&quot; alt=&quot;2014 12 09 18 02 39&quot; title=&quot;2014-12-09_18-02-39.png&quot; border=&quot;0&quot; width=&quot;504&quot; height=&quot;503&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;#8217;s much better but there is quite a bit of noise in the week to week scores which we can flatten a bit by plotting a &lt;a href=&quot;http://www.markhneedham.com/blog/2014/09/13/r-calculating-rolling-or-moving-averages/&quot;&gt;rolling mean of the last 4 weeks instead&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; library(zoo)
&amp;gt; cleanGoogleTrends = cleanGoogleTrends %&amp;gt;% 
    mutate(rolling = rollmean(score, 4, fill = NA, align=c(&amp;quot;right&amp;quot;)),
           start =  as.Date(start))
&amp;nbsp;
&amp;gt; ggplot(aes(x = start, y = rolling), data = cleanGoogleTrends) + 
    geom_line(size = 0.5)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;&lt;img src=&quot;http://www.markhneedham.com/blog/wp-content/uploads/2014/12/2014-12-09_18-05-26.png&quot; alt=&quot;2014 12 09 18 05 26&quot; title=&quot;2014-12-09_18-05-26.png&quot; border=&quot;0&quot; width=&quot;518&quot; height=&quot;505&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;#8217;s the full code if you want to reproduce:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;library(dplyr)
library(zoo)
library(ggplot2)
&amp;nbsp;
googleTrends = read.csv(&amp;quot;/Users/markneedham/Downloads/report.csv&amp;quot;, row.names=NULL)
names(googleTrends) = c(&amp;quot;week&amp;quot;, &amp;quot;score&amp;quot;)
&amp;nbsp;
cleanGoogleTrends = googleTrends %&amp;gt;% 
  mutate(ind = row_number()) %&amp;gt;% 
  group_by(ind) %&amp;gt;%
  mutate(dates = strsplit(week, &amp;quot; - &amp;quot;),
         start = dates[[1]][1] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character(),
         end =   dates[[1]][2] %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;%
  filter(!is.na(start) | !is.na(end)) %&amp;gt;%
  ungroup() %&amp;gt;%
  select(-c(ind, dates, week)) %&amp;gt;%
  mutate(start =  as.Date(start),
         score = as.numeric(score),
         rolling = rollmean(score, 4, fill = NA, align=c(&amp;quot;right&amp;quot;)))
&amp;nbsp;
ggplot(aes(x = start, y = rolling), data = cleanGoogleTrends) + 
  geom_line(size = 0.5)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
My next step is to plot the Google Trends scores against my meetup data set to see if there&amp;#8217;s any interesting correlations going on.
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As an aside I made use of &lt;a href=&quot;http://yihui.name/knitr/&quot;&gt;knitr&lt;/a&gt; while putting together this post &amp;#8211; it works really well for checking that you&amp;#8217;ve included all the steps and that it actually works!&lt;/em&gt;&lt;/p&gt;
&lt;img src=&quot;//feeds.feedburner.com/~r/MarkNeedham/~4/toNd4uQ-WQY&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
 <pubDate>Tue, 09 Dec 2014 18:14:45 +0000</pubDate>
</item>
<item>
 <title>Joanne Cranford: Let your users direct the tech</title>
 <link>http://foodieonrails.com/2014/12/let-your-users-direct-the-tech/</link>
 <description>&lt;p&gt;I was trying to explain to my co-founder Liz last night the changes that I&amp;#8217;d been making to Cake, the system that we use to process enquiries from &lt;a href=&quot;http://www.youchews.com&quot;&gt;our website&lt;/a&gt;, when she frowned and said, &amp;#8220;that sounds really complicated.&amp;#8221;&lt;/p&gt;
&lt;p&gt;It stopped me in my tracks &amp;#8211; technology is supposed to be enabling our company to move faster! She went on, &amp;#8220;Trello is so simple in comparison!&amp;#8221; She&amp;#8217;s right on that &amp;#8211; Trello IS simple but it only covers one part of of the process, while Cake is trying to do all the things. But it was time to stop ignoring that niggling feeling that I was losing my direction on what I was building, and revisit the system with the person who actually uses it every day. &lt;/p&gt;
&lt;p&gt;So co-founder-2 (Phil) and I sat down today, hooked his laptop up to a large TV screen and started putting orders through on the staging site, all the way from the customer placing them, through to the supplier accepting them, and the customer confirming and paying. I played the part of the customer, and Phil took on the two hats of the supplier and himself, doing his daily job of processing orders for You Chews. It was a bit confusing &amp;#8211; would have been better with Liz to act as supplier!&lt;/p&gt;
&lt;p&gt;Things started off slowly. I&amp;#8217;m using a Kanban system to pull changes through to production, and I&amp;#8217;m releasing changes sometimes several times a day. For Phil, that means that the system and processes he uses are changing every day &amp;#8211; and even when it seems to me like it&amp;#8217;s for the better, sometimes it&amp;#8217;s just a PITA. It&amp;#8217;s not until you see somebody else using the system that you built that you start to see whether or not it will actually work! &lt;/p&gt;
&lt;p&gt;The first order was a bit of a struggle. It became obvious fairly quickly that Cake needs to update the order status automatically, that having that as an extra step makes it significantly more confusing. &lt;/p&gt;
&lt;p&gt;With the second order, we discovered some bugs in the steps to email the supplier &amp;#8211; luckily they were just config issues, so I fixed them, and we were off again. &lt;/p&gt;
&lt;p&gt;The third and fourth orders started to go more smoothly. Phil was following the steps he had noted down for himself, knew that there would be upcoming changes to automate the status updates, and asked loads of questions. He consistently deleted one part of the email that would go to suppliers, so it was really clear that it wasn&amp;#8217;t needed. Towards the end of the meeting, he was even getting excited &amp;#8211; &amp;#8220;This is great! This is great!&amp;#8221; &amp;#8211; he even said at one point. We discovered a ton of places where small changes like wording could make the process smoother, and I walked away with a much clearer vision of what I need to create to make the system useful for him. Phil even left saying that he&amp;#8217;d enjoyed the meeting &amp;#8211; we spent about two hours in that room, so believe me that is quite an acheivement! &lt;/p&gt;
&lt;p&gt;It reinforced a few things for me. Firstly, and most obviously, test the system with real users. They can be customers or staff &amp;#8211; and don&amp;#8217;t just do a quick test, let them use it a few times, see if you can provide help and direction and if that makes a difference, and watch what they do. The more they use the system, the more useful feedback they&amp;#8217;ll be able to provide you. &lt;/p&gt;
&lt;p&gt;Secondly, if you&amp;#8217;re working in a fast-paced environment, constantly pushing through changes, it&amp;#8217;s a good thing to stop and review the bigger picture every so often. It doesn&amp;#8217;t need to be a big, formal process &amp;#8211; I spent five minutes sketching a diagram of what I was trying to do, and fifteen minutes talking it through, and was far more confident that I was heading in the right direction. &lt;/p&gt;
&lt;p&gt;Lastly: if you are going to do user testing, expect to walk away with a longer to-do list! &lt;/p&gt;</description>
 <pubDate>Tue, 09 Dec 2014 01:32:54 +0000</pubDate>
</item>
<item>
 <title>Mark Needham: R: dplyr – mutate with strptime (incompatible size/wrong result size)</title>
 <link>http://feedproxy.google.com/~r/MarkNeedham/~3/UBFi_Icjd98/</link>
 <description>&lt;p&gt;Having worked out &lt;a href=&quot;http://www.markhneedham.com/blog/2014/12/07/r-string-to-date-or-na/&quot;&gt;how to translate a string into a date or NA if it wasn&amp;#8217;t the appropriate format&lt;/a&gt; the next thing I wanted to do was store the result of the transformation in my data frame.
&lt;/p&gt;
&lt;p&gt;I started off with this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;data = data.frame(x = c(&amp;quot;2014-01-01&amp;quot;, &amp;quot;2014-02-01&amp;quot;, &amp;quot;foo&amp;quot;))
&amp;gt; data
           x
1 2014-01-01
2 2014-02-01
3        foo&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And when I tried to do the date translation ran into the following error:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; data %&amp;gt;% mutate(y = strptime(x, &amp;quot;%Y-%m-%d&amp;quot;))
Error: wrong result size (11), expected 3 or 1&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As I understand it this error is telling us that we are trying to put a value into the data frame which represents 11 rows rather than 3 rows or 1 row.&lt;/p&gt;
&lt;p&gt;
It turns out that &lt;a href=&quot;https://github.com/hadley/dplyr/issues/179&quot;&gt;storing POSIXlts in a data frame isn&amp;#8217;t such a good idea!&lt;/a&gt; In this case we can use the &lt;cite&gt;as.character&lt;/cite&gt; function to create a character vector which can be stored in the data frame:&lt;/a&gt;
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; data %&amp;gt;% mutate(y = strptime(x, &amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character())
           x          y
1 2014-01-01 2014-01-01
2 2014-02-01 2014-02-01
3        foo       &amp;lt;NA&amp;gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We can then get rid of the NA row by using the &lt;cite&gt;is.na&lt;/cite&gt; function:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; data %&amp;gt;% mutate(y = strptime(x, &amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;% filter(!is.na(y))
           x          y
1 2014-01-01 2014-01-01
2 2014-02-01 2014-02-01&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And a final tweak so that we have 100% pipelining goodness:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; data %&amp;gt;% 
    mutate(y = x %&amp;gt;% strptime(&amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% as.character()) %&amp;gt;%
    filter(!is.na(y))
           x          y
1 2014-01-01 2014-01-01
2 2014-02-01 2014-02-01&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;img src=&quot;//feeds.feedburner.com/~r/MarkNeedham/~4/UBFi_Icjd98&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
 <pubDate>Mon, 08 Dec 2014 19:02:46 +0000</pubDate>
</item>
<item>
 <title>Mark Needham: R: String to Date or NA</title>
 <link>http://feedproxy.google.com/~r/MarkNeedham/~3/Y1VT7tmbfvw/</link>
 <description>&lt;p&gt;I&amp;#8217;ve been trying to clean up a CSV file which contains some rows with dates and some not &amp;#8211; I only want to keep the cells which do have dates so I&amp;#8217;ve been trying to work out how to do that.&lt;/p&gt;
&lt;p&gt;My first thought was that I&amp;#8217;d try and find a function which would convert the contents of the cell into a date if it was in date format and NA if not. I could then filter out the NA values using the &lt;cite&gt;&lt;a href=&quot;http://www.statmethods.net/input/missingdata.html&quot;&gt;is.na&lt;/a&gt;&lt;/cite&gt; function.&lt;/p&gt;
&lt;p&gt;I started out with the &lt;cite&gt;&lt;a href=&quot;http://www.statmethods.net/input/dates.html&quot;&gt;as.Date&lt;/a&gt;&lt;/cite&gt; function&amp;#8230;&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; as.Date(&amp;quot;2014-01-01&amp;quot;)
[1] &amp;quot;2014-01-01&amp;quot;
&amp;nbsp;
&amp;gt; as.Date(&amp;quot;foo&amp;quot;)
Error in charToDate(x) : 
  character string is not in a standard unambiguous format&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&amp;#8230;but that throws an error if we have a non date value so it&amp;#8217;s not so useful in this case.&lt;/p&gt;
&lt;p&gt;Instead we can make use of the &lt;cite&gt;&lt;a href=&quot;http://stackoverflow.com/questions/14755425/what-are-the-standard-unambiguous-date-formats&quot;&gt;strptime&lt;/a&gt;&lt;/cite&gt; function which does exactly what we want:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; strptime(&amp;quot;2014-01-01&amp;quot;, &amp;quot;%Y-%m-%d&amp;quot;)
[1] &amp;quot;2014-01-01 GMT&amp;quot;
&amp;nbsp;
&amp;gt; strptime(&amp;quot;foo&amp;quot;, &amp;quot;%Y-%m-%d&amp;quot;)
[1] NA&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We can then feed those values into &lt;cite&gt;is.na&lt;/cite&gt;..
&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;r&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;gt; strptime(&amp;quot;2014-01-01&amp;quot;, &amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% is.na()
[1] FALSE
&amp;nbsp;
&amp;gt; strptime(&amp;quot;foo&amp;quot;, &amp;quot;%Y-%m-%d&amp;quot;) %&amp;gt;% is.na()
[1] TRUE&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&amp;#8230;and we have exactly the behaviour we were looking for.&lt;/p&gt;
&lt;img src=&quot;//feeds.feedburner.com/~r/MarkNeedham/~4/Y1VT7tmbfvw&quot; height=&quot;1&quot; width=&quot;1&quot; alt=&quot;&quot;/&gt;</description>
 <pubDate>Sun, 07 Dec 2014 19:29:01 +0000</pubDate>
</item>
<item>
 <title>Daniel Wildt: Desconf 2014? Sim!</title>
 <link>http://blog.danielwildt.com/2014/12/07/desconf-2014-sim/</link>
 <description>&lt;p&gt;Yes! Teremos &lt;a href=&quot;http://www.eventick.com.br/desconf-2014&quot; target=&quot;_blank&quot;&gt;Desconf 2014&lt;/a&gt; em Porto Alegre. A data é dia 16 de dezembro, a partir das 19h, no Bar Carmelita (na Cidade Baixa). Teremos 15 ou mais palestrantes, show de música e janta para o networking acontecer.&lt;/p&gt;
&lt;p&gt;Quer garantir a sua vaga e ver mais informações? &lt;a href=&quot;http://www.eventick.com.br/desconf-2014&quot; target=&quot;_blank&quot;&gt;Veja aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://vimeo.com/album/1498296&quot; target=&quot;_blank&quot;&gt;Quer ver palestras de 2010&lt;/a&gt;?&lt;/p&gt;&lt;br /&gt; Tagged: &lt;a href=&#039;http://blog.danielwildt.com/tag/desconf/&#039;&gt;desconf&lt;/a&gt;, &lt;a href=&#039;http://blog.danielwildt.com/tag/empreendedorismo/&#039;&gt;empreendedorismo&lt;/a&gt;, &lt;a href=&#039;http://blog.danielwildt.com/tag/evento/&#039;&gt;evento&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/danielwildt.wordpress.com/1517/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/danielwildt.wordpress.com/1517/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://pixel.wp.com/b.gif?host=blog.danielwildt.com&amp;#038;blog=8452578&amp;#038;post=1517&amp;#038;subd=danielwildt&amp;#038;ref=&amp;#038;feed=1&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;</description>
 <pubDate>Sun, 07 Dec 2014 11:00:00 +0000</pubDate>
</item>
<item>
 <title>Brian Oxley: Writing your own lombok annotation</title>
 <link>http://binkley.blogspot.com/2013/10/signing-maven-releases-with-gpg-while.html</link>
 <description>&lt;p&gt;It took me quite a while to get around to writing my own &lt;a href=&quot;http://projectlombok.org/features/index.html&quot; title=&quot;Lombok features&quot;&gt;lombok annotation&lt;/a&gt; and processor.  This took more effort than I expected, hopefully this post will save someone else some.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; &amp;mdash; Look at the source in &lt;a href=&quot;https://github.com/binkley/binkley/tree/develop/lombok&quot;&gt;my Github repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Motivation&lt;/h3&gt;

&lt;p&gt;Reading the excellent &lt;a href=&quot;http://www.nurkiewicz.com/2014/11/executorservice-10-tips-and-tricks.html&quot; title=&quot;ExecutorService - 10 tips and tricks&quot;&gt;&lt;cite&gt;ExecutorService - 10 tips and tricks&lt;/cite&gt;&lt;/a&gt; by Tomasz Nurkiewicz, I thought about tip #2, &lt;cite&gt;Switch names according to context&lt;/cite&gt;, which recommends wrapping important methods and code blocks with custom thread names to aid in logging and debugging.&lt;/p&gt; &lt;p&gt;&quot;This is a great use case for annotations!&quot; I thought.  The code screams &lt;em&gt;boilerplate&lt;/em&gt;:&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;public void doNiftyThings() {
    final Thread thread = Thread.currentThread();
    final String oldName = thread.getName();
    thread.setName(&quot;Boy this is nifty!&quot;);
    try {
        // Do those nifty things - the actual work
    } finally {
        thread.setName(oldName);
    }
}&lt;/pre&gt; &lt;p&gt;The whole point of the method is indented out of focus, wrapped with bookkeeping.  I&#039;d rather write this:&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;@ThreadNamed(&quot;Boy this is nifty!&quot;)
public void doNiftyThings() {
    // Do those nifty thing - the actual work
}&lt;/pre&gt; &lt;p&gt;Bonus: simple text search finds those places in my code where I change the thread name based on context.&lt;/p&gt;

&lt;h3&gt;Writing the annotation&lt;/h3&gt;

&lt;p&gt;Ok, let&#039;s make this work.  I started with cloning &lt;a href=&quot;https://github.com/rzwitserloot/lombok/blob/master/src/core/lombok/javac/handlers/HandleCleanup.java&quot;&gt;the &lt;code&gt;@Cleanup&lt;/code&gt; annotation and processor&lt;/a&gt;, and editing from there.  First the annotation, the easy bit.  I include the javadoc to emphasize the importance of documenting your public APIs.&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;/**
 * {@code ThreadNamed} sets the thread name during method execution, restoring
 * it when the method completes (normally or exceptionally).
 *
 * @author &amp;lt;a href=&quot;mailto:binkley@alumni.rice.edu&quot;&amp;gt;B. K. Oxley (binkley)&amp;lt;/a&amp;gt;
 */
@Documented
@Retention(SOURCE)
@Target({CONSTRUCTOR, METHOD})
public @interface ThreadNamed {
    /** The name for the thread while the annotated method executes. */
    String value();
}
&lt;/pre&gt; &lt;p&gt;Nothing special here.  I&#039;ve made the decision to limit the annotation to methods and constructors.  Ideally I&#039;d include &lt;em&gt;blocks&lt;/em&gt; but that isn&#039;t an option (yet) in Java, and you can always refactor out a block to a method.&lt;/p&gt;

&lt;h3&gt;Writing the processor&lt;/h3&gt;

&lt;p&gt;This is the serious part.  First some preliminaries:&lt;/p&gt; &lt;ol&gt;&lt;li&gt;I have only implemented support for JDK javac.  Lombok also supports the Eclipse compiler, which requires a separate processor class.  I have nothing against Eclipse, but it&#039;s not in my toolkit.&lt;/li&gt; &lt;li&gt;I&#039;ll discuss library dependencies below.  For now pretend these are already working for you.&lt;/li&gt; &lt;li&gt;I&#039;m a big fan of static imports, the diamond operator, etc.  I don&#039;t like retyping what the compiler is already thinking.  You should note &lt;code&gt;List&lt;/code&gt; below is &lt;em&gt;not&lt;/em&gt; &lt;code&gt;java.util.List&lt;/code&gt;; it&#039;s &lt;code&gt;com.sun.tools.javac.util.List&lt;/code&gt;.  Yeah, I don&#039;t know this class either.&lt;/li&gt; &lt;li&gt;The implementation is hard to follow.  Most of us don&#039;t spend much time with &lt;a href=&quot;http://en.wikipedia.org/wiki/Binary_expression_tree&quot; title=&quot;Binary expression trees&quot;&gt;expression trees&lt;/a&gt;, which is how most compilers (including javac) see your source code.  A language like LISP lets you write you code as the expression tree directly, which is both nifty and challenging (macros being like annotation processors).&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Without further ado:&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;/**
 * Handles the {@code lombok.ThreadNamed} annotation for javac.
 */
@MetaInfServices(JavacAnnotationHandler.class)
@HandlerPriority(value = 1024)
// 2^10; @NonNull must have run first, so that we wrap around the
// statements generated by it.
public class HandleThreadNamed
        extends JavacAnnotationHandler&amp;lt;ThreadNamed&amp;gt; {
    /**
     * lombok configuration: {@code lab.lombok.threadNamed.flagUsage} = {@code
     * WARNING} | {@code ERROR}.
     * &amp;lt;p&amp;gt;
     * If set, &amp;lt;em&amp;gt;any&amp;lt;/em&amp;gt; usage of {@code @ThreadNamed} results in a warning
     * / error.
     */
    public static final ConfigurationKey&amp;lt;FlagUsageType&amp;gt;
            THREAD_NAMED_FLAG_USAGE = new ConfigurationKey&amp;lt;FlagUsageType&amp;gt;(
            &quot;lab.lombok.threadNamed.flagUsage&quot;,
            &quot;Emit a warning or error if @ThreadNamed is used.&quot;) {
    };

    @Override
    public void handle(final AnnotationValues&amp;lt;ThreadNamed&amp;gt; annotation,
            final JCAnnotation ast, final JavacNode annotationNode) {
        handleFlagUsage(annotationNode, THREAD_NAMED_FLAG_USAGE,
                &quot;@ThreadNamed&quot;);

        deleteAnnotationIfNeccessary(annotationNode, ThreadNamed.class);
        final String threadName = annotation.getInstance().value();
        if (threadName.isEmpty()) {
            annotationNode.addError(&quot;threadName cannot be the empty string.&quot;);
            return;
        }

        final JavacNode owner = annotationNode.up();
        switch (owner.getKind()) {
        case METHOD:
            handleMethod(annotationNode, (JCMethodDecl) owner.get(),
                    threadName);
            break;
        default:
            annotationNode.addError(
                    &quot;@ThreadNamed is legal only on methods and constructors&quot;
                            + &quot;.&quot;);
            break;
        }
    }

    public void handleMethod(final JavacNode annotation,
            final JCMethodDecl method, final String threadName) {
        final JavacNode methodNode = annotation.up();

        if ((method.mods.flags &amp;amp; Flags.ABSTRACT) != 0) {
            annotation.addError(
                    &quot;@ThreadNamed can only be used on concrete methods.&quot;);
            return;
        }

        if (method.body == null || method.body.stats.isEmpty()) {
            generateEmptyBlockWarning(annotation, false);
            return;
        }

        final JCStatement constructorCall = method.body.stats.get(0);
        final boolean isConstructorCall = isConstructorCall(constructorCall);
        List&amp;lt;JCStatement&amp;gt; contents = isConstructorCall
                ? method.body.stats.tail : method.body.stats;

        if (contents == null || contents.isEmpty()) {
            generateEmptyBlockWarning(annotation, true);
            return;
        }

        contents = List
                .of(buildTryFinallyBlock(methodNode, contents, threadName,
                        annotation.get()));

        method.body.stats = isConstructorCall ? List.of(constructorCall)
                .appendList(contents) : contents;
        methodNode.rebuild();
    }

    public void generateEmptyBlockWarning(final JavacNode annotation,
            final boolean hasConstructorCall) {
        if (hasConstructorCall)
            annotation.addWarning(
                    &quot;Calls to sibling / super constructors are always &quot;
                            + &quot;excluded from @ThreadNamed;&quot;
                            + &quot; @ThreadNamed has been ignored because there&quot;
                            + &quot; is no other code in &quot; + &quot;this constructor.&quot;);
        else
            annotation.addWarning(
                    &quot;This method or constructor is empty; @ThreadNamed has &quot;
                            + &quot;been ignored.&quot;);
    }

    public JCStatement buildTryFinallyBlock(final JavacNode node,
            final List&amp;lt;JCStatement&amp;gt; contents, final String threadName,
            final JCTree source) {
        final String currentThreadVarName = &quot;$currentThread&quot;;
        final String oldThreadNameVarName = &quot;$oldThreadName&quot;;

        final JavacTreeMaker maker = node.getTreeMaker();
        final Context context = node.getContext();

        final JCVariableDecl saveCurrentThread = createCurrentThreadVar(node,
                maker, currentThreadVarName);
        final JCVariableDecl saveOldThreadName = createOldThreadNameVar(node,
                maker, currentThreadVarName, oldThreadNameVarName);

        final JCStatement changeThreadName = setThreadName(node, maker,
                maker.Literal(threadName), currentThreadVarName);
        final JCStatement restoreOldThreadName = setThreadName(node, maker,
                maker.Ident(node.toName(oldThreadNameVarName)),
                currentThreadVarName);

        final JCBlock tryBlock = setGeneratedBy(maker.Block(0, contents),
                source, context);
        final JCTry wrapMethod = maker.Try(tryBlock, nil(),
                maker.Block(0, List.of(restoreOldThreadName)));

        if (inNetbeansEditor(node)) {
            //set span (start and end position) of the try statement and
            // the main block
            //this allows NetBeans to dive into the statement correctly:
            final JCCompilationUnit top = (JCCompilationUnit) node.top()
                    .get();
            final int startPos = contents.head.pos;
            final int endPos = Javac
                    .getEndPosition(contents.last().pos(), top);
            tryBlock.pos = startPos;
            wrapMethod.pos = startPos;
            Javac.storeEnd(tryBlock, endPos, top);
            Javac.storeEnd(wrapMethod, endPos, top);
        }

        return setGeneratedBy(maker.Block(0,
                        List.of(saveCurrentThread, saveOldThreadName,
                                changeThreadName, wrapMethod)), source,
                context);
    }

    private static JCVariableDecl createCurrentThreadVar(final JavacNode node,
            final JavacTreeMaker maker, final String currentThreadVarName) {
        return maker.VarDef(maker.Modifiers(FINAL),
                node.toName(currentThreadVarName),
                genJavaLangTypeRef(node, &quot;Thread&quot;), maker.Apply(nil(),
                        genJavaLangTypeRef(node, &quot;Thread&quot;, &quot;currentThread&quot;),
                        nil()));
    }

    private static JCVariableDecl createOldThreadNameVar(final JavacNode node,
            final JavacTreeMaker maker, final String currentThreadVarName,
            final String oldThreadNameVarName) {
        return maker.VarDef(maker.Modifiers(FINAL),
                node.toName(oldThreadNameVarName),
                genJavaLangTypeRef(node, &quot;String&quot;),
                getThreadName(node, maker, currentThreadVarName));
    }

    private static JCMethodInvocation getThreadName(final JavacNode node,
            final JavacTreeMaker maker, final String currentThreadVarNAme) {
        return maker.Apply(nil(),
                maker.Select(maker.Ident(node.toName(currentThreadVarNAme)),
                        node.toName(&quot;getName&quot;)), nil());
    }

    private static JCStatement setThreadName(final JavacNode node,
            final JavacTreeMaker maker, final JCExpression threadName,
            final String currentThreadVarName) {
        return maker.Exec(maker.Apply(nil(),
                maker.Select(maker.Ident(node.toName(currentThreadVarName)),
                        node.toName(&quot;setName&quot;)), List.of(threadName)));
    }
}&lt;/pre&gt; &lt;p&gt;Wasn&#039;t that easy?&lt;/p&gt;

&lt;h3&gt;Dependencies&lt;/h3&gt;

&lt;p&gt;Of course the code depends on &lt;em&gt;lombok&lt;/em&gt;.  I&#039;m using version 1.14.8.  It also needs &lt;code&gt;tools.jar&lt;/code&gt; from the JDK for compiler innards like expression trees.  (An Eclipse processor needs an equivalent.)&lt;/p&gt; &lt;p&gt;Unfortunately lombok itself uses &quot;mangosdk&quot; to generate a &lt;code&gt;META-INF/services/lombok.javac.JavacAnnotationHandler&lt;/code&gt; file for autodiscovery of processors.  I say &#039;unfortunately&#039; because this library is not in maven and is unsupported.  Happyily Kohsuke Kawaguchi wrote the excellent &lt;a href=&quot;https://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html&quot;&gt;metainf-services&lt;/a&gt; library a while back, maintains it, and publishes to Maven central.  If you&#039;re new to annotation processors it&#039;s a good project to learn from.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Ok, that was not actually so easy.  On the other hand, finding a starting point was the biggest hurdle for me in writing a lombok annotation.  Please &lt;a href=&quot;https://github.com/binkley/binkley/tree/develop/lombok&quot;&gt;browse my source&lt;/a&gt; and try your hand at one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt; &amp;mdash; A little bonus.  This code:&lt;/p&gt; &lt;pre class=&quot;code&quot;&gt;@ThreadNamed(&quot;Slot #%2$d&quot;)
public void doSomething(final String name, final int slot) {
    // Do something with method params
}&lt;/pre&gt; &lt;p&gt;Produces the thread name &quot;Slot #2&quot; when called with &lt;code&gt;&quot;Foo&quot;, 2&lt;/code&gt;.  Strings without formatting or methods with params treat the annotation value as a plain string.&lt;/p&gt;</description>
 <pubDate>Sat, 06 Dec 2014 04:59:00 +0000</pubDate>
</item>
<item>
 <title>Felix Leipold: Managing Configuration</title>
 <link>http://wuetender-junger-mann.de/wordpress/2014/12/managing-configuration/</link>
 <description>&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;In almost every serious software development effort that entails integrating different systems multiple environments are being used throughout development, testing and the production use of the system. Each of these environments typically contains a number of systems, that interact with each other. Each system needs to know how to talk to the systems it depends on in a particular envirnoment. Also, there are other parameters such as timeouts and feature flags. that might change across different environments.&lt;/p&gt;
&lt;p&gt;The classical solution to that problem is to externalise the configuration of upstream systems into a separate file, so that the installed artefact can be made to talk to different systems depending on where it is being installed.&lt;/p&gt;
&lt;p&gt;Frameworks like spring and puppet allow the use of placeholders that get assigned different values for different environments as a means to parameterise these files.&lt;/p&gt;
&lt;h2 id=&quot;a-stroll-down-the-garden-path&quot;&gt;A Stroll down the Garden Path&lt;/h2&gt;
&lt;p&gt;On a recent project I started going down this route. Spring would load a &lt;code&gt;.properties&lt;/code&gt; file which in turn contained placeholders which puppet would then populate differently for different environments. This was the approach all services in our department were using so, in the interest of consistency, we just adopted it.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s look at an example. Our system talks to a system called System A. The interaction is encapsulated into a client abstraction taking the configuration as a a constructor parameter:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;scala&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #000080;&quot;&gt;@&lt;/span&gt;Bean
&lt;span style=&quot;color: #000080;&quot;&gt;@&lt;/span&gt;AutoWired
&lt;span style=&quot;color: #0000ff; font-weight: bold;&quot;&gt;class&lt;/span&gt; SystemAClient&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000080;&quot;&gt;@&lt;/span&gt;Value&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #6666FF;&quot;&gt;&amp;quot;${dependencies.system.a.url}) systemAUrl: String) {
&amp;nbsp;
    // ... implementation
&amp;nbsp;
}&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Spring in turn used a &lt;code&gt;.properties&lt;/code&gt; file to fill in the right hand side values. For day-to-day development on the developers&amp;#8217; workstations we used a file such as the following:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;properties&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;dependencies.system.a.url&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;http://a.development.envs.company.com&lt;/span&gt;
&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;dependencies.system.b.url&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;http://b.development.envs.company.com&lt;/span&gt;
&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;connect.timeout&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;1000&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The trouble is, that for our acceptance test environment we needed a different version of this file as we did for our continuous integration build, our demo system and most importantly production.&lt;/p&gt;
&lt;p&gt;This is were puppet came into play. The operations team created a template for the configuration file as part of their scripting of the deployment:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;properties&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;dependencies.system.a.url&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;&amp;lt;%= @dependecies_system_a_url %&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;dependencies.system.b.url&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;&amp;lt;%= @dependecies_system_b_url %&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #000080; font-weight:bold;&quot;&gt;connect.timeout&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #008000; font-weight:bold;&quot;&gt;&amp;lt;%= @connect_timeout %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dealing with optional values was extremely awkward and involved an if statement inside the placeholder expression.&lt;/p&gt;
&lt;p&gt;The values for these variables were defined in a yaml file that was far away from the code in a repository that belonged to the operation team.&lt;/p&gt;
&lt;p&gt;Here an example for the testing environment:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;yaml&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #007F45;&quot;&gt;classes&lt;/span&gt;:&lt;span style=&quot;color: #007F45;&quot;&gt;
    company::myservice&lt;/span&gt;:&lt;span style=&quot;color: green;&quot;&gt;
        dependecies_system_a_url&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: brown;&quot;&gt;: &lt;/span&gt;http://a.testing.envs.company.com&lt;span style=&quot;color: green;&quot;&gt;
        dependecies_system_b_url&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: brown;&quot;&gt;: &lt;/span&gt;http://b.testing.envs.company.com&lt;span style=&quot;color: green;&quot;&gt;
        connect_timeout&lt;/span&gt;&lt;span style=&quot;font-weight: bold; color: brown;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;&quot;&gt;1000&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id=&quot;trouble-strikes&quot;&gt;Trouble Strikes&lt;/h2&gt;
&lt;p&gt;This is of course a massively complicated system. We ran into several issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introducing new configuration parameters became hard, because
&lt;ul&gt;
&lt;li&gt;The new parameter had to be introduced at several layers.&lt;/li&gt;
&lt;li&gt;The change of the puppet config had to be in lockstep.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Textual substitutions can easily lead to escaping and type errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Understanding the whole mechanism caused a lot of cognitive burden, as we quickly learnt when introducing new team members.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Releases could easily fail, because there was no easy way to test this until the actual deployment using puppet, because some of it relied on puppet functionality and some of it relied on the spring configuration parameter resolution which both couldn&amp;#8217;t easily be tested together without an actual deployment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We actually experienced quite a few failed attempts to relese because of issues with the configuration.&lt;/p&gt;
&lt;p&gt;Surely we could have introduced a complicated test harness for this set-up, but we felt that this would be throwing good money after bad, so we had a brainstorming session to come up with our procedural requirements for the way we handle configuration.&lt;/p&gt;
&lt;h2 id=&quot;what-we-needed&quot;&gt;What we Needed&lt;/h2&gt;
&lt;p&gt;The following requirements emerged during our session:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A workflow that enables developers to do all the changes associated with a new parameter in a single commit, so that they don&amp;#8217;t go out of sync.&lt;/li&gt;
&lt;li&gt;Minimise the number of changes required to introduce a new configuration parameter.&lt;/li&gt;
&lt;li&gt;Ensure that parameter values are provided for every environment.&lt;/li&gt;
&lt;li&gt;Ensure that no values for parameters that have been removed are provied to avoid zombie values, that sometimes got updated for quite a while, before everyone realised that they were no longer used.&lt;/li&gt;
&lt;li&gt;Ensure that trivial validations for the values have been performed.&lt;/li&gt;
&lt;li&gt;A central place that tells us what configuration parameters are available and whether they are optional.&lt;/li&gt;
&lt;li&gt;A mechanism to change configuration values in an emergency without rebuilding the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;All configuration lives in the same repository as the code. There is a special place in the source directory where all the config files live. There name is the name of the environment they describe.&lt;/li&gt;
&lt;li&gt;The configuration was bundled with the application so that they would move together.&lt;/li&gt;
&lt;li&gt;When configuring the application, puppet only told the application which file to pick up.&lt;/li&gt;
&lt;li&gt;Instead of using two layers of templating we managed the actual files as deployed to the server in the source repository. To make sure this remained manageable we stripped everything out of the configuration that is not changing across environments.&lt;/li&gt;
&lt;li&gt;For the actual config files as loaded by the app we moved from &lt;code&gt;.properties&lt;/code&gt; files to &lt;code&gt;.json&lt;/code&gt; files, which we mapped to a couple of classes that actually represented the configuration. Using json4s we could easily express constraints such as: this is a number, this is a url, or this parameter is optional.&lt;/li&gt;
&lt;li&gt;We wrote a unit test that tries to load up all files and check a number of properties
&lt;ul&gt;
&lt;li&gt;Whether the json is valid json.&lt;/li&gt;
&lt;li&gt;Whether it can be deserialised into a configuration object. This in turn checked whether all non-optional values were supplied for every environment and whether URLs and numbers could be parsed as such.&lt;/li&gt;
&lt;li&gt;Whether the file has the canonical format with defined indentation and field order. If it wasn&amp;#8217;t, a correctly formatted file was written to the target folder along with an error message that contained a commandline &lt;code&gt;mv&lt;/code&gt; statement that would replace the file in question with the properly formatted version.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A little script was build that would allow the operations team to replace the config that came bundled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The configuration had been turned into proper objects:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;scala&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #00ff00; font-style: italic;&quot;&gt;/** Environment specific configuration for my service. */&lt;/span&gt;
&lt;span style=&quot;color: #0000ff; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span style=&quot;color: #0000ff; font-weight: bold;&quot;&gt;class&lt;/span&gt; MyServiceConfig&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#40;&lt;/span&gt;
    &lt;span style=&quot;color: #00ff00; font-style: italic;&quot;&gt;/** Configuration */&lt;/span&gt;
    dependendcies&lt;span style=&quot;color: #000080;&quot;&gt;:&lt;/span&gt; DependenciesConfig,
    &lt;span style=&quot;color: #00ff00; font-style: italic;&quot;&gt;/** The connect timeout for all upstream systems in ms.*/&lt;/span&gt;
    connectTimeout&lt;span style=&quot;color: #000080;&quot;&gt;:&lt;/span&gt; Int
&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span style=&quot;color: #0000ff; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span style=&quot;color: #0000ff; font-weight: bold;&quot;&gt;class&lt;/span&gt; DependenciesConfig &lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#40;&lt;/span&gt;
    &lt;span style=&quot;color: #00ff00; font-style: italic;&quot;&gt;/** We rely on Service A, which is maintained by the foo-group */&lt;/span&gt;
    systemAUrl&lt;span style=&quot;color: #000080;&quot;&gt;:&lt;/span&gt; Url,
    &lt;span style=&quot;color: #00ff00; font-style: italic;&quot;&gt;/** Service B is not required in all deployments, so it is optional. */&lt;/span&gt;
    systemBUrl&lt;span style=&quot;color: #000080;&quot;&gt;:&lt;/span&gt; Option&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#91;&lt;/span&gt;Url&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#93;&lt;/span&gt;
&lt;span style=&quot;color: #F78811;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here an example for the configuration for the testing environment:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;dependencies&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;systemAUrl&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;http://a.testing.envs.company.com&amp;quot;&lt;/span&gt;
  &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt;
  &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;connectTimeout&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #CC0000;&quot;&gt;1000&lt;/span&gt;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The configuration for a developer workstation on the other hand could look like this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;dependencies&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;systemAUrl&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;http://a.development.envs.company.com&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt;
    &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;systemBUrl&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;http://b.development.envs.company.com&amp;quot;&lt;/span&gt;
  &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt;
  &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;connectTimeout&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #CC0000;&quot;&gt;1000&lt;/span&gt;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This solution worked beautifully and suddenly introducing a new configuration parameter was no longer a dreaded task.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;MyServiceConfig&lt;/code&gt; class there now also was a canonical place to look at things that can be configured as well as to elaborated a little bit on the parameters, which was a much better place than a separate wiki page.&lt;/p&gt;
&lt;p&gt;Going further we could have also written tests on top of the &lt;code&gt;MyServiceConfig&lt;/code&gt; abstraction, e.g. to ensure that all the urls point to our companies domain or that certain patterns are being followed across environments.&lt;/p&gt;
&lt;p&gt;On my next project I will push hard for using this approach as soon as the problem of configuration comes up.&lt;/p&gt;</description>
 <pubDate>Fri, 05 Dec 2014 04:21:01 +0000</pubDate>
</item>
</channel>
</rss>
