<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.juliaaano.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.juliaaano.com/" rel="alternate" type="text/html" /><updated>2026-02-21T09:11:20+00:00</updated><id>https://www.juliaaano.com/feed.xml</id><title type="html">Juliano Mohr</title><author><name>Juliano Mohr</name></author><entry><title type="html">The Rise of Quarkus and GitHub Actions</title><link href="https://www.juliaaano.com/blog/2021/05/14/rise-of-quarkus-github-actions/" rel="alternate" type="text/html" title="The Rise of Quarkus and GitHub Actions" /><published>2021-05-14T00:00:00+00:00</published><updated>2021-05-14T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2021/05/14/rise-of-quarkus-github-actions</id><content type="html" xml:base="https://www.juliaaano.com/blog/2021/05/14/rise-of-quarkus-github-actions/"><![CDATA[<p>Thanks to <a href="https://quarkus.io/" target="_blank"><strong>Quarkus</strong></a> and <a href="https://github.com/features/actions" target="_blank"><strong>GitHub Actions</strong></a>, I now find enjoyable to do Java development and create continuous integration (CI) workflows for my applications. In this post, you will learn how to efficiently build and push container images using the GitHub ecosystem, as well as look at examples on how to write pipelines with good practices in mind. Finally, I will demonstrate a few tricks specific to building Quarkus and Java apps with Actions.</p>

<!--more-->

<figure class="image">
<img src="https://d27nechif2d87h.cloudfront.net/images/pipelines-by-sea.jpeg" alt="pipelines-by-sea" class="image-center" loading="lazy" />
<figcaption class="image-center-caption">Image: Pipelines by the sea.</figcaption>
</figure>

<p>First and foremost, let me just define what continuous integration or CI pipeline is for the purposes of this article.</p>

<p>It is specifically the process to build, test and package the software artifact in a container, so it can be ready to be deployed in any given environment.</p>

<h2 id="quarkus">Quarkus</h2>

<p><a href="https://quarkus.io/" target="_blank"><strong>Quarkus</strong></a> is an amazing Java stack for developing modern cloud-native applications. The example used throughout this blog is an app written in Quarkus. Take some time to explore the <a href="https://github.com/juliaaano/quarkus" target="_blank">source code here</a>.</p>

<h2 id="github-actions">GitHub Actions</h2>

<p>Think of <a href="https://github.com/features/actions" target="_blank">GitHub Actions</a> as the CI tool, a replacement for Jenkins or Travis CI, for example. The aspect I like most about it is the fact it’s so well integrated with the GitHub repository. This can be empowering for developers who can control and get feedback from their CI pipelines in the same place where the code and pull requests are managed.</p>

<h2 id="github-packages">GitHub Packages</h2>

<p>GitHub’s response to having a container registry comes with <a href="https://github.com/features/packages" target="_blank">GitHub Packages</a>. The container image produced by the pipeline featured in this blog is pushed to the <em>ghcr.io</em> registry. Similar to Actions, Packages are well integrated with GitHub’s repository, especially the way access control is granted to the pipeline.</p>

<h2 id="time-for-actions">Time for Action<del>s</del></h2>

<p>The CI pipeline is defined as code in what GitHub call workflows. These are yaml files contained inside the <em>.github/workflows/</em> directory.</p>

<p>Next, I will highlight the best practices and patterns that can be found in the workflows of the Quarkus <a href="https://github.com/juliaaano/quarkus" target="_blank">example application</a> of this blog.</p>

<h3 id="the-reuse-of-existing-actions">The Reuse of Existing Actions</h3>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">login ghcr.io</span>
  <span class="na">uses</span><span class="pi">:</span> <span class="s">docker/login-action@v1.8.0</span>
  <span class="na">with</span><span class="pi">:</span>
      <span class="na">registry</span><span class="pi">:</span> <span class="s">ghcr.io</span>
      <span class="na">username</span><span class="pi">:</span> <span class="s">${{ github.actor }}</span>
      <span class="na">password</span><span class="pi">:</span> <span class="s">${{ secrets.GITHUB_TOKEN }}</span>
      <span class="na">logout</span><span class="pi">:</span> <span class="kc">true</span></code></pre></figure>

<p>Perhaps one of the best traits in Actions is the ability to import existing actions in order to execute even trivial tasks. The reason I say this is because pipeline code is not something that can be (at least easily) <strong>tested</strong>. Having the opportunity to delegate tasks to code that have been tried before increases the overall trust in the pipeline as well as reducing the errors and maintenance.</p>

<p>In the example above, I felt tempted to ignore using the action and instead just run a <em>docker login</em> shell command. However, that would still be prone to error (think of leaking the password); I also would not have handled the <strong>logout</strong> having coded the logic myself.</p>

<h3 id="maven-cache">Maven Cache</h3>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">cache ~/.m2</span>
  <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache@v2</span>
  <span class="na">with</span><span class="pi">:</span>
    <span class="na">path</span><span class="pi">:</span> <span class="s">~/.m2</span>
    <span class="na">key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}</span>
    <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">${{ runner.os }}-m2</span></code></pre></figure>

<p>Maven is famous for downloading half, if not the entire, internet. Jokes aside, it is wise to cache the dependencies as it normally happens in your local dev machine.</p>

<p>The level of abstraction provided by the action is great, it gives the developers flexibility and easiness to understand.</p>

<p>Cache invalidation will basically occur whenever the pom.xml changes.</p>

<h3 id="code-scanning">Code Scanning</h3>

<p>Another powerful feature is the <a href="https://github.com/features/security" target="_blank">code scanning</a> action. Powered by CodeQL, it can be found in the Quarkus app as a separate <a href="https://github.com/juliaaano/quarkus/blob/master/.github/workflows/scanning.yml" target="_blank">workflow</a>.</p>

<figure class="image">
<img src="https://d27nechif2d87h.cloudfront.net/images/github-code-scanning.png" alt="github-code-scanning" class="image-center" loading="lazy" />
<figcaption class="image-center-caption">Image: GitHub code scanning.</figcaption>
</figure>

<p>Security vulnerabilities are reported at the pull request level, in the code diff. A brilliant application of the shift-left security concept.</p>

<h3 id="permissions">Permissions</h3>

<p>All calls to GitHub APIs are authenticated using a GITHUB_TOKEN which is present by default in the workflow. The permissions assigned to this token can be configured as code inside the workflow definition.</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">permissions</span><span class="pi">:</span>
  <span class="na">packages</span><span class="pi">:</span> <span class="s">write</span>
  <span class="na">security-events</span><span class="pi">:</span> <span class="s">write</span></code></pre></figure>

<p>Following the <strong>least privilege</strong> security principle, I set everything to read-only at the repository level and then explicitly grant the required permissions as displayed above.</p>

<h3 id="container-builds-with-jib">Container Builds with JIB</h3>

<p>In the obsession to find the most efficient way to build container images, I found <a href="https://quarkus.io/guides/container-image#jib" target="_blank">JIB for Quarkus</a>. Next is an extract straight from the docs:</p>

<p><em>The extension quarkus-container-image-jib is powered by Jib for performing container image builds. The major benefit of using Jib with Quarkus is that all the dependencies (everything found under target/lib) are cached in a different layer than the actual application making rebuilds really fast and small (when it comes to pushing). Another important benefit of using this extension is that it provides the ability to create a container image without having to have any dedicated client side tooling (like Docker) or running daemon processes (like the Docker daemon) when all that is needed is the ability to push to a container image registry.</em></p>

<p>To use it with Quarkus simply add the dependency:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
    <span class="nt">&lt;groupId&gt;</span>io.quarkus<span class="nt">&lt;/groupId&gt;</span>
    <span class="nt">&lt;artifactId&gt;</span>quarkus-container-image-jib<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<p>Then add the following argument to the Maven build.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>mvn package <span class="nt">-Dquarkus</span>.container-image.push<span class="o">=</span><span class="nb">true</span></code></pre></figure>

<h3 id="image-labels">Image Labels</h3>

<p>Container image labels are relevant. In the example I give, a label is used to trace back to the git commit where that image was built from. With Quarkus, JIB and GitHub Actions, this is done by adding the following argument to the Maven build:</p>

<ul>
  <li><em>‘-Dquarkus.jib.labels.”org.opencontainers.image.revision”=’$GITHUB_SHA</em></li>
</ul>

<p>Pay attention to the use of single and double quotes as it makes a difference in the command line.</p>

