<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Software.Development.]]></title><description><![CDATA[Paul Wellner Bou]]></description><link>https://paul.wellnerbou.de/</link><image><url>https://paul.wellnerbou.de/favicon.png</url><title>Software.Development.</title><link>https://paul.wellnerbou.de/</link></image><generator>Ghost 5.80</generator><lastBuildDate>Thu, 25 Sep 2025 12:02:43 GMT</lastBuildDate><atom:link href="https://paul.wellnerbou.de/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to use Redis and/or memory cache with node-cache-manager]]></title><description><![CDATA[<p>Upgrading legacy libraries of a (server-side, running on Node) legacy JavaScript application, I had to upgrade &#xA0;(and replace) following libraries:</p><ul><li><a href="https://www.npmjs.com/package/cache-manager?ref=paul.wellnerbou.de">cache-manager</a></li><li><a href="https://www.npmjs.com/package/cache-manager-redis?ref=paul.wellnerbou.de">cache-manager-redis</a></li><li><a href="https://www.npmjs.com/package/cache-manager-redis-store?ref=paul.wellnerbou.de">cache-manager-redis-store</a></li></ul><p>As there is missing documentation (<code>node-cache-manager-redis-yet</code> does not have any at all) and there is no current example using a memory cache and Redis at the</p>]]></description><link>https://paul.wellnerbou.de/how-to-use-redis-and-or-memory-cache-with-node-cache-manager/</link><guid isPermaLink="false">645e05fa1130170001e3b011</guid><category><![CDATA[Node]]></category><category><![CDATA[Cache]]></category><category><![CDATA[Software Development]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Fri, 12 May 2023 10:07:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1515706886582-54c73c5eaf41?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDUzfHxzdG9yZXxlbnwwfHx8fDE2ODM4ODM0OTN8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1515706886582-54c73c5eaf41?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDUzfHxzdG9yZXxlbnwwfHx8fDE2ODM4ODM0OTN8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="How to use Redis and/or memory cache with node-cache-manager"><p>Upgrading legacy libraries of a (server-side, running on Node) legacy JavaScript application, I had to upgrade &#xA0;(and replace) following libraries:</p><ul><li><a href="https://www.npmjs.com/package/cache-manager?ref=paul.wellnerbou.de">cache-manager</a></li><li><a href="https://www.npmjs.com/package/cache-manager-redis?ref=paul.wellnerbou.de">cache-manager-redis</a></li><li><a href="https://www.npmjs.com/package/cache-manager-redis-store?ref=paul.wellnerbou.de">cache-manager-redis-store</a></li></ul><p>As there is missing documentation (<code>node-cache-manager-redis-yet</code> does not have any at all) and there is no current example using a memory cache and Redis at the same time, I spend some time finding the solution. So it might be a useful shortcut for you, if you need to do the same task.</p><h2 id="tldr">TL;DR</h2><p>The code I eventually came up with (in short, for more details read further):</p><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/28559280d8a1b3cf3a5c8ab1637d9087.js"></script><!--kg-card-end: html--><h2 id="the-problems-and-my-solutions">The problems and my solutions</h2><ul><li><code>cache-manager</code>&apos;s API changed. It changed for better, so this is a good thing, just a bit of work and restructuring of code, as it relies on <code>Promise</code>s now and the application I am working on is already relying on a working <code>cache</code> object on startup.<br>So I created a wrapper object taking care of the <code>await</code>s.</li></ul><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/477381069f81eb7d1d7eead3b928d65a.js"></script><!--kg-card-end: html--><ul><li>While the memory cache accepts <code>null</code> and <code>undefined</code> as result values of a wrapped function, <code>cache-manager-redis-yet</code> does not, and instead of omitting it, it throws an error. If you don&apos;t want this error to pop up in your application, you have to catch it (see line 24).</li><li><code>cache-manager-redis</code> is not maintained any more, so I removed it completely.</li><li><code>cache-manager-redis-store</code> is not &quot;officially&quot; supported by <code>cache-manager</code>, so I used the recommend one: <code><a href="https://www.npmjs.com/package/cache-manager-redis-yet?ref=paul.wellnerbou.de">node-cache-manager-redis-yet</a></code>, which unfortunately has absolutely no documentation and no example.<br>It is a fork of <a href="https://www.npmjs.com/package/cache-manager-redis-store?ref=paul.wellnerbou.de"><code>cache-manager-redis-store</code>,</a> so we can use their example to create a Redis cache. Keep in mind, we need the full Redis URL here, including the schme <code>redis://</code>, just the host won&apos;t work.</li></ul><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/63aa9e9e101625e1c048b4b2b799a4ed.js"></script><!--kg-card-end: html--><ul><li>Inconsistencies in the API using cache-managers <code>multiCache</code>: While creating a cache with <code>caching(...)</code>, which returns a <code>Promise&lt;MemoryCache&gt;</code>, <code>multiCache(...)</code> is only accepting Cache objects as parameters, no promises. So we either have to wait until the caches are created, or wrapping it into <code>Promise.all(...)</code></li></ul><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/8a02ee7a3993fb7eac30d420168bd44e.js"></script><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Serving an SPA with Go's "Echo"]]></title><description><![CDATA[The easiest way to server an SPA (static page application) like a React app and redirecting all paths that should be handled by the client side (React) router with the Go framework Echo is using the rewrite middleware.]]></description><link>https://paul.wellnerbou.de/go-serving-an-spa-with-echo/</link><guid isPermaLink="false">644a229d2a3d020001b2c32e</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><category><![CDATA[React]]></category><category><![CDATA[SPA]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Sat, 22 Apr 2023 09:27:09 GMT</pubDate><content:encoded><![CDATA[<p>Replacing the (update: not any more unmaintained) <a href="https://github.com/gorilla/mux?ref=paul.wellnerbou.de">Gorilla/mux</a> framework with <a href="https://echo.labstack.com/?ref=paul.wellnerbou.de">Echo</a> in <a href="https://feedback.wbou.dev/?ref=paul.wellnerbou.de">&#x1F44D; Get Feedback!</a> was easy and straight forward, I did not hat to change very much. But one problem is handled differently: redirecting all paths (that are not requesting static resources and are not API endpoints) interally to <code>index.html</code>, so that the single page application works in the browser &#x2013; in my case a client side React (or Preact) app.</p><p>My Go application serves the front end resources (<code>index.html</code>, images, styles and JavaScript) with a static file server from a directory in the same container. The resources are not embedded in the binary.</p><p>What I did with <a href="https://github.com/gorilla/mux?ref=paul.wellnerbou.de">Gorilla/mux</a> (more or less, this is inlined and shortened):</p><pre><code class="language-go">muxRouter.MatcherFunc(func(r *http.Request, match *mux.RouteMatch) bool {
    return ShouldReturnIndex(r.URL.Path) || fileIsServable(r.URL.Path)
}).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
    if ShouldReturnIndex(request.URL.Path) {
        request.URL.Path = &quot;/&quot;
    }
    fileServer.ServeHTTP(writer, request)
}).Methods(&quot;GET&quot;, &quot;HEAD&quot;)
</code></pre>
<p>What this does, is: If the path matches a static resource (<code>fileIsServable</code>) or matches a pattern that should be redirected to <code>index.html</code>, a handler function is called which is rewriting the request URL to <code>/</code>, if it matches a pattern to redirect and serves the file (if <code>/</code>, this would be <code>index.html</code>) with the static file server, which is an http handler: <code>http.FileServer(http.Dir(httpRoot))</code>.</p><p>With <a href="https://echo.labstack.com/?ref=paul.wellnerbou.de">Echo</a>, it is not possible to change the url path in the same way. There are several approaches solving this with additional libraries:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://divanv.com/post/single-binary-spa-go/?ref=paul.wellnerbou.de"><div class="kg-bookmark-content"><div class="kg-bookmark-title">A single binary SPA using Go</div><div class="kg-bookmark-description">A single binary SPA using Go - Using statik and echo with to serve up a single binary React app</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://divanv.com/favicon.ico" alt><span class="kg-bookmark-author">Divan Visagie</span><span class="kg-bookmark-publisher">Divan Visagie</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://divanv.com/post/single-binary-spa-go/go-spa-head.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://dev.to/pacholoamit/one-of-the-coolest-features-of-go-embed-reactjs-into-a-go-binary-41e9?ref=paul.wellnerbou.de"><div class="kg-bookmark-content"><div class="kg-bookmark-title">One of the coolest features of Go. Embed ReactJS into a binary with Go</div><div class="kg-bookmark-description">Today we&#x2019;re going to attempt to embed a React Application into a Go binary. Please watch the youtube&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://res.cloudinary.com/practicaldev/image/fetch/s--t7tVouP9--/c_limit,f_png,fl_progressive,q_80,w_192/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/devlogo-pwa-512.png" alt><span class="kg-bookmark-author">DEV Community</span><span class="kg-bookmark-publisher">pacholoamit</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0JhpRN6k--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ooly5198oq7rxhce94e7.png" alt></div></a></figure><p>While I like the idea of embedding the front end resources into the binary, for now I just wanted to replace the http routing library, without adding any more libraries and without restructuring my application.</p><p>The easiest way for me was just redirecting internally with the <a href="https://echo.labstack.com/middleware/rewrite/?ref=paul.wellnerbou.de">Echo rewrite middleware</a> for certain paths and using <a href="https://echo.labstack.com/guide/static-files/?ref=paul.wellnerbou.de">Echo&apos;s static server</a> to serve the front end resources:</p><pre><code class="language-go">e := echo.New()
e.Pre(middleware.Rewrite(map[string]string{
    &quot;^/pathprefix/*&quot;: &quot;/&quot;,
}))
e.Static(&quot;/&quot;, fileServer.httpRoot)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[How to commit files to a docker image that are in directories declared as volumes]]></title><description><![CDATA[<blockquote><a href="https://docs.docker.com/engine/reference/commandline/commit/?ref=paul.wellnerbou.de">The commit operation will not include any data contained in volumes mounted inside the container.</a></blockquote><p>What does this mean in practice?</p><p>If you have, for example, a docker image containing any kind of data storage (in my case a container used for development and testing purposes of <a href="https://subshell.com/sophora/?ref=paul.wellnerbou.de">Sophora CMS</a> server)</p>]]></description><link>https://paul.wellnerbou.de/how-to-commit-files-to-a-docker-image-that-are-in-directories-declared-as-volumes/</link><guid isPermaLink="false">644a229d2a3d020001b2c32d</guid><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Wed, 27 Jul 2022 12:29:37 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1590496793907-4d66e2994b4d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE1fHxjb250YWluZXJ8ZW58MHx8fHwxNjU4OTI0OTQw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<blockquote><a href="https://docs.docker.com/engine/reference/commandline/commit/?ref=paul.wellnerbou.de">The commit operation will not include any data contained in volumes mounted inside the container.</a></blockquote><img src="https://images.unsplash.com/photo-1590496793907-4d66e2994b4d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE1fHxjb250YWluZXJ8ZW58MHx8fHwxNjU4OTI0OTQw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="How to commit files to a docker image that are in directories declared as volumes"><p>What does this mean in practice?</p><p>If you have, for example, a docker image containing any kind of data storage (in my case a container used for development and testing purposes of <a href="https://subshell.com/sophora/?ref=paul.wellnerbou.de">Sophora CMS</a> server), where the volumes containing data are declared as docker volumes in the original image, it is not possible to create a new image (with your personal, project specific test data) using <code>docker commit</code>.</p><p>But there is a way to put content into directories declared as volumes: Create a <code>Dockerfile</code> that is <code>ADD</code> ing this content. Of course, this means that you have to copy the content from your prepared container somwhere where your new <code>Dockerfile</code> has access to.</p><!--kg-card-begin: markdown--><pre><code>FROM baseimage

ADD /path/to/data /path/to/data/volume/directory/in/container
</code></pre>
<!--kg-card-end: markdown--><p>The resulting image will contain data in the directories, even if they are still declared as volumes.</p>]]></content:encoded></item><item><title><![CDATA[Using spring-data-solr with configurable Solr core]]></title><description><![CDATA[<p>Developing Java applications accessing data from <a href="http://lucene.apache.org/solr/?ref=paul.wellnerbou.de">Solr</a> is easier with <a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de">spring-data-solr</a>. You can just use <code>Repository</code> interfaces, auto generated <code>findBy...</code> methods or <code><a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de#repositories.query-methods.details">@Query</a></code><a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de#repositories.query-methods.details"> annotations</a> to define your data sources. Unfortunately using this method it is not possible to configure the name of the Solr <a href="https://lucene.apache.org/solr/guide/6_6/solr-cores-and-solr-xml.html?ref=paul.wellnerbou.de">core</a> (or <a href="https://wiki.apache.org/solr/SolrTerminology?ref=paul.wellnerbou.de">collection</a>). The name of</p>]]></description><link>https://paul.wellnerbou.de/using-spring-data-solr-with-configurable-solr-core/</link><guid isPermaLink="false">644a229d2a3d020001b2c329</guid><category><![CDATA[solr]]></category><category><![CDATA[spring-data-solr]]></category><category><![CDATA[workarounds]]></category><category><![CDATA[spring]]></category><category><![CDATA[java]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Tue, 21 Aug 2018 06:45:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1500534623283-312aade485b7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=8c8fc1a311d9e001b1a0bc32fdd48b08" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1500534623283-312aade485b7?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=8c8fc1a311d9e001b1a0bc32fdd48b08" alt="Using spring-data-solr with configurable Solr core"><p>Developing Java applications accessing data from <a href="http://lucene.apache.org/solr/?ref=paul.wellnerbou.de">Solr</a> is easier with <a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de">spring-data-solr</a>. You can just use <code>Repository</code> interfaces, auto generated <code>findBy...</code> methods or <code><a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de#repositories.query-methods.details">@Query</a></code><a href="https://docs.spring.io/spring-data/solr/docs/current/reference/html/?ref=paul.wellnerbou.de#repositories.query-methods.details"> annotations</a> to define your data sources. Unfortunately using this method it is not possible to configure the name of the Solr <a href="https://lucene.apache.org/solr/guide/6_6/solr-cores-and-solr-xml.html?ref=paul.wellnerbou.de">core</a> (or <a href="https://wiki.apache.org/solr/SolrTerminology?ref=paul.wellnerbou.de">collection</a>). The name of the collection is automatically defined based on the name of your <code>Document</code> class or by the <code>@SolrDocument</code> annotation.</p><!--kg-card-begin: markdown--><pre><code class="language-java">@SolrDocument(collection = &quot;collection1&quot;)
public class YourSolrDataClass {
    @Id
    public String id;
    public String text;
    // ...
}
</code></pre>
<!--kg-card-end: markdown--><p>While your <code>Repository</code> can be just an interface. See <a href="https://github.com/christophstrobl/spring-data-solr-showcase/blob/master/src/main/java/org/springframework/data/solr/showcase/product/ProductRepository.java?ref=paul.wellnerbou.de">Spring-Data-Solr&apos;s showcase implementation</a> on Github, which is downloadable from the <a href="https://projects.spring.io/spring-data-solr/?ref=paul.wellnerbou.de">&quot;Getting Started&quot; page</a> as well.</p><p><a href="https://jira.spring.io/browse/DATASOLR-304?ref=paul.wellnerbou.de">Configuring the collection name is not possible</a>. However, there is a workaround with a bit of code. Unfortunately this means that you have to implement the methods which are actually querying Solr, you can&apos;t use the <code>@Query</code> annotations and auto generation magic (which is, by the way, explained very well in <a href="https://g00glen00b.be/spring-data-solr/?ref=paul.wellnerbou.de">this article by g00glen00b</a>) in your <code>Repository</code> interface any more.</p><p><strong>First step</strong>, reimplement <code>org.springframework.data.solr.repository.query.SolrEntityInformation</code>. An implementation of this interface is handed around internally in <code>SimpleSolrRepository</code>, which is used commonly as implementation of your repository.</p><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/1c4732e532de6b464ed726339691ab1a.js"></script><!--kg-card-end: html--><p><strong>Then</strong>, implement your Repository, extending from <code>SimpleSolrRepository</code>.</p><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/2ee6ed580ff58429993607120ca4b45b.js"></script><!--kg-card-end: html--><p>That&apos;s all. After that, you can setup your Spring context.</p><!--kg-card-begin: html--><script src="https://gist.github.com/paulwellnerbou/2c76f6af40b677bfc69c8fad06e441d6.js"></script><!--kg-card-end: html--><p>If there is a simpler solution, I am looking forward to it, drop me a line. I&apos;d wish to see this feature (or more simple) included in Spring Data Solr.</p>]]></content:encoded></item><item><title><![CDATA[Securing web services with Let's Encrypt (Docker and Bitnami)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>As I spent some time trying to get this to work, so I write my steps down, as personal knowledge base.</p>
<h1 id="docker">Docker</h1>
<p>One of the most useful docker containers out there is <a href="https://github.com/jwilder/nginx-proxy?ref=paul.wellnerbou.de">jwilder&apos;s nginx-proxy</a>. There is a <a href="https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion?ref=paul.wellnerbou.de">companion docker container for let&apos;s encrypt</a> which works fine.</p>]]></description><link>https://paul.wellnerbou.de/securing-webservices-with-docker-and-lets-encrypt/</link><guid isPermaLink="false">644a229d2a3d020001b2c327</guid><category><![CDATA[HTTPS]]></category><category><![CDATA[docker]]></category><category><![CDATA[Bitnami]]></category><category><![CDATA[Let's Encrypt]]></category><category><![CDATA[Operations]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Thu, 26 Apr 2018 07:25:32 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>As I spent some time trying to get this to work, so I write my steps down, as personal knowledge base.</p>
<h1 id="docker">Docker</h1>
<p>One of the most useful docker containers out there is <a href="https://github.com/jwilder/nginx-proxy?ref=paul.wellnerbou.de">jwilder&apos;s nginx-proxy</a>. There is a <a href="https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion?ref=paul.wellnerbou.de">companion docker container for let&apos;s encrypt</a> which works fine... if you know how to use it. The documentation was (for me) not clear at all, so I try to write the important steps down here.</p>
<ol>
<li>Start nginx-proxy, just as <a href="https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion?ref=paul.wellnerbou.de">documented</a>, but don&apos;t forget the network your web services will join. Remember to adjust <code>/path/to/certs</code>, this volume has to point to an existing (empty) directory.</li>
</ol>
<pre><code>docker run -d -p 80:80 -p 443:443 \
    --name nginx-proxy \
    --net nginx_default \
    -v /path/to/certs:/etc/nginx/certs:ro \
    -v /etc/nginx/vhost.d \
    -v /usr/share/nginx/html \
    -v /var/run/docker.sock:/tmp/docker.sock:ro \
    --label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy \
    jwilder/nginx-proxy
</code></pre>
<ol start="2">
<li>Start letsencrypt-nginx-proxy-companion, just as documented there as well. Adjust the <code>/path/to/certs</code> here as well, pointing to the same directory as above.</li>
</ol>
<pre><code>docker run -d \
    -v /path/to/certs:/etc/nginx/certs:rw \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    --volumes-from nginx-proxy \
    --name letsencrypt-nginx-proxy-companion \
    jrcs/letsencrypt-nginx-proxy-companion
</code></pre>
<ol start="3">
<li>Start your web service, setting the correct environment variables and connecting to the same network (apache, in this example). In general, <code>VIRTUAL_HOST</code> and <code>LETSENCRYPT_HOST</code> should match. Certificates will only be generated automatically if both <code>LETSENCRYPT_HOST</code> and <code>LETSENCRYPT_EMAIL</code> are set.<br>
Of course, your <code>nginx-proxy</code> started above has to be reachable under the given URL (if not, let&apos;s encrypt will not be able to verify the domain).</li>
</ol>
<pre><code>docker run -d \
    --name example-app \
    --net nginx_default \
    -e &quot;VIRTUAL_HOST=my.domain.tld&quot; \
    -e &quot;LETSENCRYPT_HOST=my.domain.tld&quot; \
    -e &quot;LETSENCRYPT_EMAIL=my@valid.email&quot; \
    tutum/apache-php
</code></pre>
<p>That&apos;s the short documentation. For more and more detailed documentation, read <a href="https://github.com/jwilder/nginx-proxy?ref=paul.wellnerbou.de">https://github.com/jwilder/nginx-proxy</a> and <a href="https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion?ref=paul.wellnerbou.de">https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion</a>.</p>
<p>Of course, this works together in a <code>docker-compose</code> file as well.</p>
<pre><code>version: &apos;2&apos;
services:
  your-web-app:
    ...
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    restart: always
    ports:
    - 443:443
    - 80:80
    volumes:
    - /var/run/docker.sock:/tmp/docker.sock:ro
    - /path/to/certs:/etc/nginx/certs:ro
    - /etc/nginx/vhost.d
    - /usr/share/nginx/html
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: &quot;true&quot;
  nginx-letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt-nginx-proxy-companion
    restart: always
    volumes:
    - /path/to/certs:/etc/nginx/certs:rw
    - /var/run/docker.sock:/var/run/docker.sock:ro
    volumes_from:
    - nginx-proxy
</code></pre>
<h1 id="bitnami">Bitnami</h1>
<p>This worked without any problems, Just follow the description given here: <a href="https://docs.bitnami.com/aws/how-to/generate-install-lets-encrypt-ssl/?ref=paul.wellnerbou.de">https://docs.bitnami.com/aws/how-to/generate-install-lets-encrypt-ssl/</a></p>
<p>It is not as automated as with the docker nginx solution, but works fine and is quite easy to set up.</p>
<p>I had some problems convincing the apache to redirect automatically from http to https. Eventually this link helped: <a href="https://community.bitnami.com/t/http-https-redirect-not-working/46642/2?ref=paul.wellnerbou.de">https://community.bitnami.com/t/http-https-redirect-not-working/46642/2</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using Disqus with your managed Ghost blog]]></title><description><![CDATA[The documentation about integrating Disqus Discussions in Ghost only applies to self hosted Ghost instances or at least self packaged themes. So I created a snippet which you can paste in your Blog footer via Ghost's Code Injection.]]></description><link>https://paul.wellnerbou.de/using-disqus-with-your-managed-ghost-blog/</link><guid isPermaLink="false">644a229d2a3d020001b2c326</guid><category><![CDATA[Ghost]]></category><category><![CDATA[Disqus]]></category><category><![CDATA[Simplifying things...]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Sat, 23 Sep 2017 16:12:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The <a href="https://help.ghost.org/hc/en-us/articles/115000440851-Disqus?ref=paul.wellnerbou.de">documentation about integrating</a> <a href="https://disqus.com/?ref=paul.wellnerbou.de">Disqus Discussions</a> in <a href="https://ghost.org/?ref=paul.wellnerbou.de">Ghost</a> only applies to self hosted Ghost instances or at least self packaged themes.</p>
<p>So I created a snippet which you can paste in your &quot;Blog footer&quot; via Ghost&apos;s &quot;Code Injection&quot;:</p>
<script src="https://gist.github.com/paulwellnerbou/ecdb36c9bd86c89cdbf9705e0423d8ae.js"></script>
<p>Where <code>data-disqusName</code> is your name at Disqus and <code>data-element</code> contains the CSS selector of the element, the Disqus container will be appended in. For Ghost 0.11 and the default Casper 1.4 theme, this should be <code>.post-content</code>, for Ghost 1.0 and Casper 2 this works with <code>article.post-full:not(.page)</code>. (The <code>:not(.page)</code> part prevents comments beeing loaded on static pages. If you want them to do so, only use <code>article.post-full</code>.)</p>
<p>By the way, this works for all Websites, not only for Ghost. After working on this, I wonder why Disqus is making the integration so complicated.</p>
<p>The script is hostet on Github:</p>
<script src="https://gist.github.com/paulwellnerbou/a09e3819307851993df0aba65b266e86.js"></script>
<p>The disadvantage of this method is that it will not work anymore, if the URL changes, as there is no unique id. In this case, you will have to re-map URLs in your Disqus administration interface.</p>
<p>After implementing this, I found two similar solutions, both described more carefully, by <a href="https://jamiegoodwin.uk/how-to-add-and-future-proof-disqus-to-ghost/?ref=paul.wellnerbou.de">Jambie Goodwin</a> and <a href="https://gist.github.com/novaugust/aa73f696a72f2a2dacce85c424e12558?ref=paul.wellnerbou.de">Matt Enlow</a>, although outdated. Wish I did find them before anyway.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Best Practices setting up software projects - Part 1: The build tool]]></title><description><![CDATA[<div style="background-color: #eee; border: 1px solid #bbb; padding: 1em; border-radius: .5em;"><p>Within the last years developing, prototyping and designing software projects I collected a set of best practices for setting up and developing software projects. I wrote down a more general overview <a href="https://paul.wellnerbou.de/2016/09/19/defining-key-factors-for-successful-software-development/" title="Defining key factors for successful software development">in my article about about defining key factors for successful software development</a>.</p>
<p>The following (opinionated) principles are not limited</p></div>]]></description><link>https://paul.wellnerbou.de/best-practices-part-1-the-build-tool/</link><guid isPermaLink="false">644a229d2a3d020001b2c324</guid><category><![CDATA[Software Development]]></category><category><![CDATA[Build Tools]]></category><category><![CDATA[Maven]]></category><category><![CDATA[Gradle]]></category><category><![CDATA[Best Practices]]></category><category><![CDATA[NPM]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Fri, 22 Sep 2017 10:22:44 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1453806839674-d1a9087ca1ed?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDExM3x8dG9vbHN8ZW58MHx8fHwxNzE5MjM0NjYyfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<div style="background-color: #eee; border: 1px solid #bbb; padding: 1em; border-radius: .5em;"><img src="https://images.unsplash.com/photo-1453806839674-d1a9087ca1ed?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDExM3x8dG9vbHN8ZW58MHx8fHwxNzE5MjM0NjYyfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Best Practices setting up software projects - Part 1: The build tool"><p>Within the last years developing, prototyping and designing software projects I collected a set of best practices for setting up and developing software projects. I wrote down a more general overview <a href="https://paul.wellnerbou.de/2016/09/19/defining-key-factors-for-successful-software-development/" title="Defining key factors for successful software development">in my article about about defining key factors for successful software development</a>.</p>
<p>The following (opinionated) principles are not limited to new projects. They are valid for yet created and legacy projects as well. Following them will make the maintenance of your projects and onboarding of new developers much easier and though, cheaper and faster.</p>
<p>I made my experiences mainly in the Java world, creating libraries, command line applications and web applications with Java or Groovy, using the Spring framework very often. So especially part 3 and 4 will be tied to the Java ecosystem. The examples may not, but the general principles will be valid for other ecosystems as well.</p></div>
<hr>
<ul>
<li><a href="https://paul.wellnerbou.de/2017/09/22/best-practices-part-1-the-build-tool/">Part 1: The build and dependency management tool</a></li>
<li>Part 2: The version control system</li>
<li>Part 3: Context Definition and Dependency Injection</li>
<li>Part 4: Modularisation</li>
<li>Part 5: Documentation and the README</li>
<li>Part 6: Executable documentation and deployment prototype (aka &quot;The Dockerfile&quot;, or similar)</li>
</ul>
<hr>
<h1 id="part-1-the-build-and-dependency-management-tool">Part 1: The build and dependency management tool</h1>
<h3 id="dependency-managenent-and-build-configuration">Dependency managenent and build configuration</h3>
<p>Building your project and dependency management are two different tasks. You might want to use (or be using already) different tools. This is quite common (but not necessary) in front end projects, where npm and bower (npm for development dependencies, bower for front end, runtime dependencies) is used as dependency management and webpack, grunt or gulp as build tool.</p>
<p>In the back end world both tasks are commonly solved by the same tool.</p>
<h3 id="use-a-build-tool">Use a build tool</h3>
<p>First of all: If your software needs to be prepared or build, yes, please use a build and dependency management tool (or more of them, if needed). Don&apos;t rely only on your IDE configuration<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>. There are several reasons for that.</p>
<ul>
<li><strong>It will save you time</strong><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>. The build tool offers solutions to most issues you will have to address manually otherwise.</li>
<li><strong>Independent instance of truth</strong>: The build of your software is ok, if it succeeds with your build tool, not if &quot;it works on my machine&quot;.</li>
<li><strong>Automation and Continous Integration</strong>: Build tools are, in contrast to IDEs, runnable by automated tasks on server systems. This enables Continuous Integration and Continuous Delivery.</li>
</ul>
<h3 id="choosing-a-build-tool">Choosing a build tool</h3>
<p>So which build tool you should choose? While it fits your needs, it does not matter. I encourage you to try out several ones, not only experimenting, but with real projects, too. With this experience you will be able to decide in the future which build tool suites best for a new project.</p>
<p>Besides that, consider these points choosing a build tool:</p>
<ul>
<li>Does it fit in your technology stack? This means, for example, that you should use something able to communicate with Maven repositories if you are shipping your software in Maven repositories, and that it should be able to fetch your dependencies from where they are.</li>
<li>It is easier, especially if you are trying a new tool, if you know the technology or program language the tool is using. This will help you interpreting error messages, debugging and writing build scripts.</li>
</ul>
<p>If you want to dive in deeper in build tools and their characteristics, read <a href="http://nealford.com/memeagora/2013/01/22/why_everyone_eventually_hates_maven.html?ref=paul.wellnerbou.de">Neal Ford&apos;s article about hating or leaving Maven and the difference between composable and contextual tools</a>.</p>
<p>The aim of this article is not a detailed overview over existing build tools (there are <a href="https://zeroturnaround.com/rebellabs/java-build-tools-part-2-a-decision-makers-comparison-of-maven-gradle-and-ant-ivy/?ref=paul.wellnerbou.de">other articles</a> <a href="https://www.infoq.com/presentations/compare-build-tools?ref=paul.wellnerbou.de">specialized in this topic</a>), it should encourage you to use a build tool as primary build authority and give you some hints how to choose one. Nevertheless I will share a few experiences I made with build tools.</p>
<h3 id="running-your-project">Running your project</h3>
<p>I met a lot of projects without any hint on how to start the software. Every developer had the run configuration saved in his IDE. This works... at least on &quot;my machine&quot; (from the developer&apos;s point of view).</p>
<p>If technically possible, provide a run task in your build tool configuration for development purposes. This is quite common<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> for Maven (e.g. <code>mvn tomcat:run</code> for web apps, Gradle (e.g. <code>./gradlew bootRun</code> for <a href="https://projects.spring.io/spring-boot/?ref=paul.wellnerbou.de">Spring Boot</a> applications, or <code>npm build &amp;&amp; npm serve</code>, to assemble and serve front end applications).<br>
Providing this, you will have the most important part of <a href="https://paul.wellnerbou.de/2016/09/19/defining-key-factors-for-successful-software-development/#runscript">&quot;The run script&quot;</a><sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>.</p>
<h4 id="my-personal-experience-with-concrete-build-tools">My personal experience with concrete build tools</h4>
<p>I am mainly developing in the Java world in Java and Groovy, using Maven and Gradle as build tools.</p>
<p>I personally used Maven a lot and very, very extensively and at some point I started to agree <a href="http://kent.spillner.org/blog/work/2009/11/14/java-build-tools.html?ref=paul.wellnerbou.de">Kent R. Spillner in &quot;Maven is a horrible implementation of bad ideas&quot;</a>. But that&apos;s not completely true. I agree, that Maven is far away from being the best build tool in the world. It is horribly unflexible, creating custom tasks is only possible with workarounds, writing own plugins is unnecessarily complicated and your pom.xml files will get terribly long.</p>
<p>But the dependency management just works, it is fast, and it does it&apos;s job: compiling, testing, building and even running or deploying the software. There Maven&apos;s features end. If you want Maven to do something else, it often gets very complicated up to impossible, because you are bound tightly to Maven&apos;s defined project life cycle.</p>
<p>Gradle seemed to be the solution: flexible, enables you to create custom tasks and a relationship between those and using the well known dependency infrastructure of Maven. After using Gradle for a few years now, in some cases I am considering switching back to Maven again. I love the flexibility of Gradle. But it is slow (although <a href="https://gradle.org/gradle-vs-maven-performance/?ref=paul.wellnerbou.de">Gradle tells us the opposite</a>, but that&apos;s not the experience I made), and I found me fighting with configuration problems Maven solves out of the box.</p>
<blockquote>
<p>Maven does a lot of things which need to be configured manually in Gradle. On the other hand: If you need some custom tasks not fitting in Maven&apos;s tight build life cycle of Java projects, prefer Gradle.</p>
</blockquote>
<p>Lately I tried <a href="http://beust.com/kobalt/home/index.html?ref=paul.wellnerbou.de">Kobalt</a>, but had to discard it as I worked on a project depending on libraries provided in an old maven1 repository, which is not supported by Kobalt, and because of lacking IDE support<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>. I will try again in my next project, hoping that the IDE support will improve.</p>
<p>Using the Maven dependency ecosystem, there are still <a href="http://www.scala-sbt.org/?ref=paul.wellnerbou.de">SBT</a> from the Scala world, <a href="http://ant.apache.org/ivy/?ref=paul.wellnerbou.de">Ivy</a>, <a href="https://leiningen.org/?ref=paul.wellnerbou.de">Leiningen</a> (which mainly targets Clojure projects) and <a href="https://buildr.apache.org/?ref=paul.wellnerbou.de">Buildr</a> to try.</p>
<p>I did not try <a href="https://ruby.github.io/rake/?ref=paul.wellnerbou.de">Rake</a> for Java projects as <a href="http://kent.spillner.org/blog/work/2009/11/14/java-build-tools.html?ref=paul.wellnerbou.de">Spillner suggested in 2009</a>, <a href="https://www.thoughtworks.com/de/radar/tools/rake-for-java-net?ref=paul.wellnerbou.de">Thoughtwork&apos;s Technology Radar recommended in 2012</a> and <a href="https://martinfowler.com/articles/rake.html?ref=paul.wellnerbou.de">Martin Flower wrote about</a>, but it does not seem to be very common in the Java world, though.</p>
<p>For front end projects I used <a href="https://www.npmjs.com/?ref=paul.wellnerbou.de">npm</a>, <a href="https://bower.io/?ref=paul.wellnerbou.de">Bower</a>, <a href="https://gruntjs.com/?ref=paul.wellnerbou.de">Grunt</a> and <a href="https://gulpjs.com/?ref=paul.wellnerbou.de">Gulp</a>, but made positive experiences with npm as a single dependency management and &quot;build coordination&quot; tool, without any others, as <a href="https://www.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/?ref=paul.wellnerbou.de">Keith Circle recommended in 2014 already</a>. I call it &quot;Build coordination tool&quot;, because npm actually does not build my project, but manages and runs the scripts that will do so. Typically this includes minifying und bundling sources. As build tool (or &quot;module bundler&quot;) I recommend <a href="https://webpack.github.io/?ref=paul.wellnerbou.de">webpack</a><sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>.</p>
<p>I recommend <a href="https://gist.github.com/addyosmani/9f10c555e32a8d06ddb0?ref=paul.wellnerbou.de">Addy Osmani&apos;s npm scripts boilerplate gist</a> to pick the npm scripts you need for your project.</p>
<p>To bring the backend and front end worlds together, there is <a href="https://github.com/eirslett/frontend-maven-plugin?ref=paul.wellnerbou.de">maven-frontend-plugin</a> for Maven, and <a href="https://plugins.gradle.org/plugin/com.moowork.node?ref=paul.wellnerbou.de">gradle-node-plugin</a> for Gradle, which just execute your npm/Grunt/Gulp tasks.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>There are exceptions for some technologies, like the Microsoft .NET world, where the build configuration is bundled in the IDE project configuration. <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Having fought hours or days with Maven and Gradle to achieve a clean build configuration, this may sound dodgy. But I am convinced, I would have spent much more time (maybe on other problems) without build tool. <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>I wish it was even more common. <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>There are two excellent articles about this concept from Thoughtworker Pete Hodgson in two parts, called <a href="https://www.thoughtworks.com/insights/blog/praise-go-script-part-i?ref=paul.wellnerbou.de">&quot;The praise of the ./go script, part I&quot;</a> and <a href="https://www.thoughtworks.com/insights/blog/praise-go-script-part-ii?ref=paul.wellnerbou.de">part II</a>. I prefer to call it &quot;run&quot; to avoid confusion with the <a href="https://golang.org/?ref=paul.wellnerbou.de">programming language</a> or the <a href="https://www.gocd.org/?ref=paul.wellnerbou.de">Continuous Delivery Server</a>. <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>The support of Kobalt in my favourite IDE (IntelliJ) is bad: if your Kobalt build script is not completely correct (including compile and runtime erros) -- which happens often when starting to learn a new tool -- the project tree disappears. <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>There is an excellent webpack introduction on <a href="https://frontend.center/ep1-webpack-from-first-principles?ref=paul.wellnerbou.de">Front End Center</a> by <a href="https://glenmaddern.com/?ref=paul.wellnerbou.de">Glenn Maddern</a>. <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[Basic Auth with Geb and FirefoxDriver]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>Update: Unfortunately this solution is not working any more with recent versions of Firefox and FirefoxDriver.</em></p>
<p>I spent some time currently to automate integration tests and webtests, mainly using <a href="http://spockframework.org/?ref=paul.wellnerbou.de">spock</a> and, for the web test part, <a href="http://www.gebish.org/?ref=paul.wellnerbou.de">geb</a>.</p>
<p>Unfortunately I did not find any (simple) working example with basic auth. I</p>]]></description><link>https://paul.wellnerbou.de/basic-auth-with-geb-and-firefoxdriver/</link><guid isPermaLink="false">644a229d2a3d020001b2c323</guid><category><![CDATA[web]]></category><category><![CDATA[geb]]></category><category><![CDATA[spock]]></category><category><![CDATA[firefoxdriver]]></category><category><![CDATA[automation]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Wed, 12 Jul 2017 07:26:28 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1470165511815-34e78ff7a111?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=a6898c2feca39d5d68445f87c3247382" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1470165511815-34e78ff7a111?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=a6898c2feca39d5d68445f87c3247382" alt="Basic Auth with Geb and FirefoxDriver"><p><em>Update: Unfortunately this solution is not working any more with recent versions of Firefox and FirefoxDriver.</em></p>
<p>I spent some time currently to automate integration tests and webtests, mainly using <a href="http://spockframework.org/?ref=paul.wellnerbou.de">spock</a> and, for the web test part, <a href="http://www.gebish.org/?ref=paul.wellnerbou.de">geb</a>.</p>
<p>Unfortunately I did not find any (simple) working example with basic auth. I spent quite a few hours trying it and found a solution now. As stated <a href="https://stackoverflow.com/questions/5672407/how-to-perform-basic-authentication-for-firefoxdriver-chromedriver-and-iedriver?ref=paul.wellnerbou.de">here</a>, it should be possible to pass username and password in your url: <code>http://user:pass@host.tld</code>.</p>
<p>To avoid an alert box warning the user that the browser is going to login with the given credentitals, Firefox&apos; property <code>signon.autologin.proxy</code> has to be set to true.</p>
<p>This can be achieved initializing <code>FirefoxDriver</code> (Groovy example) with:</p>
<pre><code class="language-groovy">driver = {
	FirefoxProfile profile = new FirefoxProfile();
	// this avoids the &quot;Your are signing in to...&quot; alert
	profile.setPreference(&quot;signon.autologin.proxy&quot;, true);
	
	DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
	desiredCapabilities.setCapability(&apos;acceptInsecureCerts&apos;, true);
	
	FirefoxOptions options = new FirefoxOptions().setProfile(profile)
            .addCapabilities(desiredCapabilities);
	
	new FirefoxDriver(options)
}
</code></pre>
<p>There is an excellent <a href="https://github.com/geb/geb-example-gradle?ref=paul.wellnerbou.de">example project by geb</a> which uses the latest versions of selenium and FirefoxDriver (marionette).</p>
<p>I created a <a href="https://github.com/geb/geb-example-gradle/pull/28?ref=paul.wellnerbou.de">pull request on this example project for documentation purposes implementing this change</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Defining key factors for successful software development]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>A while ago I was asked about my opinion of key factors for successful and quality software development. There are a few lists published from more or less famous programmers, like <a href="https://www.quora.com/What-are-the-best-kept-secrets-of-great-programmers/answer/Jens-Rantil?ref=paul.wellnerbou.de">this excellent collection from Jens Rantil</a> or <a href="http://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html?ref=paul.wellnerbou.de">this from computer game development legend John Romero</a> (scroll down to the</p>]]></description><link>https://paul.wellnerbou.de/defining-key-factors-for-successful-software-development/</link><guid isPermaLink="false">644a229d2a3d020001b2c322</guid><category><![CDATA[Software Development]]></category><category><![CDATA[Clean Code]]></category><category><![CDATA[Best Practices]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Mon, 19 Sep 2016 11:38:43 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1550527882-b71dea5f8089?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEwfHxrZXl8ZW58MHx8fHwxNjUwNDMzNDUz&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1550527882-b71dea5f8089?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDEwfHxrZXl8ZW58MHx8fHwxNjUwNDMzNDUz&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Defining key factors for successful software development"><p>A while ago I was asked about my opinion of key factors for successful and quality software development. There are a few lists published from more or less famous programmers, like <a href="https://www.quora.com/What-are-the-best-kept-secrets-of-great-programmers/answer/Jens-Rantil?ref=paul.wellnerbou.de">this excellent collection from Jens Rantil</a> or <a href="http://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html?ref=paul.wellnerbou.de">this from computer game development legend John Romero</a> (scroll down to the bottom of the article).</p>
<p>Both of these lists do not separate more general, organisational topics from detailed, programming design specific guidelines. Both aspects are important, but the latter ones can be implemented within a development team, while the former topics might need to be addressed to a higher organisational level and though might be, depending on your organisation, more difficult to implement.</p>
<p>I won&apos;t mention evident best practices, such as &quot;<b>use a version control system</b>&quot;, &quot;<b>set up a continuous integration</b>&quot;, and so on, I assume nobody will argue about those points.</p>
<h2 id="organisationalkeyfactors">Organisational key factors</h2>
<ul>
<li><b>Code Reviews<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>:</b> As a development team member, review code, as much as possible, not to control your team members, but mainly for knowledge transfer. If several people are working on a system, it will help to prevent re-inventions and will save time on further development if the team members are aware of the changes done to the code they are working with.</li>
<li><b>Mentor-ship in heterogeneous teams:</b> <em>Heterogeneous</em> is a complicated word for a simple fact that you will face in most teams: there are developers with more overview able to write better code with less errors in less time than others. One of the reasons is the varying amount of experience, so take measures to keep all developers on (your) track, using e.g. pair programming and code reviews (with at least two developers in front of a screen forcing them to talk directly, unlike above, without code review tools), short training or live coding sessions, ...)</li>
<li><b>Be pragmatic:</b> No ideological discussions. Strive for pragmatic solutions. Software development is a business, not an art<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>, you earn (or your company earns) money selling solutions, not the most beautiful piece of code or technology.</li>
<li><b>UX:</b> If your software needs an UI, especially a web based UI, try hard to get an <b>UX expert which takes the principle UI decisions</b>, not the so called designers. Most designers (all I met) are perfectionist about their layout and design<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>, but they often don&apos;t think beyond it. This means that they don&apos;t think about what should actually happen if the user clicks on their so carefully designed button or what should happen if something goes wrong<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>.</li>
</ul>
<h2 id="softwaredesignbestpractices">Software design best practices</h2>
<ul>
<li><b>Unit Tests and Test Driven Development:</b> Unit testable code leads to good software design and allows refactoring</li>
<li><a name="runscript"></a><b>&apos;The Run Script&apos;<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>:</b> Instead of documenting extensively and describing how to run your project, create a script running your software on a developer&apos;s machine (I recommend container or virtualization technologies (Docker<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>, Chef, Ansible, ...) over build systems (Maven, Gradle, ...), if possible, out of two reasons: First, you have a running example of a possible deployment scenario; and second, a virtualized container avoids side effects with your local system.<br>
I ususally set up both.</li>
<li><b>Development environment:</b> Make sure your development environment (if the software needs more than the run script), can be set up from scratch automatically. Minimize or avoid ramp up time, developers need to start the project. Whatever is important to know to get started, should be documented shortly in a kind of README<sup class="footnote-ref"><a href="#fn7" id="fnref7">[7]</a></sup>.</li>
<li><b>Further Automation:</b> automate all tasks you have to do more than once, this includes acceptance tests/web tests. Automating will not only save you time, it will make your environment more maintainable (testable). This implies <b>automation of release todos</b>.<br><br>
The three bullet points above, unit tests, &apos;the run script&apos; and setting up the development environment are parts of automation, as well.</li>
<li><b>Encourage innovation:</b> With good and motivated developers innovation will happen, if the technological framework and project set up won&apos;t stop it. Assure that it is...
<ul>
<li>easy to switch development branches (use a clean repository<sup class="footnote-ref"><a href="#fn8" id="fnref8">[8]</a></sup>)</li>
<li>easy to rollback your system</li>
<li>easy to set up a new environment from scratch (see above)</li>
<li>possibility to use whatever IDE to develop, do not force your team to use one OS/software/IDE</li>
</ul>
</li>
<li><b>Avoid inheritance...:</b> Inheritance causes way more software design issues than you might think. There are lots of articles out there about this issue<sup class="footnote-ref"><a href="#fn9" id="fnref9">[9]</a></sup>, consider <a href="https://g.co/kgs/Rbwvyt?ref=paul.wellnerbou.de">Robert Martin&apos;s Book</a> and <a href="https://g.co/kgs/wkS6oR?ref=paul.wellnerbou.de">Gang of Four&apos;s Design Patterns</a>, as well.</li>
<li><b>Operation awareness:</b> You may call it <b>DevOps</b> or not, keep your developers aware of or make them take part in the deployment and operations of the software they write, this will help them to keep in mind topics like caching, distribution, synchronization, sessions, monitoring, performance, redundancy, concurrency, ...</li>
<li><b>Keep your Code clean:</b> Read, understand and follow Robert Martin&apos;s principles in his Books <a href="https://g.co/kgs/Rbwvyt?ref=paul.wellnerbou.de">Clean Code</a> and <a href="https://g.co/kgs/g8LkHn?ref=paul.wellnerbou.de">Clean Coder</a>.<br>
As developers spend about 10 times more time reading code than writing code<sup class="footnote-ref"><a href="#fn10" id="fnref10">[10]</a></sup>, you can imagine that speeding up the reading process will help your efficiency.</li>
<li><b>Frameworks</b>: For the same reason: choose a framework not (only) considering speed of development (unless you are prototyping), but considering the cleanness of it&apos;s architecture and it&apos;s principles to keep your code clean.</li>
<li><b>Be aware of the <a href="https://en.wikipedia.org/wiki/Pareto_principle?ref=paul.wellnerbou.de">Pareto principle</a></b>, which is so true in software development. Keep this in mind when estimating and when communicating that &quot;80% of the task is done&quot;.</li>
<li><b>Be pragmatic:</b> Again.</li>
<li>No ideological discussions about technology.</li>
<li>If the 20% of the work of a certain task which needs 80% of the time is not really necessary<sup class="footnote-ref"><a href="#fn11" id="fnref11">[11]</a></sup>, don&apos;t do it. Strive for simplicity. Remember: Quality, Tests and clean code is no option!</li>
</ul>
<p><em>Thanks to <a href="https://twitter.com/dswinscoe?ref=paul.wellnerbou.de">Don Swinscoe (@dswinscoe)</a> for re-reading and correcting this text as a native speaker.</em></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Although code reviews are a development team&apos;s topic, the organisational conditions has to be set up. Code reviews need time in which developers are not writing code. <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Programming has it&apos;s own aesthetics, creativity and beauty, but, just as with a carpenter, who&apos;s work is often a result of design, beauty, function and form, , so too in Software Development. The money is made with usable products, not (only) with beauty. Although beautiful code is, in most cases, part of a working, maintainable and sustainable solution. <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>I remember my discussion with a (very recognized) designer, clarifying some points regarding the layout for a front end project I was supposed to implement. I was trying to convince him to use as much yet existing layout components as possible (e.g. material design components), <a href="https://www.safaribooksonline.com/library/view/the-art-of/9780596527679/ch13s03.html?ref=paul.wellnerbou.de">&quot;maximizing work not done&quot;</a>. His answer: &quot;Well, that is not exactly my goal, from a designer&apos;s point of view&quot;. This is totally correct, and that is ok, if you are creating a piece of art or similar, where you need something different, for whatever reason. But that&apos;s not necessarily the goal for good UX, and in most cases, it will make the implementation more expensive. Eventually it depends on what the customer is asking for (and is willing to pay for). <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>Sorry, designers, this might a bit exaggerated (but only a bit), but that is my experience. <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>There are two excellent articles about this concept from Thoughtworker Pete Hodgson in two parts, called <a href="https://www.thoughtworks.com/insights/blog/praise-go-script-part-i?ref=paul.wellnerbou.de">&quot;The praise of the ./go script, part I&quot;</a> and <a href="https://www.thoughtworks.com/insights/blog/praise-go-script-part-ii?ref=paul.wellnerbou.de">part II</a>. I prefer to call it &quot;run&quot; to avoid confusion with the <a href="https://golang.org/?ref=paul.wellnerbou.de">programming language</a> or the <a href="https://www.gocd.org/?ref=paul.wellnerbou.de">Continuous Delivery Server</a>. <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>Google Chrome Developer&apos;s Youtube-Channel recommends to <a href="https://www.youtube.com/watch?v=06pkOtDLpmI&amp;ref=paul.wellnerbou.de">dockerize your app</a>, as well. <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn7" class="footnote-item"><p><a href="https://www.makeareadme.com/?ref=paul.wellnerbou.de">Make a readme</a> <a href="#fnref7" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn8" class="footnote-item"><p>My nightmare regarding &quot;dirty&quot; repositories was a web shop project using IBM Websphere Commerce. Based on the sample implementation of IBM, only new and modified resources were checked in (to save repository space). This lead to about 20,000 unversioned files in your project root, there was no .gitignore maintained. There was no way to do a &quot;clean checkout&quot;, you had to ask another developer to copy his development workspace, if you needed a new, working one. Estimated about 30% of the developer time was spent only to keep the development instances running, fixing errors, upgrading to new versions of IBM Websphere Commerce... fighting against the system. <a href="#fnref8" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn9" class="footnote-item"><p>See <a href="http://programmers.stackexchange.com/questions/75189/why-avoid-java-inheritance-extends?ref=paul.wellnerbou.de">http://programmers.stackexchange.com/questions/75189/why-avoid-java-inheritance-extends</a>,<br>
<a href="http://www.javaworld.com/article/2073649/core-java/why-extends-is-evil.html?ref=paul.wellnerbou.de">http://www.javaworld.com/article/2073649/core-java/why-extends-is-evil.html</a>,<br>
<a href="https://en.wikipedia.org/wiki/Composition_over_inheritance?ref=paul.wellnerbou.de">https://en.wikipedia.org/wiki/Composition_over_inheritance</a>,<br>
<a href="https://blog.pivotal.io/labs/labs/all-evidence-points-to-oop-being-bullshit?ref=paul.wellnerbou.de">https://blog.pivotal.io/labs/labs/all-evidence-points-to-oop-being-bullshit</a>,<br>
<a href="http://c2.com/cgi/wiki?ArgumentsAgainstOop=&amp;ref=paul.wellnerbou.de">http://c2.com/cgi/wiki?ArgumentsAgainstOop</a>,<br>
<a href="http://blogs.perl.org/users/sid_burn/2014/03/inheritance-is-bad-code-reuse-part-1.html?ref=paul.wellnerbou.de">http://blogs.perl.org/users/sid_burn/2014/03/inheritance-is-bad-code-reuse-part-1.html</a>, ... <a href="#fnref9" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn10" class="footnote-item"><p>See <a href="https://www.butterfly.com.au/blog/website-development/clean-high-quality-code-a-guide-on-how-to-become-a-better-programmer?ref=paul.wellnerbou.de">https://www.butterfly.com.au/blog/website-development/clean-high-quality-code-a-guide-on-how-to-become-a-better-programmer</a> and <a href="https://blog.codinghorror.com/when-understanding-means-rewriting/?ref=paul.wellnerbou.de">https://blog.codinghorror.com/when-understanding-means-rewriting/</a> <a href="#fnref10" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn11" class="footnote-item"><p>(Un)fortunately this decision will mostly be taken by other people (product owners, customers, stake holders). This decision has to be accepted. But you can make it transparent to them so that they have better information to decide if they really need this few pixel alignments more, this special animated checkbox, or special features that automatically detect the mood of the users.<br>
But we, as professional software developers have to consider that many of those special features (aside from pixels...) may save time to others using this software, even if they are using it in a way this software was never designed for. But that is seldom their fault. <a href="#fnref11" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Generated Styleguides: A markdown approach]]></title><description><![CDATA[A generated styleguide catalogue has many advantages in every day project live (see below), but as most of the available tools did not suite my needs (difficult to set up, too much tool dependencies, bugs, ...) I created my own solution: [style-code](https://github.com/paulwellnerbou/style-code).]]></description><link>https://paul.wellnerbou.de/generated-styleguides-a-markdown-approach/</link><guid isPermaLink="false">644a229d2a3d020001b2c321</guid><category><![CDATA[Frontend]]></category><category><![CDATA[Styleguides]]></category><category><![CDATA[Best Practices]]></category><category><![CDATA[Software Development]]></category><category><![CDATA[Project]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Fri, 24 Jun 2016 09:42:16 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1475669698648-2f144fcaaeb1?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=3e6b401685823ceb9cb8510e237ecb01" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1475669698648-2f144fcaaeb1?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=3e6b401685823ceb9cb8510e237ecb01" alt="Generated Styleguides: A markdown approach"><p>A generated styleguide catalogue has many advantages in every day project live (see below), but as most of the available tools did not suite my needs (difficult to set up, too much tool dependencies, bugs, ...) I created my own solution: <a href="https://github.com/paulwellnerbou/style-code?ref=paul.wellnerbou.de">style-code</a>.</p>
<h1 id="howageneratedstyleguidewillhelpdevelopingwebprojectteams">How a generated styleguide will help developing web project teams</h1>
<p>It is quote common in web projects, even in bigger ones, that the &quot;Layout&quot; people are responsible for all appeareance topics. Most of the times this is leading to a kind of <em>&quot;PDD&quot;</em>: Photoshop Driven Development. Especially (but not only) in these projects it is important to create a kind of &quot;Layout component catalogue&quot;.</p>
<p>This won&apos;t solve the usability issues (Layout is not usability, as we know), but, if established as part of the layout development, encourages designers and frontend developers (those defining the styles technically, in CSS or any preprocessored technology like SASS, LESS, ...) to think in independent components.</p>
<p>The resulting creation of an inventory of layout definitions (definition of standard font sizes, appearance of links, paragraphs, buttons) or components (visual elements containing more atomic elements, for example teasers, menus, ...) has several advantages:</p>
<ul>
<li>Overview over all used styles (&quot;Do we really need 4 different link styles? And 6 different font sizes with 10 different line-height definitions? And, if yes, why?&quot;)</li>
<li>Explaining all the styles and naming them forces designers to think about the reason why this style is needed and should be applied in which cases.</li>
<li>Consolidation of styles</li>
<li>CSS style definitions will be more independent as they are designed for each component (avoidance of definitions like <code>.main .right-content .marginal-element:first-child .header {...}</code>).</li>
<li>First acceptance of visual elements won&apos;t depend on a working system, feedback from the designers will (hopefully) focus just on this element, and not on any bug or feature request elsewhere on the site (this might sound strange, but will save a lot of time, according my experiences)</li>
<li>Reuse of already defined components, technically, which leads to cleaner style definitions</li>
</ul>
<h1 id="whystylecode">Why <a href="https://github.com/paulwellnerbou/style-code?ref=paul.wellnerbou.de">style-code</a>?</h1>
<p>There are some tools out there to generate styleguides, like <a href="https://jacobrask.github.io/styledocco/?ref=paul.wellnerbou.de">StyleDocco</a>,<br>
<a href="http://documentcss.com/?ref=paul.wellnerbou.de">documentCSS</a>, <a href="http://warpspire.com/kss/styleguides/?ref=paul.wellnerbou.de">KSS Stylesheets</a> or <a href="http://livingstyleguide.devbridge.com/?ref=paul.wellnerbou.de">Devbridge&apos;s Styleguide</a>.</p>
<h2 id="noprerequisitesexceptjava">No prerequisites (except java)</h2>
<p>All of them do have one requirement in common: The need of (at least) <a href="https://www.npmjs.com/?ref=paul.wellnerbou.de">npm</a>, others need even more installed tools, like Ruby, Ruby DevKit. That makes it quite difficult to integrate the styleguide generation into an highly automated and platform independent environment (=&gt; java world). Did you try to run e.g. documentCss from a Jenkins, without needing root access to the underlying operating system?</p>
<p>A lot of the npm tasks can be automated, for example with the <a href="https://github.com/eirslett/frontend-maven-plugin?ref=paul.wellnerbou.de">maven-frontend-plugin</a>. This works fine until the npm task you use needs a locally installed Ruby. <a href="https://jacobrask.github.io/styledocco/?ref=paul.wellnerbou.de">StyleDocco</a>, for example, works, but has bugs with background graphics (the frames used there are no real iframes, but javascript generated iframes, where Firefox is not able to resolve the resource URLs of the graphics).</p>
<p><a href="https://github.com/paulwellnerbou/style-code?ref=paul.wellnerbou.de">style-code</a> needs just java.</p>
<h2 id="separationfromproductivecsscode">Separation from productive CSS code</h2>
<p>Most of the existing tools are aiming to document the existing CSS code with examples, similar to JavaDoc. That is not what I want in my styleguide. The styleguide should be a separate document, an implementation reference showing how the elements should look like (in any browser, real HTML/CSS/JS) including implementation examples.</p>
<p>At the same time it needs to work with the productive resource files (CSS, JavaScript, Fonts), to be able to develop, test and find regressions without depending on the running system.</p>
<p>The documentation made with style-code is not embedded in any CSS files, it is a separate markdown file, which will be enhanced by iframes and live editing support by some injected JavaScript.</p>
<h1 id="stylecodegradlepluginanddemoproject">style-code gradle plugin and demo project</h1>
<p>There is a <a href="https://github.com/paulwellnerbou/style-code-demo-project?ref=paul.wellnerbou.de">demo project</a> using the <a href="https://github.com/paulwellnerbou/style-code-gradle-plugin?ref=paul.wellnerbou.de">Gradle plugin</a> to show how a styleguide project can be set up.</p>
<p>There are various possibilities, I am still working on the demo project and will add some more demo projects as well to create showcases for different use cases.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[A web based Java DateTime parse debugger]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>After using the <a href="http://grokdebug.herokuapp.com/?ref=paul.wellnerbou.de">Grok Debugger</a> often in the last weeks, I searched for a similar service for <a href="http://www.joda.org/joda-time/?ref=paul.wellnerbou.de">joda</a>&apos;s time patterns to parse strings. I did not find anything, so I created one, for you and for me.</p>
<p><strong>Update on 2017-09-26:</strong> Just updated this application to use <a href="http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html?ref=paul.wellnerbou.de">Java 8&</a></p>]]></description><link>https://paul.wellnerbou.de/a-web-base-jodatime-parse-debugger/</link><guid isPermaLink="false">644a229d2a3d020001b2c320</guid><category><![CDATA[java]]></category><category><![CDATA[Joda Time]]></category><category><![CDATA[Date and Time]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Thu, 25 Feb 2016 19:28:17 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1484856275728-97e5c0381ec0?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=c598e10a5e4cadde32b96e9431356a1e" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1484856275728-97e5c0381ec0?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=c598e10a5e4cadde32b96e9431356a1e" alt="A web based Java DateTime parse debugger"><p>After using the <a href="http://grokdebug.herokuapp.com/?ref=paul.wellnerbou.de">Grok Debugger</a> often in the last weeks, I searched for a similar service for <a href="http://www.joda.org/joda-time/?ref=paul.wellnerbou.de">joda</a>&apos;s time patterns to parse strings. I did not find anything, so I created one, for you and for me.</p>
<p><strong>Update on 2017-09-26:</strong> Just updated this application to use <a href="http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html?ref=paul.wellnerbou.de">Java 8&apos;s DateTime API</a>, removing JodaTime, using only Java 8&apos;s DateTime API.</p>
<ul>
<li><a href="https://java-time-parse-debugger.herokuapp.com/?ref=paul.wellnerbou.de">https://java-time-parse-debugger.herokuapp.com/</a></li>
</ul>
<p>The former URL joda-time-parse-debugger.herokuapp.com ist not reachable any more.</p>
<p>You can find the source code <a href="https://github.com/paulwellnerbou/java-time-parse-debugger?ref=paul.wellnerbou.de">on github</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Git Changelog Jenkins Plugin Released]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://paul.wellnerbou.de/content/images/2015/10/Screenshot-from-2015-10-07-08_36_29.png" alt="Git Changelog Plugin" loading="lazy"></p>
<p>As <a href="https://paul.wellnerbou.de/2015/07/13/git-jira-log-1-0-released/">announced earlier</a>, the first public version of the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Changelog+Plugin?ref=paul.wellnerbou.de">Git Changelog Plugin</a> for <a href="http://jenkins-ci.org/?ref=paul.wellnerbou.de">Jenkins</a> is now released and available via Jenkins&apos; offical update site.</p>
<p>I got some <a href="https://groups.google.com/forum/?ref=paul.wellnerbou.de#!topic/jenkinsci-dev/6RxOPndNkRo">inspiration from Oleg Nenashev on Jenkins&apos; mailing list</a>, so I restructured the library and the plugin so that the <a href="https://www.atlassian.com/software/jira?ref=paul.wellnerbou.de">Jira</a> filter</p>]]></description><link>https://paul.wellnerbou.de/git-changelog-jenkins-plugin-released/</link><guid isPermaLink="false">644a229d2a3d020001b2c31f</guid><category><![CDATA[Jenkins]]></category><category><![CDATA[JIRA]]></category><category><![CDATA[Plugin]]></category><category><![CDATA[Continuous Integration]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Wed, 07 Oct 2015 05:31:50 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://paul.wellnerbou.de/content/images/2015/10/Screenshot-from-2015-10-07-08_36_29.png" alt="Git Changelog Plugin" loading="lazy"></p>
<p>As <a href="https://paul.wellnerbou.de/2015/07/13/git-jira-log-1-0-released/">announced earlier</a>, the first public version of the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Changelog+Plugin?ref=paul.wellnerbou.de">Git Changelog Plugin</a> for <a href="http://jenkins-ci.org/?ref=paul.wellnerbou.de">Jenkins</a> is now released and available via Jenkins&apos; offical update site.</p>
<p>I got some <a href="https://groups.google.com/forum/?ref=paul.wellnerbou.de#!topic/jenkinsci-dev/6RxOPndNkRo">inspiration from Oleg Nenashev on Jenkins&apos; mailing list</a>, so I restructured the library and the plugin so that the <a href="https://www.atlassian.com/software/jira?ref=paul.wellnerbou.de">Jira</a> filter is just one possible output format of the changelog.</p>
<p>The key feature of the plugin is the automatic search of the latest tag and the changelog generation.</p>
<p>For now, there are only two output formats defined: a simple, human readable git history (similar to git log), and the mentioned Jira filter. See the <a href="https://github.com/jenkinsci/git-changelog-plugin?ref=paul.wellnerbou.de">README on github</a> or the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Changelog+Plugin?ref=paul.wellnerbou.de">Wiki page</a> for some basic examples to get started.</p>
<p>The <a href="https://github.com/jenkinsci/git-changelog-plugin?ref=paul.wellnerbou.de">code is available on github</a>, pull requests are welcome!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Load testing a new environment replaying live logs using chronicreplay]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>While creating a proof of concept of a new, cloud based environment of a big news platform, we used <a href="https://github.com/paulwellnerbou/chronicreplay?ref=paul.wellnerbou.de">chronicreplay</a> to test the behaviour of the new environment under a realistic load, similar to the productive system.</p>
<p>chronicreplay replays Apache (or any other) log files in the correct time and</p>]]></description><link>https://paul.wellnerbou.de/load-testing-a-new-environment-using-chronicreplay-to-replay-apache-log-files/</link><guid isPermaLink="false">644a229d2a3d020001b2c31e</guid><category><![CDATA[load test]]></category><category><![CDATA[chronicreplay]]></category><category><![CDATA[gnuplot]]></category><category><![CDATA[data visualization]]></category><category><![CDATA[cloud]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Fri, 04 Sep 2015 05:46:40 GMT</pubDate><media:content url="https://images.unsplash.com/37/tEREUy1vSfuSu8LzTop3_IMG_2538.jpg?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=0040ac1df776695f9431582a6fe6d388" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/37/tEREUy1vSfuSu8LzTop3_IMG_2538.jpg?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=0040ac1df776695f9431582a6fe6d388" alt="Load testing a new environment replaying live logs using chronicreplay"><p>While creating a proof of concept of a new, cloud based environment of a big news platform, we used <a href="https://github.com/paulwellnerbou/chronicreplay?ref=paul.wellnerbou.de">chronicreplay</a> to test the behaviour of the new environment under a realistic load, similar to the productive system.</p>
<p>chronicreplay replays Apache (or any other) log files in the correct time and order, see <a href="https://github.com/paulwellnerbou/chronicreplay/blob/master/README.md?ref=paul.wellnerbou.de">chronicreplay&apos;s README</a> for more information. As we had the time of the request in the original Apache log files, we were able to plot and analyze the time differences.</p>
<p><img src="https://paul.wellnerbou.de/content/images/2015/09/loadtest.png" alt="Load testing a new environment replaying live logs using chronicreplay" loading="lazy"></p>
<p>The peaks in this graph are caused by Java&apos;s default garbage collector cycles. Switching to a parallel way those peaks disappeared (visible in the data of Server 1). <a href="http://www.fasterj.com/?ref=paul.wellnerbou.de">FasterJ</a> has an <a href="http://www.fasterj.com/articles/oraclecollectors1.shtml?ref=paul.wellnerbou.de">excellent article explaining Java&apos;s garbage collectors</a>.</p>
<p>I updated chronicreplay to write more logfiles, better structured than before, so that it is much easier to use <a href="http://www.gnuplot.info/?ref=paul.wellnerbou.de">gnuplot</a> to visualize the data.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Solr 4 packaged with logging libraries]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://paul.wellnerbou.de/content/images/2015/08/solr-log4j.png" alt="Solr and Log4J Logos" loading="lazy"></p>
<p>The Solr 4 web archive (war) does not ship with logging libraries any more. So everyone who want to deploy it into a container have to either include the logging libraries in the classpath of the container or repackage the solr with the logging libraries.</p>
<p>I assume there are hundreds</p>]]></description><link>https://paul.wellnerbou.de/solr-4-packaged-with-logging-libraries/</link><guid isPermaLink="false">644a229d2a3d020001b2c31d</guid><category><![CDATA[solr]]></category><category><![CDATA[solr-war]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Sat, 15 Aug 2015 12:01:48 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://paul.wellnerbou.de/content/images/2015/08/solr-log4j.png" alt="Solr and Log4J Logos" loading="lazy"></p>
<p>The Solr 4 web archive (war) does not ship with logging libraries any more. So everyone who want to deploy it into a container have to either include the logging libraries in the classpath of the container or repackage the solr with the logging libraries.</p>
<p>I assume there are hundreds of repackaged solr 4 packages around the world. I discovered an <a href="https://github.com/finn-no/solr-war?ref=paul.wellnerbou.de">approach on github</a> of <a href="https://github.com/finn-no?ref=paul.wellnerbou.de">https://github.com/finn-no</a>, but they are including some custom libraries in the package as well, so it is not usable by others.</p>
<p>I <a href="https://github.com/paulwellnerbou/solr-war?ref=paul.wellnerbou.de">forked this repository</a> and created a generic version of a repackaged solr, <a href="https://bintray.com/paulwellnerbou/maven/solr-war?ref=paul.wellnerbou.de">available on bintray</a>.</p>
<p>You can either <a href="https://bintray.com/artifact/download/paulwellnerbou/maven/de/wellnerbou/solr/solr-war/1.0-solr-4.7.2-log4j2/solr-war-1.0-solr-4.7.2-log4j2.war?ref=paul.wellnerbou.de">download it directly</a> or include it in your <code>build.gradle</code>.</p>
<pre><code>repositories {
    maven {
        url  &quot;http://dl.bintray.com/paulwellnerbou/maven&quot; 
    }
}
</code></pre>
<p>There is more documentation for other ways to access this repository (maven, cURL, Artifactory and Nexus mirrors) on <a href="https://bintray.com/paulwellnerbou/maven/solr-war?ref=paul.wellnerbou.de">bintray&apos;s repository site</a> and in the <a href="https://github.com/paulwellnerbou/solr-war/blob/master/README.md?ref=paul.wellnerbou.de">README.md of the github repository</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[git-jira-log 1.0 released]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>A while ago I finished <a href="https://github.com/paulwellnerbou/git-jira-log?ref=paul.wellnerbou.de">version 1.0 of my library</a> to extract a changelog in form of a Jira filter based on ticket names in the git log of the project.</p>
<p>This library can be used as command line utility as well as library. The git part is based</p>]]></description><link>https://paul.wellnerbou.de/git-jira-log-1-0-released/</link><guid isPermaLink="false">644a229d2a3d020001b2c31c</guid><category><![CDATA[Jenkins]]></category><category><![CDATA[git-jira]]></category><category><![CDATA[release]]></category><dc:creator><![CDATA[Paul Wellner Bou]]></dc:creator><pubDate>Mon, 13 Jul 2015 12:29:20 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>A while ago I finished <a href="https://github.com/paulwellnerbou/git-jira-log?ref=paul.wellnerbou.de">version 1.0 of my library</a> to extract a changelog in form of a Jira filter based on ticket names in the git log of the project.</p>
<p>This library can be used as command line utility as well as library. The git part is based on <a href="https://eclipse.org/jgit/?ref=paul.wellnerbou.de">JGit</a>. I wrote about it <a href="https://paul.wellnerbou.de/2015/06/24/changelog-with-git-and-jira-creating-jira-filter-url-based-on-git-commits-between-two-revisions/">here</a> already.</p>
<p>A <a href="https://github.com/paulwellnerbou/git-jira-log-jenkins-plugin?ref=paul.wellnerbou.de">first version of a plugin</a> for <a href="http://jenkins-ci.org/?ref=paul.wellnerbou.de">Jenkins</a> is ready, too, documentation and examples are expected soon.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>