<p>Also, it is worth mentioning the label name was not chosen arbitrarily, but based on standards from the <a href="https://github.com/opencontainers/image-spec" target="_blank">Open Container Initiative</a>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>You have seen a little bit of how to do continuous integration using modern frameworks. Despite the tools, what really matters is how close to the developers the process can get. With GitHub Actions and a modern language like Quarkus, people who get to write the code can now feel more than empowered to build and ship code fast. After all, that is the point of disciplines like DevOps and Continuous Delivery.</p>

<p>There is way more you can learn by going through the source code at:</p>

<ul>
  <li><a href="https://github.com/juliaaano/quarkus" target="_blank">https://github.com/juliaaano/quarkus</a></li>
</ul>

<p>Bonus: worth checking there how the pipeline handles build and testing in Quarkus <strong>NATIVE</strong> mode.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[Continuous integration pipeline for Quarkus and Java applications using GitHub Actions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">5 Java App Essentials</title><link href="https://www.juliaaano.com/blog/2020/04/08/five-java-app-essentials/" rel="alternate" type="text/html" title="5 Java App Essentials" /><published>2020-04-08T00:00:00+00:00</published><updated>2020-04-08T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2020/04/08/five-java-app-essentials</id><content type="html" xml:base="https://www.juliaaano.com/blog/2020/04/08/five-java-app-essentials/"><![CDATA[<p>You’re building from scratch just another microservice and the programing language of choice is once again Java. What are the 5 non-functional capabilities you’re more likely to need to set up before writing any business code? Well, that usually depends on the project’s requirements, however, more often than not I find myself dealing with the same concerns over and over. Here, I’ll show you what they are and <strong>how to implement them in a lightweight, almost framework-free approach.</strong></p>

<!--more-->

<figure class="image">
<img src="https://d27nechif2d87h.cloudfront.net/images/five-app-essentials.png" alt="filters-in-action" class="image-center-2" loading="lazy" />
<figcaption class="image-center-caption">Image: Top five.</figcaption>
</figure>

<h2 id="get-started">Get Started</h2>

<p>First of all, I acknowledge we are past another decade, where popular frameworks such as Spring Boot and <a href="https://quarkus.io/" target="_blank"><strong>Quarkus</strong></a> have taken over the Java development landscape. The examples shown here have been intentionally created to be independent of these frameworks.</p>

<p>Robert C. Martin <a href="https://blog.cleancoder.com/uncle-bob/2014/05/11/FrameworkBound.html" target="_blank">has once said</a> software teams get excessively bound to frameworks to the point the control over the software architecture is lost. There’s no doubt this resonates with his work on the <a href="https://en.wikipedia.org/wiki/SOLID" target="_blank">SOLID</a> software design principles. Remember, higher-level policies of systems (business domain) should not depend on lower-level ones (frameworks).</p>

<p>Enough said, I rest my case and give you here my list of <strong>five essential microservices capabilities</strong>:</p>

<h3 id="1-api">1. API</h3>

<p>The most common way to reach a service from the “outside” is via an <strong>HTTP API</strong>. The majority of software backend applications nowadays implement some sort of REST API.</p>

<p><a href="https://sparkjava.com/" target="_blank"><strong>Spark Java</strong></a> is a simple, yet powerful micro-framework that provides a DSL for rapid development of HTTP endpoints. It is less invasive compared to other web frameworks, but still offers a lot of power and flexibility.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">static</span> <span class="n">spark</span><span class="o">.</span><span class="na">Spark</span><span class="o">.*;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">get</span><span class="o">(</span><span class="s">"/hello"</span><span class="o">,</span> <span class="o">(</span><span class="n">req</span><span class="o">,</span> <span class="n">res</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="s">"Hello World"</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre></figure>

<p>I wrote a blog post in the past about Spark Java <a href="https://www.juliaaano.com/blog/2017/02/21/make-simple-with-spark-java/"><strong>here</strong></a>.</p>

<h3 id="2-testing">2. Testing</h3>

<p>Seeing that <em><del>REST</del></em> APIs are everywhere, we must think about how to <strong>test</strong> them.</p>

<p><a href="https://rest-assured.io/" target="_blank"><strong>Rest Assured</strong></a> is a great option. It has been out there for a while, so chances are you have heard about it. In short, it’s a Java DSL for testing of REST services.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Test</span>
<span class="kt">void</span> <span class="nf">greet_john</span><span class="o">()</span> <span class="o">{</span>

    <span class="kd">final</span> <span class="nc">String</span> <span class="n">jsonBody</span> <span class="o">=</span> <span class="n">format</span><span class="o">(</span><span class="s">"{\"name\":\"%s\",\"surname\":\"%s\"}"</span><span class="o">,</span> <span class="s">"John"</span><span class="o">,</span> <span class="s">"Smith"</span><span class="o">);</span>

    <span class="n">given</span><span class="o">()</span>
        <span class="o">.</span><span class="na">accept</span><span class="o">(</span><span class="no">JSON</span><span class="o">)</span>
        <span class="o">.</span><span class="na">contentType</span><span class="o">(</span><span class="no">JSON</span><span class="o">)</span>
        <span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">jsonBody</span><span class="o">)</span>
    <span class="o">.</span><span class="na">when</span><span class="o">()</span>
        <span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="s">"/greeting"</span><span class="o">)</span>
    <span class="o">.</span><span class="na">then</span><span class="o">()</span>
        <span class="o">.</span><span class="na">statusCode</span><span class="o">(</span><span class="mi">200</span><span class="o">)</span>
        <span class="o">.</span><span class="na">contentType</span><span class="o">(</span><span class="no">JSON</span><span class="o">)</span>
        <span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"greeting"</span><span class="o">,</span> <span class="n">not</span><span class="o">(</span><span class="n">nullValue</span><span class="o">()))</span>
        <span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="s">"greeting"</span><span class="o">,</span> <span class="n">equalTo</span><span class="o">(</span><span class="s">"Hello, John Smith!"</span><span class="o">));</span>
<span class="o">}</span></code></pre></figure>

<p>Full example can be found in my <a href="https://github.com/juliaaano/archetypes/blob/master/sparkjava/src/main/resources/archetype-resources/src/test/java/route/GreetingRouteShould.java" target="_blank"><strong>GitHub</strong></a>.</p>

<h3 id="3-logging">3. Logging</h3>

<p>Logging, in general, certainly deserves its own topic. Here I’ll discuss specifically two related aspects of application logging: <strong>correlation ID</strong> and <strong>log filter</strong>.</p>

<h4 id="31-correlation-id">3.1. Correlation ID</h4>

<p>In a world of distributed microservices, it’s imperative to be able to trace requests that travel from one service to another.</p>

<p>For this reason, it is recommended that every logging statement should include a correlation identifier to the request that it belongs to.</p>

<p>In Java, a popular solution is to use a logging framework that supports <a href="https://logback.qos.ch/manual/mdc.html" target="_blank"><strong>MDC - Mapped Diagnostic Context</strong></a>. With MDC, you are given access to store information in the context of a thread. This allows for an elegant solution where a “Request ID” is set to MDC and later read and written by the logging framework.</p>

<p>The Request ID should originate from the incoming request and always propagate through by each service. A common approach is to use HTTP Headers to carry this information. The header names should be standardized, <strong>X-Request-ID</strong> being a usual example of a name.</p>

<p>If the incoming request does not bring the expected X-Request-ID header, the app should create one and be the originator of that request.</p>

<p>Here is an example of generating an X-Request-ID and assigning it to the MDC:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml">// APP-YEAR-DAYOFYEAR-randomUUID: APP-2020-150-194a89c21ffa
String correlationId = "APP-".concat(now().format(ISO_ORDINAL_DATE)).concat(randomUUID().toString().substring(23, 36));
MDC.put("X-Request-ID", correlationId);</code></pre></figure>

<p>And finally, an example of how to use X-Request-ID in <a href="https://logback.qos.ch/" target="_blank"><strong>Logback</strong></a>:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;appender</span> <span class="na">name=</span><span class="s">"STDOUT"</span> <span class="na">class=</span><span class="s">"ch.qos.logback.core.ConsoleAppender"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;encoder&gt;</span>
    <span class="nt">&lt;pattern&gt;</span>%date [%thread] %-5level %logger{15} [%X{X-Request-ID}] - %msg%n<span class="nt">&lt;/pattern&gt;</span>
  <span class="nt">&lt;/encoder&gt;</span>
<span class="nt">&lt;/appender&gt;</span></code></pre></figure>

<p>Checkout working example from <a href="https://github.com/juliaaano/archetypes/blob/master/sparkjava/src/main/resources/archetype-resources/src/main/java/spark/SparkContext.java" target="_blank"><strong>here</strong></a>.</p>

<h4 id="32-log-filter">3.2. Log Filter</h4>

<p>Recently, <a href="https://www.juliaaano.com/blog/2020/01/20/request-log-level-filter/">I have written a full post about log filters</a>. You can jump straight there in case you’re interested.</p>

<p>I recommend setting up log filters to enable the use case of <strong>adjusting the log level on a per HTTP request basis</strong>. In practice, it could let you access the DEBUG logging of a service in production, without having to restart for configuration updates.</p>

<h3 id="4-container">4. Container</h3>

<p>When it’s time to ship your application there’s nothing better than packaging in a container.</p>

<p>In the example I’ll show you, <a href="https://www.juliaaano.com/blog/2018/02/25/fast-java-builds-with-docker/"><strong>Docker</strong> is used to build and run the Java app</a>, making the process portable and transparent regardless where it is executed.</p>

<figure class="highlight"><pre><code class="language-docker" data-lang="docker"><span class="c">### BUILDER IMAGE ###</span>
<span class="k">FROM</span><span class="w"> </span><span class="s">maven:3-jdk-11-slim</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s">builder</span>

<span class="k">COPY</span><span class="s"> pom.xml /build/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> dependency:go-offline

<span class="k">COPY</span><span class="s"> src /build/src/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> <span class="nt">--offline</span> package <span class="nt">-DskipTests</span> <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mkdir </span>app <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mv </span>build/target/app-<span class="k">*</span>.jar app/app.jar

<span class="c">### PRODUCTION IMAGE ###</span>
<span class="k">FROM</span><span class="s"> openjdk:11-jre-slim</span>

<span class="k">COPY</span><span class="s"> --from=builder app/app.jar app/app.jar</span>

<span class="k">WORKDIR</span><span class="s"> /app</span>

<span class="k">CMD</span><span class="s"> ["java", "-jar", "app.jar"]</span></code></pre></figure>

<p>The code comes from <a href="https://github.com/juliaaano/archetypes/tree/master/sparkjava" target="_blank"><strong>this repo</strong></a>, where you also find samples to configure <a href="https://github.com/juliaaano/archetypes/tree/master/sparkjava/src/main/resources/archetype-resources/manifests" target="_blank">Kubernetes and Istio</a>.</p>

<h3 id="5-pipeline">5. Pipeline</h3>

<p>An application deployment pipeline should be set early on in the project. At least something to test and build the artifacts should be in place from the beginning.</p>

<p><a href="https://github.com/juliaaano/archetypes/blob/master/sparkjava/src/main/resources/archetype-resources/.travis.yml" target="_blank"><strong>Here’s a proof of concept pipeline built for Travis CI</strong></a>. The idea is to showcase the implementation of multiple stages where Java, Docker and Github releases are featured.</p>

<p>More on this topic to be seen in a previous <a href="https://www.juliaaano.com/blog/2017/04/10/build-and-release-pipeline/"><strong>post</strong></a> in this very same blog!</p>

<h2 id="wrap-up">Wrap up</h2>

<p>Thanks for coming all the way here.</p>

<p>Everything you’ve seen is available and ready to be used in the format of Maven archetypes. To install them, visit <a href="https://github.com/juliaaano/archetypes/">https://github.com/juliaaano/archetypes/</a>.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[Five essential non-funcional capabilities a microservice app should have.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Easy encryption with PGP and Docker</title><link href="https://www.juliaaano.com/blog/2020/02/18/encryption-pgp-docker/" rel="alternate" type="text/html" title="Easy encryption with PGP and Docker" /><published>2020-02-18T00:00:00+00:00</published><updated>2020-02-18T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2020/02/18/encryption-pgp-docker</id><content type="html" xml:base="https://www.juliaaano.com/blog/2020/02/18/encryption-pgp-docker/"><![CDATA[<p>Encryption is complicated. People don’t pay too much attention because the process and tools are often cumbersome. In this post, I show you how to encrypt data effortlessly by combining tools like <a href="https://gnupg.org/" target="_blank"><strong>GPG</strong></a> and <strong>Docker</strong> (or <a href="https://podman.io/" target="_blank"><strong>Podman</strong></a>) containers. Your privacy in this wild wild internet is guaranteed!</p>

<!--more-->

<h2 id="tldr">TL;DR</h2>

<p>The goal is <strong>for anyone</strong> to encrypt a message <strong>from anywhere</strong> addressed to a recipient (in this case myself):</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"send me a secret"</span> | docker run <span class="nt">-i</span> juliaaano/encrypt</code></pre></figure>

<h2 id="show-me-how">Show me how</h2>

<p>The intent is to provide a good experience by abstracting the use of GPG with <em><del>Docker</del></em> Linux containers.</p>

<p>The container image that I use is lightweight, has GPG installed and imports my public PGP key.</p>

<figure class="highlight"><pre><code class="language-docker" data-lang="docker"><span class="k">FROM</span><span class="s"> debian:stable-slim</span>

<span class="k">RUN </span>apt-get update <span class="o">&amp;&amp;</span> apt-get <span class="nb">install</span> <span class="nt">-y</span> gnupg2 curl

<span class="k">RUN </span>curl <span class="nt">-sSL</span> https://www.juliaaano.com/key.asc | gpg <span class="nt">--import</span> -

<span class="k">ENTRYPOINT</span><span class="s"> ["gpg", "--trust-model", "always", "--encrypt", "--armor", "--output", "-", "--recipient", "juliaaano"]</span></code></pre></figure>

<h2 id="about-pgpgpg">About PGP/GPG</h2>

<p>So far it has been assumed a PGP key pair exists so you have a public key for encryption and “hopefully” its private counterpart for decryption.</p>

<p>Creating a key pair with GPG is easy, and there are several <a href="https://help.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key" target="_blank">resources available</a>.</p>

<p>Once you’ve got your keys, you can build and distribute your container image so anyone can send encrypted messages to you. You still need to deal with GPG to decrypt them yourself.</p>

<h2 id="usage-examples">Usage examples</h2>

<ol>
<li>
Encrypt a text message or a text file:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"send me a secret"</span> | docker run <span class="nt">-i</span> juliaaano/encrypt
<span class="nb">cat </span>my-sample-file.txt | docker run <span class="nt">-i</span> juliaaano/encrypt</code></pre></figure>

</li>
<li>
Save encrypted output to a file:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"send me a secret"</span> | docker run <span class="nt">-i</span> juliaaano/encrypt <span class="o">&gt;</span> secret.txt.asc</code></pre></figure>

</li>
<li>
Copy encrypted output to the clipboard (MacOS only):

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">cat </span>my-sample-file.txt | docker run <span class="nt">-i</span> juliaaano/encrypt | pbcopy</code></pre></figure>

</li>
<li>
Encrypt binary (non-text) files:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">docker run <span class="nt">-v</span> <span class="si">$(</span><span class="nb">pwd</span><span class="si">)</span>:/tmp juliaaano/encrypt /tmp/myfile.zip <span class="o">&gt;</span> myfile.zip.asc</code></pre></figure>

</li>
<li>
Use Podman containers instead of Docker:

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"send me a secret"</span> | podman run <span class="nt">-i</span> juliaaano/encrypt
<span class="nb">cat </span>my-sample-file.txt | podman run <span class="nt">-i</span> juliaaano/encrypt</code></pre></figure>

</li>
</ol>

<h2 id="summary">Summary</h2>

<p>The source code for this project can be found at <a href="https://github.com/juliaaano/encrypt" target="_blank"><strong>juliaaano/encrypt</strong></a>.</p>

<p>If you like it, comment with an <strong>encrypted</strong> message down below :-)</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[A trick that combines Docker containers, GPG and PGP encryption.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to set up a per-request log level filter</title><link href="https://www.juliaaano.com/blog/2020/01/20/request-log-level-filter/" rel="alternate" type="text/html" title="How to set up a per-request log level filter" /><published>2020-01-20T00:00:00+00:00</published><updated>2020-01-20T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2020/01/20/request-log-level-filter</id><content type="html" xml:base="https://www.juliaaano.com/blog/2020/01/20/request-log-level-filter/"><![CDATA[<p>The ability to easily change the log level of an application from INFO to DEBUG, or any other log level, is a feature frequently desired to have in any backend system. What if there is a way to configure the application to dynamically set its log level based on an input given by the consumer of the application. More specifically, this blog post will demonstrate how to tune Java’s <strong><a href="https://logback.qos.ch/" target="_blank">Logback</a></strong> and <strong><a href="https://logging.apache.org/log4j/2.x/" target="_blank">Log4j</a></strong> libraries to let HTTP clients define what log level to generate on the the server-side by simply passing an HTTP header.</p>

<!--more-->

<p>In a nutshell, a request like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">curl <span class="nt">-H</span> <span class="s2">"X-Log-Level: DEBUG"</span> http://localhost:8000/hello</code></pre></figure>

<p>Would result in logs <strong>set to the DEBUG level</strong>, only for that request, in the <em>hello</em> service logs.
<br /><br /></p>

<figure class="image">
<img src="https://d27nechif2d87h.cloudfront.net/images/hario-filters-in-action.jpg" alt="filters-in-action" class="image-center" loading="lazy" />
<figcaption class="image-center-caption">Image: Filters in action.</figcaption>
</figure>

<p>Advantages:</p>

<ul>
  <li>Easy troubleshooting in production.</li>
  <li>No need to restart the service.</li>
  <li>Delegate control to the client.</li>
</ul>

<p><strong>Time for action.</strong> Getting this to work is mostly a matter of configuring properly the logger framework.</p>

<p>Both Java logging frameworks Logback and Log4j have a capability called <strong><a href="https://logback.qos.ch/manual/filters.html" target="_blank">Filters</a></strong>. They allow log events to be evaluated to determine if or how they should be published. A developer can write a custom implementation of a Filter, however many implementations are already provided. One of them is the <strong><a href="https://logback.qos.ch/manual/filters.html" target="_blank">DynamicThresholdFilter</a></strong>.</p>

<p>The DynamicThresholdFilter allows filtering by log level based on specific attributes which are present in the MDC.</p>

<p>The <strong><a href="https://logback.qos.ch/manual/mdc.html" target="_blank">MDC</a></strong> (Mapped Diagnosed Context) is a key piece here because it needs to be used to signal which log level to use in the thread context initiated by the HTTP request.</p>

<p>Assigning a value to the MDC is simple and can be done with SLF4J:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml">org.slf4j.MDC.put("X-Log-Level", "DEBUG");</code></pre></figure>

<p>The idea is to set the log level in the MDC right after the request comes in, using a Servlet Request Filter, for example.</p>

<h3 id="logback-configuration">Logback configuration</h3>

<p>The DynamicThresholdFilter in Logback is quite powerful, but a bit more difficult to distil.</p>

<p>A thoroughly <a href="https://logback.qos.ch/manual/filters.html" target="_blank">reading of the official docs</a> is recommended.</p>

<p>Following is an example that achieves the desired outcome. <strong>Notice the need to set the root logger to DEBUG</strong>. This is required as it will be the lowest log level you will be able to configure as per request. If INFO would be set there, you wouldn’t be able to go any lower than that (DEBUG being the lowest, ERROR the highest).</p>

<p>However, the default log level is still INFO, as it is enforced by the <em>DefaultThreshold</em> attribute of the Filter.</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;root</span> <span class="na">level=</span><span class="s">"DEBUG"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;appender-ref</span> <span class="na">ref=</span><span class="s">"STDOUT"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/root&gt;</span>
<span class="nt">&lt;turboFilter</span> <span class="na">class=</span><span class="s">"ch.qos.logback.classic.turbo.DynamicThresholdFilter"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;Key&gt;</span>X-Log-Level<span class="nt">&lt;/Key&gt;</span>
  <span class="nt">&lt;DefaultThreshold&gt;</span>${LOG_LEVEL:-INFO}<span class="nt">&lt;/DefaultThreshold&gt;</span>
  <span class="nt">&lt;MDCValueLevelPair&gt;</span>
    <span class="nt">&lt;value&gt;</span>ERROR<span class="nt">&lt;/value&gt;</span>
    <span class="nt">&lt;level&gt;</span>ERROR<span class="nt">&lt;/level&gt;</span>
  <span class="nt">&lt;/MDCValueLevelPair&gt;</span>
  <span class="nt">&lt;MDCValueLevelPair&gt;</span>
    <span class="nt">&lt;value&gt;</span>WARN<span class="nt">&lt;/value&gt;</span>
    <span class="nt">&lt;level&gt;</span>WARN<span class="nt">&lt;/level&gt;</span>
  <span class="nt">&lt;/MDCValueLevelPair&gt;</span>
  <span class="nt">&lt;MDCValueLevelPair&gt;</span>
    <span class="nt">&lt;value&gt;</span>DEBUG<span class="nt">&lt;/value&gt;</span>
    <span class="nt">&lt;level&gt;</span>DEBUG<span class="nt">&lt;/level&gt;</span>
  <span class="nt">&lt;/MDCValueLevelPair&gt;</span>
<span class="nt">&lt;/turboFilter&gt;</span></code></pre></figure>

<h3 id="log4j-2-configuration">Log4j 2 configuration</h3>

<p>In Log4j 2 the solution is a bit more straightforward to understand. Consider the value of <em>X-Log-Level</em> present in MDC.</p>

<ol>
  <li>If the value is either TRACE or DEBUG, log events at that level will also be accepted.</li>
  <li>If the value is something else (does not match any of <em>keyValuePair</em> list), INFO is assumed.</li>
  <li>If there is no <em>X-Log-Level</em> at all, <em>onMismatch</em> ensures the filter is neutral, behaviour doesn’t change.</li>
</ol>

<p>Look for DynamicThresholdFilter in <a href="https://logging.apache.org/log4j/2.x/manual/filters.html" target="_blank">Log4j’s Filters documentation</a>.</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">DynamicThresholdFilter</span><span class="pi">:</span>
<span class="na">key</span><span class="pi">:</span> <span class="s">X-Log-Level</span>
<span class="na">onMatch</span><span class="pi">:</span> <span class="s">ACCEPT</span>
<span class="na">onMismatch</span><span class="pi">:</span> <span class="s">NEUTRAL</span>
<span class="na">defaultThreshold</span><span class="pi">:</span> <span class="s">INFO</span>
<span class="na">keyValuePair</span><span class="pi">:</span>
  <span class="pi">-</span>
  <span class="na">key</span><span class="pi">:</span> <span class="s">TRACE</span>
  <span class="na">value</span><span class="pi">:</span> <span class="s">TRACE</span>
  <span class="pi">-</span>
  <span class="na">key</span><span class="pi">:</span> <span class="s">DEBUG</span>
  <span class="na">value</span><span class="pi">:</span> <span class="s">DEBUG</span></code></pre></figure>

<h2 id="dont-believe-what-you-see">Don’t believe what you see?</h2>

<p>See those logging filters running. Checkout <strong><a href="https://github.com/juliaaano/archetypes/tree/master/sparkjava" target="_blank">this project</a></strong> in GitHub. It’s a Maven archetype that will generate a project with many interesting features. The per-request log level filter is one of them.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[This blog shows how to let clients control the log level of the backend app through the HTTP request header.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fast Java builds with Docker</title><link href="https://www.juliaaano.com/blog/2018/02/25/fast-java-builds-with-docker/" rel="alternate" type="text/html" title="Fast Java builds with Docker" /><published>2018-02-25T00:00:00+00:00</published><updated>2018-02-25T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2018/02/25/fast-java-builds-with-docker</id><content type="html" xml:base="https://www.juliaaano.com/blog/2018/02/25/fast-java-builds-with-docker/"><![CDATA[<p>There is a common pattern emerging which is to use Docker to <strong>build</strong> the software artefact. This approach has become popular since your machine or CI agent is not required to have anything installed but Docker. However, if you have tried this before with <strong>Java/Maven</strong>, you are most likely to know how <strong>slow</strong> it can be to see Maven download half of the internet inside the container in every single run. Here I show you how to address that issue with a simple trick.</p>

<!--more-->

<p>What we want to do is to copy the <strong>pom.xml</strong> and the <strong>app sources</strong> in two separate steps.</p>

<figure class="highlight"><pre><code class="language-docker" data-lang="docker"><span class="k">FROM</span><span class="s"> maven:3</span>

<span class="k">COPY</span><span class="s"> pom.xml /build/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> package

<span class="k">COPY</span><span class="s"> src /build/src/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> <span class="nt">--offline</span> package <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mkdir </span>app <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mv </span>build/target/app-<span class="k">*</span>.jar app/app.jar <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">rm</span> <span class="nt">-rf</span> build</code></pre></figure>

<p>The two most important things in this example are running Maven with the pom.xml in isolation and once the sources are added, running Maven again with the <em>–offline</em> option set.</p>

<p>This is only possible thanks to Docker’s built-in cache. Before you ask, yes, if you make any changes to the pom.xml you will invalidate the subsequent cached instructions and you will download half of the internet again. It only works under the assumption that application code is changed more often than the dependency management configuration.</p>

<h3 id="multi-stage-builds">Multi-stage builds</h3>

<p>The previous example alone doesn’t provide much context. After all, what do you do with that Dockerfile?</p>

<p>I hope you have heard about <strong><a href="https://docs.docker.com/develop/develop-images/multistage-build/" target="_blank">Docker multi-stage builds</a></strong>. It has been introduced to encourage the use of docker as a builder engine.</p>

<figure class="highlight"><pre><code class="language-docker" data-lang="docker"><span class="c">### BUILDER IMAGE ###</span>
<span class="k">FROM</span><span class="w"> </span><span class="s">maven:3</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s">builder</span>

<span class="k">COPY</span><span class="s"> pom.xml /build/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> package

<span class="k">COPY</span><span class="s"> src /build/src/</span>

<span class="k">RUN </span>mvn <span class="nt">--file</span> build/pom.xml <span class="nt">--batch-mode</span> <span class="nt">--offline</span> package <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mkdir </span>app <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">mv </span>build/target/app-<span class="k">*</span>.jar app/app.jar <span class="se">\
</span>	<span class="o">&amp;&amp;</span> <span class="nb">rm</span> <span class="nt">-rf</span> build

<span class="c">### PRODUCTION IMAGE ###</span>
<span class="k">FROM</span><span class="s"> openjdk:8-jre-alpine</span>

<span class="k">COPY</span><span class="s"> --from=builder app/app.jar app/app.jar</span>

<span class="k">CMD</span><span class="s"> ["java", "-jar", "app.jar"]</span></code></pre></figure>

<p>The idea is to show how easy Docker can be used to both build and run your software. Ultimately, entire pipelines could be created with just a Dockerfile and multi-stage builds. That would be a very comfortable position for the developer who would be able to execute all these stages locally exactly the same as the CI agent.</p>

<p>More information at <a href="https://github.com/juliaaano/archetypes" target="_blank">https://github.com/juliaaano/archetypes</a></p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[A smart way to cache Maven builds in Docker.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Easy conversion of HTTP payloads</title><link href="https://www.juliaaano.com/blog/2017/06/24/payload/" rel="alternate" type="text/html" title="Easy conversion of HTTP payloads" /><published>2017-06-24T00:00:00+00:00</published><updated>2017-06-24T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2017/06/24/payload</id><content type="html" xml:base="https://www.juliaaano.com/blog/2017/06/24/payload/"><![CDATA[<p>Almost every application needs to handle data in an interchangeable format. In the world of http JSON based API’s, the task of serializing and deserializing the payloads are something usually delegated to a third party library. Some examples are <em>Jackson</em>, <em>Gson</em> and the most recent Java EE spec <em>JsonP</em>. What if there is a way where applications can be decoupled from these providers in a similar fashion of how SLF4J does for logging? That’s the goal of <strong><a href="https://github.com/juliaaano/payload" target="_blank">Payload</a></strong>.</p>

<!--more-->

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
  <span class="nt">&lt;groupId&gt;</span>com.juliaaano<span class="nt">&lt;/groupId&gt;</span>
  <span class="nt">&lt;artifactId&gt;</span>payload<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;version&gt;</span>${check.latest}<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// Serialization</span>
<span class="nc">Payload</span><span class="o">&lt;</span><span class="nc">MyObject</span><span class="o">&gt;</span> <span class="n">payload</span> <span class="o">=</span> 
	<span class="no">JSON</span><span class="o">.</span><span class="na">payload</span><span class="o">().</span><span class="na">newInstance</span><span class="o">(</span><span class="k">new</span> <span class="nc">MyObject</span><span class="o">());</span>
<span class="nc">String</span> <span class="n">json</span> <span class="o">=</span> <span class="n">payload</span><span class="o">.</span><span class="na">raw</span><span class="o">();</span></code></pre></figure>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// Deserialization</span>
<span class="nc">Payload</span><span class="o">&lt;</span><span class="nc">MyObject</span><span class="o">&gt;</span> <span class="n">payload</span> <span class="o">=</span>
	<span class="no">XML</span><span class="o">.</span><span class="na">payload</span><span class="o">().</span><span class="na">newInstance</span><span class="o">(</span><span class="n">xmlAsString</span><span class="o">,</span> <span class="nc">MyObject</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="nc">MyObject</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">payload</span><span class="o">.</span><span class="na">get</span><span class="o">();</span></code></pre></figure>

<p>Payload acts as a <strong>facade</strong> for the various libraries out there, which means it needs to find in the classpath a third party to do the actual work. Just like SLF4J would need log4J or Logback, for example.</p>

<p>The design is quite flexible in the way it can accommodate custom implementations of the mechanism that does the conversion. I call it the <strong>Provider</strong> in this context. Understand more about providers in <a href="https://github.com/juliaaano/payload#providers" target="_blank">https://github.com/juliaaano/payload#providers</a>.</p>

<p><strong>Testing</strong> is something that you might want to use this library for. The ability to swap the underlying provider gives you a way to assemble your JSON test data using a different instrument rather than the one used production, but still keeping the same API.</p>

<p>No major <strong>performance</strong> drawbacks have been identified by using <em>Payload</em> instead of directly employing Jackson or Gson. The project contains a few JUnit <a href="https://github.com/juliaaano/payload/blob/0.0.3/src/test/java/com/juliaaano/payload/json/JsonBenchmark.java" target="_blank">benchmark tests</a> to address the matter.</p>

<p>I have created a small app as a <strong>proof of concept</strong> for this project: <a href="https://github.com/juliaaano/payload-tests" target="_blank">Payload Tests</a>. There you can see how things are expected to work, including the implementation of a custom provider.</p>

<p>Great effort has been put in the <strong>design</strong> aspect. It is fair to mention the main motivation behind this initiative was actually to exercise good practices such as object composition, OOP, build a pipeline to continuously release in Maven Central, just to name a few. If you have read this far and have also found value in what has been built, I’d be more than happy to accept your contributions. Keep the good coding.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[A library to convert JSON, XML and more.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Build and release pipeline</title><link href="https://www.juliaaano.com/blog/2017/04/10/build-and-release-pipeline/" rel="alternate" type="text/html" title="Build and release pipeline" /><published>2017-04-10T00:00:00+00:00</published><updated>2017-04-10T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2017/04/10/build-and-release-pipeline</id><content type="html" xml:base="https://www.juliaaano.com/blog/2017/04/10/build-and-release-pipeline/"><![CDATA[<p>A guide to get you started with the implementation of a software build pipeline in <strong><a href="https://travis-ci.org/" target="_blank">Travis CI</a></strong> that automatically gets your code released to GitHub and pushed to a Docker registry. It takes you through some extra features such as Java’s JAR signing (GPG) and encryption of secret data for your build. The examples assume that Java and Maven are in use. Furthermore, if releasing to <strong><a href="https://central.sonatype.org/pages/apache-maven.html" target="_blank">Maven Central</a></strong> is your goal, this guide will take you right there at the door.</p>

<!--more-->

<h2 id="goals">Goals</h2>

<p>For every commit pushed to the master branch in GitHub, the following tasks should be completed by Travis:</p>

<ul>
  <li>Software is built and dependencies are resolved.</li>
  <li>Artifacts are signed.</li>
  <li>Docker image is built.</li>
  <li>Tests run.</li>
  <li>Image is pushed with tag ‘latest’ to <a href="https://hub.docker.com" target="_blank">Docker Hub</a>.</li>
</ul>

<p>These are the basics that should invariably happen. Additionally, as a consequence of the command:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="s">git tag v1.0.0 &amp;&amp; git push --tags</span></code></pre></figure>

<p>Travis should also trigger:</p>

<ul>
  <li>Maven to set a new version based on the Git tag name.</li>
  <li>Docker to push an image with the same tag as the Git tag name.</li>
  <li>Creation of a new GitHub release with all artifacts, javadocs, sources and signature files.</li>
</ul>

<h2 id="travis">Travis</h2>

<p>Make sure Travis and GitHub integration are properly set up.</p>

<p>One of the great advantages of CI tools like Travis is that the build configuration is defined as code and version controlled with the rest of your project in Git. In practice, this means you should have a <strong>.travis.yml</strong> file checked in your repository.</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">language</span><span class="pi">:</span> <span class="s">java</span>

<span class="na">jdk</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">oraclejdk8</span>

<span class="na">services</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">docker</span>

<span class="na">cache</span><span class="pi">:</span>
  <span class="na">directories</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s2">"</span><span class="s">$HOME/.m2"</span>

<span class="na">before_install</span><span class="pi">:</span>
  <span class="c1"># travis encrypt-file command automatically generates the openssl command</span>
  <span class="pi">-</span> <span class="s">openssl aes-256-cbc -K $encrypted_88b828c73747_key -iv $encrypted_88b828c73747_iv -in codesign.asc.enc -out codesign.asc -d</span>
  <span class="pi">-</span> <span class="s">gpg --batch --fast-import codesign.asc</span>
  <span class="pi">-</span> <span class="s">if [ -n "$TRAVIS_TAG" ]; then</span>
      <span class="s">mvn versions:set -DnewVersion=$TRAVIS_TAG;</span>
    <span class="s">fi</span>

<span class="na">install</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">mvn install -DskipTests=true -B -V -Psign -Dgpg.passphrase=$GPG_PASSPHRASE</span>
  <span class="pi">-</span> <span class="s">docker build -t $TRAVIS_REPO_SLUG .</span>

<span class="na">script</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">mvn test -B</span>

<span class="na">after_success</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">docker login -u=$DOCKER_USERNAME -p=$DOCKER_PASSWORD;</span>
  <span class="pi">-</span> <span class="s">if [ -n "$TRAVIS_TAG" ]; then</span>
      <span class="s">docker tag $TRAVIS_REPO_SLUG $TRAVIS_REPO_SLUG:$TRAVIS_TAG;</span>
      <span class="s">docker push $TRAVIS_REPO_SLUG:$TRAVIS_TAG;</span>
    <span class="s">elif [ "$TRAVIS_BRANCH" == "master" ]; then</span>
      <span class="s">docker push $TRAVIS_REPO_SLUG;</span>
    <span class="s">fi</span>

<span class="na">deploy</span><span class="pi">:</span>
  <span class="na">provider</span><span class="pi">:</span> <span class="s">releases</span>
  <span class="na">api_key</span><span class="pi">:</span>
    <span class="na">secure</span><span class="pi">:</span> <span class="s">encrypted-key-generated-by-travis-setup-releases-cli</span>
  <span class="na">file_glob</span><span class="pi">:</span> <span class="kc">true</span>
  <span class="na">file</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">target/app-*.jar</span>
    <span class="pi">-</span> <span class="s">target/java-starter-*.jar</span>
    <span class="pi">-</span> <span class="s">target/java-starter-*.jar.asc</span>
  <span class="na">skip_cleanup</span><span class="pi">:</span> <span class="kc">true</span>
  <span class="na">on</span><span class="pi">:</span>
    <span class="na">repo</span><span class="pi">:</span> <span class="s">juliaaano/java-starter</span>
    <span class="na">branch</span><span class="pi">:</span> <span class="s">master</span>
    <span class="na">tags</span><span class="pi">:</span> <span class="kc">true</span></code></pre></figure>

<h2 id="jar-sign-and-encryption">JAR Sign and Encryption</h2>

<p>In the <strong>before_install</strong> step of the .travis.yml example above, there is a command to decrypt a codesign.asc.enc file to a decrypted codesign.asc one. This is done securely because my repository, in Travis, is the only one with a private key to decrypt it. Previously, I had used <a href="https://docs.travis-ci.com/user/encrypting-files" target="_blank">Travis CLI in my local machine to encrypt</a> that file with the public key available in the corresponding Travis build repo.</p>

<p>The codesign.asc is nothing more than another private key I have once created with GPG. Since it is a requirement from Maven Central to have signed JARs, I found useful to include it as part of my builds. There are plenty of resources out there <a href="https://central.sonatype.org/pages/working-with-pgp-signatures.html" target="_blank">explaining how to work with</a> the GnuPG tool.</p>

<p>A Maven <a href="https://maven.apache.org/plugins/maven-gpg-plugin/" target="_blank">plugin</a> has the job to do the actual JAR signing. For this case, it assumes my key is set as default in the environment (gpg –fast-import). The passphrase is expected to be configured ahead in Travis as an environment variable: $GPG_PASSPHRASE.</p>

<p>There is a project with the <strong>pom.xml</strong> configured with GPG <a href="https://github.com/juliaaano/payload/blob/1.0.0/pom.xml" target="_blank">here</a>.</p>

<h2 id="docker">Docker</h2>

<p>Pay attention to the variables <strong>$DOCKER_USERNAME</strong> and <strong>$DOCKER_PASSWORD</strong>. They should be manually assigned in Travis (same as $GPG_PASSPHRASE) and in my case they refer to my own Docker Hub credentials.</p>

<p>Besides the build and push steps, one good idea might be executing a ‘docker run’ during the ‘script’ stage and conditionally fail or pass the build.</p>

<h2 id="github-release">GitHub Release</h2>

<p>Every successful build derived from master and with a tag is directly posted to a GitHub release. An access token (api_key) is required by Travis, but again the command line tool <a href="https://docs.travis-ci.com/user/deployment/releases/" target="_blank">handles that for you</a>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Much has been said about continuous delivery. I strongly agree it is a matter of process and people before anything else. Nonetheless, I don’t find examples or how-to’s out there quite often. Probably because the resulting implementation is specific to the development process in place. I hope you can use this to get you started and evolve it towards your own deployment pipeline.</p>

<p>The solution presented in this blog came from my Spark Java Maven <strong>Archetypes</strong> project. Check out the source code at <a href="https://github.com/juliaaano/archetypes/tree/master/sparkjava" target="_blank">https://github.com/juliaaano/archetypes/tree/master/sparkjava</a>.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[Software build and release pipeline in Travis CI for a Java Maven based project.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">API &amp;amp; Platforms are the new SOA</title><link href="https://www.juliaaano.com/blog/2017/03/04/apis-the-new-soa/" rel="alternate" type="text/html" title="API &amp;amp; Platforms are the new SOA" /><published>2017-03-04T00:00:00+00:00</published><updated>2017-03-04T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2017/03/04/apis-the-new-soa</id><content type="html" xml:base="https://www.juliaaano.com/blog/2017/03/04/apis-the-new-soa/"><![CDATA[<p>The business around API’s is growing these days. There has been quite a lot of talking about how companies should be building platforms to achieve innovation and reach new markets. It’s all about opening your business to let others create value on top of it. The financial industry (i.e. banks) is taking the lead in this area. One thing I didn’t realize before is how similar this movement is to the old gold SOA.</p>

<!--more-->

<p>When I think about Service Oriented Architectures, I remember the promise of having areas of business modeled as <strong>web services</strong> that were supposed to be shared and discoverable on the internet. A significant fact which represented this period was the vendor-mafia that came and raped the industry by pushing their heavy weight ESB products.</p>

<p><img src="https://d27nechif2d87h.cloudfront.net/images/blue-bus.svg" alt="enterprise-service-bus" class="image-right" loading="lazy" /></p>

<p>It turns out Platforms &amp; API’s are not proposing something much different from what people expected from SOA before. I am afraid the same old vendors have already perceived that.</p>

<p>Not long ago I had the opportunity to attend a conference focused on the API/Platform space. I noticed a bunch of companies with bundle products that remembered pretty much the enterprise service buses we learned to be suspicious about. More specifically, there were solutions that addressed the issues of the enterprise in <strong>horizontal</strong> layers, where API’s were exposed in standard ways with some sort of orchestrator in the middle.</p>

<p>While I draw this parallel between API’s and SOA, I can’t avoid to remember how many discussions there has been around Microservices and SOA. I guess that was the <strong>wrong</strong> comparison. The new SOA is “The Platform”. Microservices are just an implementation detail.</p>

<p>Lastly, I do understand there are many differences between the new API movement and SOA. One example is the <strong>developer engagement</strong>. It seems to be more interesting to build apps on top of friendly JSON and hypermedia driven api’s than it used to be with the problematic XML SOAP protocol. However, in principle, I believe both approaches share the same purpose.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[The API / Platform space and Service Oriented Architectures have much in common, specially the appetite from vendors to sell their solutions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Make it simple with Spark Java</title><link href="https://www.juliaaano.com/blog/2017/02/21/make-simple-with-spark-java/" rel="alternate" type="text/html" title="Make it simple with Spark Java" /><published>2017-02-21T00:00:00+00:00</published><updated>2017-02-21T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2017/02/21/make-simple-with-spark-java</id><content type="html" xml:base="https://www.juliaaano.com/blog/2017/02/21/make-simple-with-spark-java/"><![CDATA[<p>About an year ago I’ve stumbled upon this interesting little framework called <strong><a href="https://sparkjava.com/" target="_blank">Spark Java</a></strong>. If you are looking for a lightweight alternative to quickly develop <strong>REST APIs in Java</strong>, you might like this.</p>

<!--more-->

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">...</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">get</span><span class="o">(</span><span class="s">"/hello"</span><span class="o">,</span> <span class="o">(</span><span class="n">req</span><span class="o">,</span> <span class="n">res</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="s">"Hello World"</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>

<p>Pretty straightforward. Spark Java leverages Java 8 to provide an easy to use and understand api. Method get() registers the endpoint and starts up an embedded Jetty server to handle the incoming http requests.</p>

<p>Look at this other example:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">...</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
  <span class="kd">final</span> <span class="nc">Repository</span> <span class="n">repository</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Repository</span><span class="o">();</span>
  <span class="n">post</span><span class="o">(</span><span class="s">"/hello"</span><span class="o">,</span> <span class="s">"application/json"</span><span class="o">,</span> <span class="o">(</span><span class="n">req</span><span class="o">,</span> <span class="n">res</span><span class="o">)</span> <span class="o">-&gt;</span>
    <span class="nc">Entity</span> <span class="n">entity</span> <span class="o">=</span> <span class="n">repository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">body</span><span class="o">());</span>
    <span class="n">res</span><span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="mi">201</span><span class="o">);</span>
    <span class="k">return</span> <span class="n">entity</span><span class="o">;</span>
  <span class="o">},</span> <span class="k">new</span> <span class="nc">JsonResponseTransformer</span><span class="o">());</span>
<span class="o">}</span></code></pre></figure>

<p>Here we declare a <strong>POST</strong> endpoint that only gets called if the client sets Accept: “application/json” request header. Moreover, we return an entity that is serialized to <strong>JSON</strong> using an object that implements ResponseTransformer; it could possibly use <a href="https://github.com/google/gson" target="_blank">Gson</a> behind the scenes.</p>

<p>Spark Java has not invented anything new. The design is pretty much taken from Ruby’s Sinatra framework.</p>

<h3 id="in-summary">In summary</h3>

<p>Simple, easy to maintain and understand.</p>

<p>No “magic”. Get rid of all the levels of indirection that a framework like Spring MVC introduces.</p>

<p>Better <strong>separation of concerns</strong>. Spark Java does not try to save the world.</p>

<h3 id="theres-more">There’s more…</h3>

<p>Let’s go a bit fancy. Here’s a design idea you can use when there are multiple endpoints to configure.</p>

<p>First, create a builder interface:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">EndpointBuilder</span> <span class="o">{</span>
  <span class="kt">void</span> <span class="nf">configure</span><span class="o">(</span><span class="nc">Service</span> <span class="n">spark</span><span class="o">,</span> <span class="nc">String</span> <span class="n">basePath</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>

<p>Now, let’s say you have one of many other rest endpoints resources to set up:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CustomerEndpoint</span> <span class="kd">implements</span> <span class="nc">EndpointBuilder</span> <span class="o">{</span>

  <span class="kd">private</span> <span class="kd">final</span> <span class="nc">CustomerService</span> <span class="n">customerService</span><span class="o">;</span>

  <span class="kd">public</span> <span class="nf">CustomerEndpoint</span><span class="o">(</span><span class="nc">CustomerService</span> <span class="n">service</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">customerService</span> <span class="o">=</span> <span class="n">service</span><span class="o">;</span>
  <span class="o">}</span>

  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">configure</span><span class="o">(</span><span class="nc">Service</span> <span class="n">spark</span><span class="o">,</span> <span class="nc">String</span> <span class="n">basePath</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">spark</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">basePath</span> <span class="o">+</span> <span class="s">"/customer"</span><span class="o">,</span> <span class="o">(</span><span class="n">req</span><span class="o">,</span> <span class="n">res</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
      <span class="k">return</span> <span class="s">"hello"</span><span class="o">;</span>
    <span class="o">});</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre></figure>

<p>Finally, create a RestContext class that will hold the spark instance and will enable you to configure whatever routes you wish:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">class</span> <span class="nc">RestContext</span> <span class="o">{</span>

  <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Logger</span> <span class="n">logger</span> <span class="o">=</span> <span class="nc">LoggerFactory</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="nc">RestContext</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Service</span> <span class="n">spark</span><span class="o">;</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">basePath</span><span class="o">;</span>

  <span class="kd">public</span> <span class="nf">RestContext</span><span class="o">(</span><span class="kt">int</span> <span class="n">port</span><span class="o">,</span> <span class="nc">String</span> <span class="n">basePath</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">basePath</span> <span class="o">=</span> <span class="n">basePath</span><span class="o">;</span>
    <span class="n">spark</span> <span class="o">=</span> <span class="nc">Service</span><span class="o">.</span><span class="na">ignite</span><span class="o">().</span><span class="na">port</span><span class="o">(</span><span class="n">port</span><span class="o">);</span> <span class="c1">// import spark.Service;</span>
  <span class="o">}</span>

  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addEndpoint</span><span class="o">(</span><span class="nc">EndpointBuilder</span> <span class="n">endpoint</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">endpoint</span><span class="o">.</span><span class="na">configure</span><span class="o">(</span><span class="n">spark</span><span class="o">,</span> <span class="n">basePath</span><span class="o">);</span>
    <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"REST endpoints registered for {}."</span><span class="o">,</span> <span class="n">endpoint</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
  <span class="o">}</span>

  <span class="c1">// Then you can even have some fun:</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">enableCors</span><span class="o">()</span> <span class="o">{</span>
    <span class="n">spark</span><span class="o">.</span><span class="na">before</span><span class="o">((</span><span class="n">request</span><span class="o">,</span> <span class="n">response</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span>
      <span class="n">response</span><span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"Access-Control-Allow-Origin"</span><span class="o">,</span> <span class="s">"*"</span><span class="o">);</span>
      <span class="n">response</span><span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"Access-Control-Allow-Methods"</span><span class="o">,</span> <span class="s">"GET, POST, PUT, DELETE, OPTIONS"</span><span class="o">);</span>
      <span class="n">response</span><span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"Access-Control-Allow-Headers"</span><span class="o">,</span> <span class="s">"Content-Type, api_key, Authorization"</span><span class="o">);</span>
    <span class="o">});</span>
    <span class="n">logger</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"CORS support enabled."</span><span class="o">);</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre></figure>

<p>You should be able to use this context class in your main method (and optionally in your test classes):</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">...</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
  <span class="nc">RestContext</span> <span class="n">context</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">RestContext</span><span class="o">(</span><span class="mi">8080</span><span class="o">,</span> <span class="s">"/api"</span><span class="o">);</span>
  <span class="n">context</span><span class="o">.</span><span class="na">addEndpoint</span><span class="o">(</span><span class="k">new</span> <span class="nc">CustomerEndpoint</span><span class="o">(</span><span class="k">new</span> <span class="nc">CustomerService</span><span class="o">()));</span>
  <span class="n">context</span><span class="o">.</span><span class="na">addEndpoint</span><span class="o">(</span><span class="k">new</span> <span class="nc">AnotherEndpoint</span><span class="o">());</span> <span class="c1">// you can add or remove as many as you want.</span>
  <span class="n">context</span><span class="o">.</span><span class="na">enableCors</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[Take it easy and develop REST APIs in Java. Fast, elegant, declarative and functional.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Building this Blog</title><link href="https://www.juliaaano.com/blog/2017/02/07/building-this-blog/" rel="alternate" type="text/html" title="Building this Blog" /><published>2017-02-07T00:00:00+00:00</published><updated>2017-02-07T00:00:00+00:00</updated><id>https://www.juliaaano.com/blog/2017/02/07/building-this-blog</id><content type="html" xml:base="https://www.juliaaano.com/blog/2017/02/07/building-this-blog/"><![CDATA[<p>A few weeks ago I decided to engage in a project of building a blog. I was looking for challenges, I wanted to build something of my own, without using some of these well known platforms like Wordpress, Blogger, etc. It was more about the journey and satisfaction of dealing with a domain that I was never very familiar with: <strong>front-end development</strong>.</p>

<!--more-->
<p>The result is this website you are seeing now. Although it may look simple (that’s always the goal!), there has been many things I’ve been through during this project. I would like to share with you the major practices and tools I learned the past weeks. This way I hope I can help you if you are also interested on building your own website.</p>

<p>I’ll be brief, most of the topics deserve their own blog posts, and I’m looking forward to write more about them in the future.</p>

<h3 id="jekyll">Jekyll</h3>

<p>The great deal about this website is that it is completely static. I use <strong><a href="https://jekyllrb.com" target="_blank">Jekyll</a></strong> to generate, from templates, the whole content on every source commit. This means no dynamic content, no databases, no <a href="https://en.wikipedia.org/wiki/Content_management_system" target="_blank">CMS</a>; just <strong>plain html</strong>. I reckon this makes development much simpler because I’ve established just enough architecture to solve my problem.</p>

<h3 id="github-pages">GitHub Pages</h3>

<p>Here comes the magic! <strong><a href="https://pages.github.com" target="_blank">GitHub Pages</a></strong> has a wonderful <a href="https://help.github.com/articles/about-github-pages-and-jekyll/" target="_blank">integration with Jekyll</a>. Everytime you push code to your pages repository/branch, GitHub will build your site. You don’t need to keep stored your generated web site, because GitHub will do that for you behind the scenes. In the end you get continuous integration, deployment and hosting for free.</p>

<h3 id="disqus">Disqus</h3>

<p>After realising the benefits of having a static website, I asked myself: how am I going to provide comments for the posts? Here <strong><a href="https://disqus.com" target="_blank">Disqus</a></strong> comes into play. Just like Google <a href="#analytics">Analytics</a>, you add a javascript to your html page and bam! It’s there.</p>

<h3 id="analytics">Analytics</h3>

<p>I guess <strong><a href="https://www.google.com/analytics/" target="_blank">Google Analytics</a></strong> is de facto standard for this kind of thing. If you know better solutions, I’m happy to hear.</p>

<h3 id="domain-dns">Domain (DNS)</h3>

<p>Time to setup a custom domain name. I’ve long used juliaaano as an online identity and I hope one day I can tell you the story why. DNS is provided by <strong><a href="https://aws.amazon.com/route53/" target="_blank">Amazon Route 53</a></strong>. All I had to do there was to create a <a href="https://help.github.com/articles/using-a-custom-domain-with-github-pages/" target="_blank">couple of CNAME entries here and there</a>.</p>

<h3 id="accelerated-mobile-pages-removed"><del>Accelerated Mobile Pages</del> (Removed)</h3>

<p><del>I’m proud to say this website is powered by <strong><a href="https://www.ampproject.org" target="_blank">AMP</a></strong>. I stumbled upon this technology by accident and got immediately really excited about it. Besides ensuring your pages load super fast, AMP helps you to build better html. Other than that, it’s a step towards the <a href="https://en.wikipedia.org/wiki/Progressive_web_app" target="_blank">Progressive Web Apps</a> movement. It’s been designed to delivery content to mobile devices, but I see no reason why I wouldn’t use with desktops.</del></p>

<p><strong>Update (2025):</strong> AMP has been removed from this site. Google no longer requires AMP for preferential search ranking, making the additional complexity unnecessary. The site now uses standard HTML with modern best practices like lazy loading images.</p>

<h3 id="content-delivery-network-cdn">Content Delivery Network (CDN)</h3>

<p>All my images, javascript and fonts are delivered by <strong><a href="https://aws.amazon.com/cloudfront/" target="_blank">Amazon CloudFront</a></strong>, backed by <a href="https://aws.amazon.com/s3" target="_blank">Amazon S3</a>. If you decide to have fun with this stuff, pay special attention to cache headers and Cross-Origin Resource Sharing (CORS) settings.</p>

<h3 id="compress-html">Compress HTML</h3>

<p>Getting the html optimised to be delivered over the network is a piece of cake with <strong><a href="https://github.com/penibelst/jekyll-compress-html" target="_blank">Jekyll Compress Html</a></strong>.</p>

<h3 id="responsive">Responsive</h3>

<p>It has been challenging to learn a few CSS tricks to get this website look decent in different screen sizes. I assume you should always have this in mind.</p>

<h3 id="accessibility">Accessibility</h3>

<p>I hope this blog is friendly to people who are visually impaired. I’ve favoured HTML5 tags (header, nav, section, etc.) instead of divs and I’ve tried to use <strong><a href="https://www.w3.org/WAI/intro/aria" target="_blank">WAI-ARIA</a></strong> best practices.</p>

<h3 id="fonts">Fonts</h3>

<p>Why not have a deterministic approach to how your text will look like? I’ve noticed that major websites use their own <strong>typeface</strong>. Although I didn’t want to license ($$$) a paid web font at this moment, I liked the idea to self host the <a href="https://github.com/showcases/fonts" target="_blank">free fonts</a> my blog is using. The benefits are a stronger visual identity and a more predictable behavior, since you don’t rely on the browser picking up the font for you.</p>

<h3 id="font-awesome">Font Awesome</h3>

<p>How awesome is <strong><a href="https://fontawesome.com" target="_blank">Font Awesome</a></strong> with its endless number of icons. You can setup a private account with their CDN where you are able to do some customisations as well as configure to asynchronously load the fonts in your page. Awesome!</p>

<h3 id="favicons">Favicons</h3>

<p>Nowadays favicons go beyond the scope of displaying a nice little image in your browser when a web page is bookmarked. There are specific icons for Android, iPhone and so on. Therefore, if you want to look good in all different platforms, make sure you define them properly <a href="https://realfavicongenerator.net" target="_blank">here</a> or <a href="https://www.websiteplanet.com/webtools/favicon-generator" target="_blank">here</a>.</p>

<h3 id="atom-feeds-rss">Atom Feeds (RSS)</h3>

<p>I keep a RSS-like feed of all my posts. The <strong><a href="https://github.com/jekyll/jekyll-feed" target="_blank">jekyll-feed</a></strong> plugin does that seamlessly for me.</p>

<h3 id="meta-tags-open-graphtwitter">Meta Tags (Open Graph/Twitter)</h3>

<p>This becomes relevant when someone shares a page from your website in a social network. You need to define which image, title and text to display when Facebook/Twitter render the post/tweet card, for example. I’m using a combination of <strong><a href="https://ogp.me/" target="_blank">Open Graph</a></strong> and <strong><a href="https://developer.x.com/en/docs/x-for-websites/cards/overview/abouts-cards" target="_blank">Twitter Cards</a></strong>.</p>

<h3 id="seo">SEO</h3>

<p><strong><a href="https://github.com/jekyll/jekyll-seo-tag" target="_blank">Jekyll SEO Tag</a></strong> to the rescue.</p>

<h3 id="sitemap">Sitemap</h3>

<p>A sitemap makes easier for Google to find my pages (SEO++). The plugin <strong><a href="https://github.com/jekyll/jekyll-sitemap" target="_blank">Jekyll Sitemap</a></strong> creates a new sitemap.xml file on every build.</p>

<h3 id="w3c">W3C</h3>

<p>I often test my site against the <strong><a href="https://validator.w3.org" target="_blank">W3C Validator</a></strong>. It helps me to spot malformed html and stay compliant with W3C standards.</p>

<h3 id="htmlproofer">HTMLProofer</h3>

<p>Fantastic tool to validate generated html output: <strong><a href="https://github.com/gjtorikian/html-proofer" target="_blank">HTMLProofer</a></strong>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>It’s been a nice learning experience to go through this road. As a developer, I wanted to be a bit more professional by building my presence online with my own hands.</p>

<p>I would like to aknowledge and thank <strong><a href="https://www.yegor256.com" target="_blank">Yegor Bugayenko</a></strong> for his blog and <a href="https://www.yegor256.com/256-bloghacks.html" target="_blank">book</a>. They’ve both served to me as a model and foundation for this project.</p>]]></content><author><name>Juliano Mohr</name></author><summary type="html"><![CDATA[The history, technology, tools and practices behind this blog.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" /><media:content medium="image" url="https://d27nechif2d87h.cloudfront.net/images/juliano-bonanza-coffee.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>