<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>semipol.de</title><updated>2024-12-10T11:56:59+00:00</updated><link href="https://www.semipol.de/" rel="alternate" type="text/html" title="html"/><link href="https://www.semipol.de/feed.xml" rel="self" type="application/atom+xml" title="atom"/><link href="https://www.semipol.de/index.json" rel="alternate" type="application/json" title="json"/><id>https://www.semipol.de/</id><entry><title>Testing OpenAPI specification compliance in Quarkus with Prism</title><link rel="alternate" href="https://www.semipol.de/posts/2024/12/testing-openapi-specification-compliance-in-quarkus-with-prism/"/><id>https://www.semipol.de/posts/2024/12/testing-openapi-specification-compliance-in-quarkus-with-prism/</id><published>2024-12-04T00:00:00+00:00</published><updated>2024-12-06T20:12:01+01:00</updated><summary>Quarkus is a good framework choice when developing RESTful APIs in an API-first manner by using the OpenAPI generator to generate models and API interfaces. That way, larger parts of compliance with the API specification are already handled by the compiler. However, not every inconsistency can be detected this way. In this post, I demonstrate how to integrate Stoplight’s Prism proxy into the test infrastructure of a Quarkus Kotlin project for validating OpenAPI specification compliance automatically as part of the API tests.
Table of contentsMotivationValidating OpenAPI compliance with PrismIntegrating Prism into QuarkusImplementing a Quarkus test resourceRedirecting test requests through the test resourceDetecting and fixing a bug in the example projectUsing the test resource in integration testsTrading confidence for test execution timeSummary MotivationIn API-first development with Quarkus and Kotlin I have shown a basic setup for Quarkus to support API-first development. As a short recap, API-first development is an approach of developing (RESTful) APIs, where a formal specification of the intended API (changes) is created before implementing the API provider or consumers. That way, we can make use of the specification for code generation, parallel development, and for verification purposes.
A common issue seen when using APIs based on their documentation is that the actual API implementation differs from what is documented. The setup shown before prevents larger parts of this problem by leveraging code generation through the OpenAPI Generator. Moreover, the compiler catches a few error cases when generated interfaces are not implemented properly. However, not every aspect of API compliance is validated this way and we would still be able to provide an implementation that deviates from the specification. Here’s a short example demonstrating one of the more obvious ways we can still deviate:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # ... paths: /pets: get: summary: List all pets operationId: listPets responses: '200': description: An array of pets content: application/json: schema: $ref: "#/components/schemas/Pets" # ... components: schemas: PetId: type: integer format: int64 Pet: type: object required: - id - name properties: id: $ref: "#/components/schemas/PetId" name: type: string Pets: type: array items: $ref: "#/components/schemas/Pet"</summary><content type="html"><![CDATA[<p>Quarkus is a good framework choice when developing RESTful APIs in an API-first manner by using the OpenAPI generator to generate models and API interfaces.
That way, larger parts of compliance with the API specification are already handled by the compiler.
However, not every inconsistency can be detected this way.
In this post, I demonstrate how to integrate Stoplight’s Prism proxy into the test infrastructure of a Quarkus Kotlin project for validating OpenAPI specification compliance automatically as part of the API tests.</p>
<nav id="toc" class="toc" role="doc-toc"><h2 id="toc-title">Table of contents</h2><ol class="toc-list level-1"><li><a href="#_motivation">Motivation</a></li><li><a href="#_validating_openapi_compliance_with_prism">Validating OpenAPI compliance with Prism</a></li><li><a href="#_integrating_prism_into_quarkus">Integrating Prism into Quarkus</a><ol class="toc-list level-2"><li><a href="#_implementing_a_quarkus_test_resource">Implementing a Quarkus test resource</a></li><li><a href="#_redirecting_test_requests_through_the_test_resource">Redirecting test requests through the test resource</a></li><li><a href="#_detecting_and_fixing_a_bug_in_the_example_project">Detecting and fixing a bug in the example project</a></li><li><a href="#_using_the_test_resource_in_integration_tests">Using the test resource in integration tests</a></li><li><a href="#_trading_confidence_for_test_execution_time">Trading confidence for test execution time</a></li></ol></li><li><a href="#_summary">Summary</a></li></ol></nav>
<section class="doc-section level-1"><h2 id="_motivation">Motivation</h2><p>In <a href="https://www.semipol.de/posts/2024/08/api-first-development-with-quarkus-and-kotlin/">API-first development with Quarkus and Kotlin</a> I have shown a basic setup for Quarkus to support API-first development.
As a short recap, API-first development is an approach of developing (RESTful) APIs, where a formal specification of the intended API (changes) is created before implementing the API provider or consumers.
That way, we can make use of the specification for code generation, parallel development, and for verification purposes.</p>
<p>A common issue seen when using APIs based on their documentation is that the actual API implementation differs from what is documented.
The setup shown before prevents larger parts of this problem by leveraging code generation through the <a href="https://openapi-generator.tech/">OpenAPI Generator</a>.
Moreover, the compiler catches a few error cases when generated interfaces are not implemented properly.
However, not every aspect of API compliance is validated this way and we would still be able to provide an implementation that deviates from the specification.
Here’s a short example demonstrating one of the more obvious ways we can still deviate:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="yaml"><table class="linenotable"><tbody><tr><td class="linenos gl"><pre class="lineno"> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="code"><pre><span class="c1"># ...</span>
<span class="na">paths</span><span class="pi">:</span>
  <span class="na">/pets</span><span class="pi">:</span>
    <span class="na">get</span><span class="pi">:</span>
      <span class="na">summary</span><span class="pi">:</span> <span class="s">List all pets</span>
      <span class="na">operationId</span><span class="pi">:</span> <span class="s">listPets</span>
      <span class="na">responses</span><span class="pi">:</span>
        <span class="s1">&#39;</span><span class="s">200&#39;</span><span class="err">:</span>
          <span class="na">description</span><span class="pi">:</span> <span class="s">An array of pets</span>
          <span class="na">content</span><span class="pi">:</span>
            <span class="na">application/json</span><span class="pi">:</span>
              <span class="na">schema</span><span class="pi">:</span>
                <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/schemas/Pets&#34;</span>
<span class="c1"># ...</span>
<span class="na">components</span><span class="pi">:</span>
  <span class="na">schemas</span><span class="pi">:</span>
    <span class="na">PetId</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">integer</span>
      <span class="na">format</span><span class="pi">:</span> <span class="s">int64</span>
    <span class="na">Pet</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">object</span>
      <span class="na">required</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">id</span>
        <span class="pi">-</span> <span class="s">name</span>
      <span class="na">properties</span><span class="pi">:</span>
        <span class="na">id</span><span class="pi">:</span>
          <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/schemas/PetId&#34;</span>
        <span class="na">name</span><span class="pi">:</span>
          <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
    <span class="na">Pets</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">array</span>
      <span class="na">items</span><span class="pi">:</span>
        <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/schemas/Pet&#34;</span>
</pre></td></tr></tbody></table></code></pre></div>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>The example here is a stripped down version of the actual API definition in the <a href="https://github.com/languitar/quarkus-api-first-example">example project</a> for the sake of brevity.</p></aside>
<p>The <code>GET /pets</code> should clearly return an array of <code>Pet</code> objects.
However, we could easily (and hopefully accidentally) implement it this way without the Kotlin compiler detecting the problem:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="k">override</span> <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">listPets</span><span class="p">():</span> <span class="nc">Response</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="p">.</span><span class="nf">ok</span><span class="p">(</span><span class="nf">listOf</span><span class="p">(</span><span class="s">&#34;not&#34;</span><span class="p">,</span> <span class="s">&#34;valid&#34;</span><span class="p">)).</span><span class="nf">build</span><span class="p">()</span>
<span class="p">}</span></code></pre></div>
<p>Being able to do this is definitely not ideal and we need to improve the test harness of the API implementation to prevent such deviations from being possible.</p></section>
<section class="doc-section level-1"><h2 id="_validating_openapi_compliance_with_prism">Validating OpenAPI compliance with Prism</h2><p>Fortunately, tools are available to check actual API requests and responses for compliance with the specification.
Probably the best option to use right now is Stoplight’s <a href="https://stoplight.io/open-source/prism">Prism</a>.In addition to being a mock server, which would be useful for implementing a consumer for a yet to be implemented API, Prism can also act as a validation proxy.
In this mode, Prism compares requests and responses to the OpenAPI specification and flags invalid requests or responses.</p>
<p>Let’s explore for a moment how that works.
First, we spin up a stub implementation providing an invalid response.
The quickest way I could come up with is by using the <a href="https://docs.python.org/3/library/http.server.html">Python http.server module</a>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="kn">from</span> <span class="n">http.server</span> <span class="kn">import</span> <span class="n">BaseHTTPRequestHandler</span><span class="p">,</span> <span class="n">HTTPServer</span>

<span class="k">class</span> <span class="nc">BrokenServer</span><span class="p">(</span><span class="n">BaseHTTPRequestHandler</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">do_GET</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">send_response</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">send_header</span><span class="p">(</span><span class="sh">&#34;</span><span class="s">Content-type</span><span class="sh">&#34;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">application/json</span><span class="sh">&#34;</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">end_headers</span><span class="p">()</span>
        <span class="n">self</span><span class="p">.</span><span class="n">wfile</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="nf">bytes</span><span class="p">(</span><span class="sh">&#39;</span><span class="s">[</span><span class="sh">&#34;</span><span class="s">not</span><span class="sh">&#34;</span><span class="s">, </span><span class="sh">&#34;</span><span class="s">valid</span><span class="sh">&#34;</span><span class="s">]</span><span class="sh">&#39;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">utf-8</span><span class="sh">&#34;</span><span class="p">))</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">&#34;</span><span class="s">__main__</span><span class="sh">&#34;</span><span class="p">:</span>
    <span class="k">with</span> <span class="nc">HTTPServer</span><span class="p">((</span><span class="sh">&#34;</span><span class="s">localhost</span><span class="sh">&#34;</span><span class="p">,</span> <span class="mi">9000</span><span class="p">),</span> <span class="n">BrokenServer</span><span class="p">)</span> <span class="k">as</span> <span class="n">server</span><span class="p">:</span>
        <span class="n">server</span><span class="p">.</span><span class="nf">serve_forever</span><span class="p">()</span></code></pre></div>
<p>Once this script is launched, we can verify that it provides a reply for <code>GET /pets</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>curl <span class="nt">-4</span> <span class="nt">-v</span> http://localhost:9000/pets
<span class="go">* Host localhost:9000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying 127.0.0.1:9000...
* Connected to localhost (127.0.0.1) port 9000
* using HTTP/1.x
</span><span class="gp">&gt;</span><span class="w"> </span>GET /pets HTTP/1.1
<span class="gp">&gt;</span><span class="w"> </span>Host: localhost:9000
<span class="gp">&gt;</span><span class="w"> </span>User-Agent: curl/8.11.0
<span class="gp">&gt;</span><span class="w"> </span>Accept: <span class="k">*</span>/<span class="k">*</span>
<span class="gp">&gt;</span><span class="w">
</span><span class="go">* Request completely sent off
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 200 OK
&lt; Server: BaseHTTP/0.6 Python/3.12.7
&lt; Date: Thu, 28 Nov 2024 21:59:32 GMT
&lt; Content-type: application/json
&lt;
</span><span class="gp">* shutting down connection #</span>0
<span class="go">[&#34;not&#34;, &#34;valid&#34;]</span></code></pre></div>
<p>We can now launch Prism with the known OpenAPI specification and our broken implementation as the upstream server:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="go">❯ ./prism-cli-linux proxy openapi.yaml http://127.0.0.1:9000
[11:03:46 PM] › [CLI] …  awaiting  Starting Prism…
[11:03:47 PM] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/pets
[11:03:47 PM] › [CLI] ▶  start     Prism is listening on http://127.0.0.1:4010</span></code></pre></div>
<p>When we repeat the curl request against the proxy, we receive the following:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>curl <span class="nt">-4</span> <span class="nt">-v</span> http://localhost:4010/pets
<span class="go">* Host localhost:4010 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying 127.0.0.1:4010...
* Connected to localhost (127.0.0.1) port 4010
* using HTTP/1.x
</span><span class="gp">&gt;</span><span class="w"> </span>GET /pets HTTP/1.1
<span class="gp">&gt;</span><span class="w"> </span>Host: localhost:4010
<span class="gp">&gt;</span><span class="w"> </span>User-Agent: curl/8.11.0
<span class="gp">&gt;</span><span class="w"> </span>Accept: <span class="k">*</span>/<span class="k">*</span>
<span class="gp">&gt;</span><span class="w">
</span><span class="go">* Request completely sent off
&lt; HTTP/1.1 200 OK
&lt; Access-Control-Allow-Origin: *
&lt; Access-Control-Allow-Headers: *
&lt; Access-Control-Allow-Credentials: true
&lt; Access-Control-Expose-Headers: *
&lt; sl-violations: [{&#34;location&#34;:[&#34;response&#34;,&#34;body&#34;,&#34;0&#34;],&#34;severity&#34;:&#34;Error&#34;,&#34;code&#34;:&#34;type&#34;,&#34;message&#34;:&#34;Response body property 0 must be object&#34;},{&#34;location&#34;:[&#34;response&#34;,&#34;body&#34;,&#34;1&#34;],&#34;severity&#34;:&#34;Error&#34;,&#34;code&#34;:&#34;type&#34;,&#34;message&#34;:&#34;Response body property 1 must be object&#34;}]
&lt; server: BaseHTTP/0.6 Python/3.12.7
&lt; date: Thu, 28 Nov 2024 22:03:48 GMT
&lt; content-type: application/json
&lt; Content-Length: 15
&lt; Connection: keep-alive
&lt; Keep-Alive: timeout=5
&lt;
</span><span class="gp">* Connection #</span>0 to host localhost left intact
<span class="go">[&#34;not&#34;,&#34;valid&#34;]</span></code></pre></div>
<p>Prism has added an <code>sl-violations</code> header with information on how the response deviates from the API specification.
For the sake of completeness, this header is absent in case of valid responses:</p>
<div class="listing-block"><pre class="rouge highlight"><code>&lt; HTTP/1.1 200 OK
&lt; Access-Control-Allow-Origin: *
&lt; Access-Control-Allow-Headers: *
&lt; Access-Control-Allow-Credentials: true
&lt; Access-Control-Expose-Headers: *
&lt; server: BaseHTTP/0.6 Python/3.12.7
&lt; date: Thu, 28 Nov 2024 22:07:08 GMT
&lt; content-type: application/json
&lt; Content-Length: 2
&lt; Connection: keep-alive
&lt; Keep-Alive: timeout=5
&lt;
* Connection #0 to host localhost left intact
[]</code></pre></div>
<p>It’s still somewhat easy to miss the violations header.
We can make violations a bit more obvious by using the <code>--errors</code> command line flag.
This instructs Prism to respond with an internal server error in case of violations, which is a lot less likely to be missed:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>curl <span class="nt">-4</span> <span class="nt">-v</span> http://localhost:4010/pets
<span class="go">* Host localhost:4010 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying 127.0.0.1:4010...
* Connected to localhost (127.0.0.1) port 4010
* using HTTP/1.x
</span><span class="gp">&gt;</span><span class="w"> </span>GET /pets HTTP/1.1
<span class="gp">&gt;</span><span class="w"> </span>Host: localhost:4010
<span class="gp">&gt;</span><span class="w"> </span>User-Agent: curl/8.11.0
<span class="gp">&gt;</span><span class="w"> </span>Accept: <span class="k">*</span>/<span class="k">*</span>
<span class="gp">&gt;</span><span class="w">
</span><span class="go">* Request completely sent off
&lt; HTTP/1.1 500 Internal Server Error
&lt; Access-Control-Allow-Origin: *
&lt; Access-Control-Allow-Headers: *
&lt; Access-Control-Allow-Credentials: true
&lt; Access-Control-Expose-Headers: *
&lt; sl-violations: [{&#34;location&#34;:[&#34;response&#34;,&#34;body&#34;,&#34;0&#34;],&#34;severity&#34;:&#34;Error&#34;,&#34;code&#34;:&#34;type&#34;,&#34;message&#34;:&#34;Response body property 0 must be object&#34;},{&#34;location&#34;:[&#34;response&#34;,&#34;body&#34;,&#34;1&#34;],&#34;severity&#34;:&#34;Error&#34;,&#34;code&#34;:&#34;type&#34;,&#34;message&#34;:&#34;Response body property 1 must be object&#34;}]
&lt; content-type: application/problem+json
&lt; Content-Length: 483
&lt; Date: Thu, 28 Nov 2024 22:09:38 GMT
&lt; Connection: keep-alive
&lt; Keep-Alive: timeout=5
&lt;
</span><span class="gp">* Connection #</span>0 to host localhost left intact
<span class="go">{
</span><span class="gp">  &#34;type&#34;: &#34;https://stoplight.io/prism/errors#</span>VIOLATIONS<span class="s2">&#34;,
</span><span class="go">  &#34;title&#34;: &#34;Request/Response not valid&#34;,
  &#34;status&#34;: 500,
  &#34;detail&#34;: &#34;Your request/response is not valid and the --errors flag is set, so Prism is generating this error for you.&#34;,
  &#34;validation&#34;: [
    {
      &#34;location&#34;: [
        &#34;response&#34;,
        &#34;body&#34;,
        &#34;0&#34;
      ],
      &#34;severity&#34;: &#34;Error&#34;,
      &#34;code&#34;: &#34;type&#34;,
      &#34;message&#34;: &#34;Response body property 0 must be object&#34;
    },
    {
      &#34;location&#34;: [
        &#34;response&#34;,
        &#34;body&#34;,
        &#34;1&#34;
      ],
      &#34;severity&#34;: &#34;Error&#34;,
      &#34;code&#34;: &#34;type&#34;,
      &#34;message&#34;: &#34;Response body property 1 must be object&#34;
    }
  ]
}</span></code></pre></div>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>I have pretty-printed the JSON error response for better readability.</p></aside></section>
<section class="doc-section level-1"><h2 id="_integrating_prism_into_quarkus">Integrating Prism into Quarkus</h2><p>In <a href="https://www.semipol.de/posts/2024/08/api-first-development-with-quarkus-and-kotlin/">API-first development with Quarkus and Kotlin</a> I have set up a <a href="https://github.com/languitar/quarkus-api-first-example">Quarkus + Kotlin example project for API-first development</a>.
I will now show how to integrate Prism into the test setup of that project so that we get automatic response validation whenever we test one of the API endpoints.
That way, it becomes even less likely that the API implementation is not compliant with the OpenAPI specification.</p>
<section class="doc-section level-2"><h3 id="_implementing_a_quarkus_test_resource">Implementing a Quarkus test resource</h3><p>For validating responses with Prism, we need a running instance of Prism that tests can use for requests instead of the actual Quarkus app.
The most portable way is to start Prism as a container, which avoids developers from having to provide an installation of Prism on their machine.
External services such as the Prism proxy are usually spun up as &#34;test resources&#34; in Quarkus.
Therefore, we first need an implementation of a <code>QuarkusTestResourceLifecycleManager</code>, which we call <code>PrismProxyResource</code>.
This class spins up a Prism container using <a href="https://testcontainers.com/">testcontainers</a>.
The container is configured to proxy requests to the started Quarkus app used by the Quarkus test infrastructure:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="kd">class</span> <span class="nc">PrismProxyResource</span> <span class="p">:</span> <span class="nc">QuarkusTestResourceLifecycleManager</span> <span class="p">{</span>

    <span class="k">override</span> <span class="k">fun</span> <span class="nf">start</span><span class="p">():</span> <span class="nc">MutableMap</span><span class="p">&lt;</span><span class="nc">String</span><span class="p">,</span> <span class="nc">String</span><span class="p">&gt;</span> <span class="p">{</span>
        <span class="nc">Testcontainers</span><span class="p">.</span><span class="nf">exposeHostPorts</span><span class="p">(</span><span class="nf">testPort</span><span class="p">())</span> <b class="conum">1</b>
        <span class="n">proxyContainer</span><span class="p">.</span><span class="nf">start</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">emptyMap</span><span class="p">&lt;</span><span class="nc">String</span><span class="p">,</span> <span class="nc">String</span><span class="p">&gt;().</span><span class="nf">toMutableMap</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">override</span> <span class="k">fun</span> <span class="nf">stop</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">proxyContainer</span><span class="p">.</span><span class="nf">stop</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">companion</span> <span class="k">object</span> <span class="p">{</span>
        <span class="k">private</span> <span class="kd">var</span> <span class="py">proxyContainer</span><span class="p">:</span> <span class="nc">GenericContainer</span><span class="p">&lt;</span><span class="err">*</span><span class="p">&gt;</span> <span class="p">=</span>
            <span class="nc">GenericContainer</span><span class="p">&lt;</span><span class="nc">Nothing</span><span class="p">&gt;(</span><span class="nc">DockerImageName</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="s">&#34;stoplight/prism:5&#34;</span><span class="p">)).</span><span class="nf">apply</span> <span class="p">{</span>
                <span class="nf">withAccessToHost</span><span class="p">(</span><span class="k">true</span><span class="p">)</span> <b class="conum">2</b>
                <span class="nf">withCopyFileToContainer</span><span class="p">(</span> <b class="conum">3</b>
                    <span class="nc">MountableFile</span><span class="p">.</span><span class="nf">forClasspathResource</span><span class="p">(</span><span class="s">&#34;META-INF/openapi.yaml&#34;</span><span class="p">),</span>
                    <span class="s">&#34;/tmp/openapi.yaml&#34;</span>
                <span class="p">)</span>
                <span class="nf">withCommand</span><span class="p">(</span>
                    <span class="s">&#34;proxy&#34;</span><span class="p">,</span>
                    <span class="s">&#34;--errors&#34;</span><span class="p">,</span> <b class="conum">4</b>
                    <span class="s">&#34;-h&#34;</span><span class="p">,</span> <span class="s">&#34;0.0.0.0&#34;</span><span class="p">,</span> <b class="conum">5</b>
                    <span class="s">&#34;/tmp/openapi.yaml&#34;</span><span class="p">,</span> <b class="conum">5</b>
                    <span class="s">&#34;http://host.testcontainers.internal:${testPort()}&#34;</span> <b class="conum">6</b>
                <span class="p">)</span>
                <span class="nf">withExposedPorts</span><span class="p">(</span><span class="mi">4010</span><span class="p">)</span> <b class="conum">7</b>
            <span class="p">}</span>

        <span class="k">private</span> <span class="k">fun</span> <span class="nf">testPort</span><span class="p">():</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nc">ConfigProvider</span><span class="p">.</span><span class="nf">getConfig</span><span class="p">().</span><span class="nf">getOptionalValue</span><span class="p">(</span>
            <span class="s">&#34;quarkus.http.test-port&#34;</span><span class="p">,</span>
            <span class="nc">Int</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span>
        <span class="p">).</span><span class="nf">orElse</span><span class="p">(</span><span class="mi">8081</span><span class="p">)</span> <span class="c1">// The default as documented by Quarkus</span>

        <span class="k">fun</span> <span class="nf">proxyPort</span><span class="p">():</span> <span class="nc">Int</span> <span class="p">=</span> <span class="n">proxyContainer</span><span class="p">.</span><span class="n">firstMappedPort</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<div class="olist arabic"><ol class="arabic"><li>Prism needs access to the Quarkus app used during tests execution.
Quarkus opens an app on a well-known port when running tests.
The Prism container needs access to this app.
Therefore, testcontainers is configured to expose this well-known Quarkus test port from the host system (where the test app is running) to containers.</li><li>The Prism container also needs to declare that it needs host access for being able to reach the Quarkus test app.</li><li>Prism has to know the OpenAPI specification to validate against.
Therefore, we copy it to the container.</li><li>We instruct Prism to generate errors, which will surface automatically in most test cases.
That way, we cannot forget to check the <code>sl-violations</code> header in tests.</li><li>Prism must listen on all interfaces so that requests from outside the container – ie., the host system executing the tests – can be received.</li><li>The upstream for Prism is the test Quarkus app running on the host system.
The URL constructed here uses the <a href="https://java.testcontainers.org/features/networking/#exposing-host-ports-to-the-container">platform-agnostic host exposing feature of testcontainers</a>.</li><li>Finally, we also need to expose the Prism port so that it can be reach from the host system running the tests and thereby performing API requests.</li></ol></div>
<p>As this new resource uses testcontainers, the dependency has to be declared in <code>pom.xml</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
    <span class="nt">&lt;groupId&gt;</span>org.testcontainers<span class="nt">&lt;/groupId&gt;</span>
    <span class="nt">&lt;artifactId&gt;</span>testcontainers<span class="nt">&lt;/artifactId&gt;</span>
    <span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></div>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>A suitable testcontainers version is already set in the Quarkus BOM.</p></aside></section>
<section class="doc-section level-2"><h3 id="_redirecting_test_requests_through_the_test_resource">Redirecting test requests through the test resource</h3><p>With the test resource in place, we can adapt the existing API test to perform requests through Prism:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="nd">@QuarkusTest</span>
<span class="nd">@QuarkusTestResource</span><span class="p">(</span><span class="nc">PrismProxyResource</span><span class="o">::</span><span class="k">class</span><span class="p">)</span> <b class="conum">1</b>
<span class="kd">class</span> <span class="nc">PetsApiTest</span> <span class="p">{</span>

    <span class="nd">@Inject</span>
    <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">petRepository</span><span class="p">:</span> <span class="nc">PetRepository</span>

    <span class="nd">@BeforeEach</span>
    <span class="k">fun</span> <span class="nf">clearRepo</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">petRepository</span><span class="p">.</span><span class="nf">clear</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="nd">@BeforeEach</span>
    <span class="k">fun</span> <span class="nf">usePrism</span><span class="p">()</span> <span class="p">{</span>
        <span class="nc">RestAssured</span><span class="p">.</span><span class="n">port</span> <span class="p">=</span> <span class="nc">PrismProxyResource</span><span class="p">.</span><span class="nf">proxyPort</span><span class="p">()</span> <b class="conum">2</b>
        <span class="nc">RestAssured</span><span class="p">.</span><span class="nf">enableLoggingOfRequestAndResponseIfValidationFails</span><span class="p">()</span> <b class="conum">3</b>
    <span class="p">}</span>

    <span class="nd">@Nested</span>
    <span class="k">inner</span> <span class="kd">class</span> <span class="nc">CreatePets</span> <span class="p">{</span>

        <span class="nd">@Test</span>
        <span class="k">fun</span> <span class="nf">`can</span> <span class="n">create</span> <span class="n">new</span> <span class="nf">pets`</span><span class="p">()</span> <span class="p">{</span>
            <span class="kd">val</span> <span class="py">pet</span> <span class="p">=</span> <span class="nc">Pet</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="s">&#34;new name&#34;</span><span class="p">,</span> <span class="s">&#34;some tag&#34;</span><span class="p">)</span>
            <span class="nc">Given</span> <span class="p">{</span>
                <span class="nf">body</span><span class="p">(</span><span class="n">pet</span><span class="p">)</span>
                <span class="nf">contentType</span><span class="p">(</span><span class="nc">ContentType</span><span class="p">.</span><span class="nc">JSON</span><span class="p">)</span>
            <span class="p">}</span> <span class="nc">When</span> <span class="p">{</span>
                <span class="nf">post</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
            <span class="p">}</span> <span class="nc">Then</span> <span class="p">{</span>
                <span class="nf">statusCode</span><span class="p">(</span><span class="nc">StatusCode</span><span class="p">.</span><span class="nc">CREATED</span><span class="p">)</span>
            <span class="p">}</span>
            <span class="nf">assertTrue</span><span class="p">(</span><span class="n">petRepository</span><span class="p">.</span><span class="nf">listPets</span><span class="p">().</span><span class="nf">contains</span><span class="p">(</span><span class="n">pet</span><span class="p">))</span>
        <span class="p">}</span>

    <span class="p">}</span>

    <span class="c1">// ...</span></code></pre></div>
<div class="olist arabic"><ol class="arabic"><li>At least one test class in Quarkus needs to declare <code>PrismProxyResource</code> as a <code>QuarkusTestResource</code> so that the proxy container is actually started before tests launch.</li><li>We need to convince REST-assured to use the forwarded proxy port instead of the test port of the Quarkus app.
Unfortunately, I could not find a way to prevent this manual configuration step.
The Quarkus test infrastructure resets the REST-assured port before each test.
So we need to overwrite this manually before each test case is run.</li><li>When REST-assured expectations fail, its usually a good idea to see the data that caused the failure.
Could/should be set up once globally for all tests.</li></ol></div>
<p>We now automatically validate all requests and responses against the OpenAPI specification.</p></section>
<section class="doc-section level-2"><h3 id="_detecting_and_fixing_a_bug_in_the_example_project">Detecting and fixing a bug in the example project</h3><p>Running the existing tests in the example project that previously ran green through Prism immediately brought up a violation that was unnoticed before.
Two tests, one for <code>listPets</code> and one for <code>showPetById</code>, failed with the following error reported by Prism:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="json"><span class="p">{</span><span class="w">
    </span><span class="nl">&#34;type&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://stoplight.io/prism/errors#VIOLATIONS&#34;</span><span class="p">,</span><span class="w">
    </span><span class="nl">&#34;title&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Request/Response not valid&#34;</span><span class="p">,</span><span class="w">
    </span><span class="nl">&#34;status&#34;</span><span class="p">:</span><span class="w"> </span><span class="mi">500</span><span class="p">,</span><span class="w">
    </span><span class="nl">&#34;detail&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Your request/response is not valid and the --errors flag is set, so Prism is generating this error for you.&#34;</span><span class="p">,</span><span class="w">
    </span><span class="nl">&#34;validation&#34;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">&#34;location&#34;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                </span><span class="s2">&#34;response&#34;</span><span class="p">,</span><span class="w">
                </span><span class="s2">&#34;body&#34;</span><span class="p">,</span><span class="w">
                </span><span class="s2">&#34;0&#34;</span><span class="p">,</span><span class="w">
                </span><span class="s2">&#34;tag&#34;</span><span class="w">
            </span><span class="p">],</span><span class="w">
            </span><span class="nl">&#34;severity&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Error&#34;</span><span class="p">,</span><span class="w">
            </span><span class="nl">&#34;code&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;type&#34;</span><span class="p">,</span><span class="w">
            </span><span class="nl">&#34;message&#34;</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Response body property 0.tag must be string&#34;</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
</span><span class="p">}</span></code></pre></div>
<p>Pets can have tags according to our specification:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="yaml"><span class="na">Pet</span><span class="pi">:</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">object</span>
  <span class="na">required</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">id</span>
    <span class="pi">-</span> <span class="s">name</span>
  <span class="na">properties</span><span class="pi">:</span>
    <span class="na">id</span><span class="pi">:</span>
      <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/schemas/PetId&#34;</span>
    <span class="na">name</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
    <span class="na">tag</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">string</span></code></pre></div>
<p>However, <code>tag</code> is not declared to be nullable but our serialization adds a <code>null</code> value when the tag is not set in our data class for Pet, which is generated as:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="kd">data class</span> <span class="nc">Pet</span> <span class="p">(</span>
    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">Long</span><span class="p">,</span>

    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">String</span><span class="p">,</span>

    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;tag&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">tag</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">String</span><span class="p">?</span> <span class="p">=</span> <span class="k">null</span>
<span class="p">)</span></code></pre></div>
<p>Probably, the kotlin-server generator of the OpenAPI Generator should have added an explicit <code>@JsonInclude</code> annotation to each field to prevent this issues in the first place.
I could change the <a href="https://openapi-generator.tech/docs/templating/">generator templates</a> to add these annotations.
But then I would be deviating from upstream and wouldn’t get updates for the affected templates anymore with version bumps of OpenAPI Generator.
Therefore, for now, an easier option to fix this problem is to configure the Jackson <code>ObjectMapper</code> used by Quarkus to always exclude null values:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="nd">@Singleton</span>
<span class="kd">class</span> <span class="nc">ObjectMapperCustomizer</span><span class="p">:</span> <span class="nc">ObjectMapperCustomizer</span> <span class="p">{</span>
    <span class="k">override</span> <span class="k">fun</span> <span class="nf">customize</span><span class="p">(</span><span class="n">objectMapper</span><span class="p">:</span> <span class="nc">ObjectMapper</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">objectMapper</span><span class="p">.</span><span class="nf">setSerializationInclusion</span><span class="p">(</span><span class="nc">JsonInclude</span><span class="p">.</span><span class="nc">Include</span><span class="p">.</span><span class="nc">NON_NULL</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>After adding this class to the project, tests execute successfully and we know that all parts of the REST API covered by tests are complying with the OpenAPI specification.</p></section>
<section class="doc-section level-2"><h3 id="_using_the_test_resource_in_integration_tests">Using the test resource in integration tests</h3><p>For now, we have covered typical <code>@QuarkusTests</code>, which are often used for tests that are at least close to the unit test level.
However, the same setup can also be used for integration tests so that we also gain confidence regarding OpenAPI compliance for the integrated product.
The following example shows how to use the new test resource also for integration tests.
Please note, in Quarkus integration tests, tests do not have access to the dependency injection container.
Therefore, we cannot directly modify the contents of the <code>PetRepository</code>.
Instead, we need to use the REST API to test the business logic, which is a good thing to do in integration tests in any case.
With these types of tests we want to gain confidence that the integrated software works as intended and support the business cases.</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="nd">@QuarkusIntegrationTest</span>
<span class="nd">@QuarkusTestResource</span><span class="p">(</span><span class="nc">PrismProxyResource</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
<span class="kd">class</span> <span class="nc">PetsApiIT</span> <span class="p">{</span>

    <span class="nd">@BeforeEach</span>
    <span class="k">fun</span> <span class="nf">beforeEach</span><span class="p">()</span> <span class="p">{</span> <b class="conum">1</b>
        <span class="nc">RestAssured</span><span class="p">.</span><span class="n">port</span> <span class="p">=</span> <span class="nc">PrismProxyResource</span><span class="p">.</span><span class="nf">proxyPort</span><span class="p">()</span>
        <span class="nc">RestAssured</span><span class="p">.</span><span class="nf">enableLoggingOfRequestAndResponseIfValidationFails</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">`can</span> <span class="n">list</span> <span class="n">created</span> <span class="nf">pets`</span><span class="p">()</span> <span class="p">{</span>
        <span class="kd">val</span> <span class="py">pet</span> <span class="p">=</span> <span class="nc">Pet</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="s">&#34;new name&#34;</span><span class="p">,</span> <span class="s">&#34;some tag&#34;</span><span class="p">)</span>
        <span class="nc">Given</span> <span class="p">{</span> <b class="conum">2</b>
            <span class="nf">body</span><span class="p">(</span><span class="n">pet</span><span class="p">)</span>
            <span class="nf">contentType</span><span class="p">(</span><span class="nc">ContentType</span><span class="p">.</span><span class="nc">JSON</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">When</span> <span class="p">{</span>
            <span class="nf">post</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Then</span> <span class="p">{</span>
            <span class="nf">statusCode</span><span class="p">(</span><span class="nc">StatusCode</span><span class="p">.</span><span class="nc">CREATED</span><span class="p">)</span>
        <span class="p">}</span>

        <span class="kd">val</span> <span class="py">responseBody</span> <span class="p">=</span> <span class="nc">When</span> <span class="p">{</span>
            <span class="k">get</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Then</span> <span class="p">{</span>
            <span class="nf">statusCode</span><span class="p">(</span><span class="nc">StatusCode</span><span class="p">.</span><span class="nc">OK</span><span class="p">)</span>
            <span class="nf">contentType</span><span class="p">(</span><span class="nc">ContentType</span><span class="p">.</span><span class="nc">JSON</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Extract</span> <span class="p">{</span>
            <span class="nf">body</span><span class="p">().</span><span class="nf">`as`</span><span class="p">(</span><span class="n">petListTypeRef</span><span class="p">)</span>
        <span class="p">}</span>

        <span class="nf">assertTrue</span><span class="p">(</span><span class="n">responseBody</span><span class="p">.</span><span class="nf">contains</span><span class="p">(</span><span class="n">pet</span><span class="p">))</span>
    <span class="p">}</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">`can</span> <span class="n">receive</span> <span class="n">created</span> <span class="nf">pets`</span><span class="p">()</span> <span class="p">{</span>
        <span class="kd">val</span> <span class="py">pet</span> <span class="p">=</span> <span class="nc">Pet</span><span class="p">(</span><span class="mi">17</span><span class="p">,</span> <span class="s">&#34;new name&#34;</span><span class="p">)</span>
        <span class="nc">Given</span> <span class="p">{</span>
            <span class="nf">body</span><span class="p">(</span><span class="n">pet</span><span class="p">)</span>
            <span class="nf">contentType</span><span class="p">(</span><span class="nc">ContentType</span><span class="p">.</span><span class="nc">JSON</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">When</span> <span class="p">{</span>
            <span class="nf">post</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Then</span> <span class="p">{</span>
            <span class="nf">statusCode</span><span class="p">(</span><span class="nc">StatusCode</span><span class="p">.</span><span class="nc">CREATED</span><span class="p">)</span>
        <span class="p">}</span>

        <span class="kd">val</span> <span class="py">responseBody</span> <span class="p">=</span> <span class="nc">When</span> <span class="p">{</span>
            <span class="k">get</span><span class="p">(</span><span class="s">&#34;/pets/${pet.id}&#34;</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Then</span> <span class="p">{</span>
            <span class="nf">statusCode</span><span class="p">(</span><span class="nc">StatusCode</span><span class="p">.</span><span class="nc">OK</span><span class="p">)</span>
            <span class="nf">contentType</span><span class="p">(</span><span class="nc">ContentType</span><span class="p">.</span><span class="nc">JSON</span><span class="p">)</span>
        <span class="p">}</span> <span class="nc">Extract</span> <span class="p">{</span>
            <span class="nf">body</span><span class="p">().</span><span class="nf">`as`</span><span class="p">(</span><span class="nc">Pet</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
        <span class="p">}</span>

        <span class="nf">assertEquals</span><span class="p">(</span><span class="n">pet</span><span class="p">,</span> <span class="n">responseBody</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">companion</span> <span class="k">object</span> <span class="p">{</span>
        <span class="k">private</span> <span class="kd">val</span> <span class="py">petListTypeRef</span> <span class="p">=</span> <span class="kd">object</span> <span class="err">: </span><span class="nc">TypeRef</span><span class="p">&lt;</span><span class="nc">List</span><span class="p">&lt;</span><span class="nc">Pet</span><span class="p">&gt;&gt;()</span> <span class="p">{}</span>

        <span class="nd">@BeforeAll</span>
        <span class="nd">@JvmStatic</span>
        <span class="k">fun</span> <span class="nf">configureObjectMapper</span><span class="p">()</span> <span class="p">{</span> <b class="conum">3</b>
            <span class="nc">RestAssured</span><span class="p">.</span><span class="n">config</span> <span class="p">=</span> <span class="nc">RestAssuredConfig</span><span class="p">.</span><span class="nf">config</span><span class="p">()</span>
                <span class="p">.</span><span class="nf">objectMapperConfig</span><span class="p">(</span><span class="nc">ObjectMapperConfig</span><span class="p">().</span><span class="nf">jackson2ObjectMapperFactory</span> <span class="p">{</span> <span class="n">cls</span><span class="p">,</span> <span class="n">charset</span> <span class="p">-&gt;</span>
                    <span class="nc">ObjectMapper</span><span class="p">().</span><span class="nf">apply</span> <span class="p">{</span>
                        <span class="nf">findAndRegisterModules</span><span class="p">()</span>
                        <span class="nc">ObjectMapperCustomizer</span><span class="p">().</span><span class="nf">customize</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
                    <span class="p">}</span>
                <span class="p">})</span>
        <span class="p">}</span>
    <span class="p">}</span>

<span class="p">}</span></code></pre></div>
<div class="olist arabic"><ol class="arabic"><li>Similar to the <code>@QuarkusTest</code> case, we unfortunately need to configure REST-assured before each test case to pass requests through Prism.</li><li>Test cases now use the API to set up the pre-conditions instead of manipulating the internal repository.</li><li>The integration test code has no access to the <code>ObjectMapper</code> instance configured inside the Quarkus app.
Therefore, we need to configure it similar to how it would be configured inside the app so that API requests issued by the test code are valid.
For this purpose, we simply reused the <code>ObjectMapperCustomizer</code> from the app code so that we effectively get the same configuration.</li></ol></div>
<p>With this test in place, we can now launch integration test for the first time:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>./mvnw verify <span class="nt">-DskipITs</span><span class="o">=</span><span class="nb">false</span>
<span class="go">
</span><span class="c">...
</span><span class="go">
[INFO] --- failsafe:3.2.5:integration-test (default) @ quarkus-api-first-example ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel
[INFO] Running de.semipol.PetsApiIT

</span><span class="c">...
</span><span class="go">
[11:36:59 AM] › [CLI] …  awaiting  Starting Prism…
2024-12-04 12:37:01,201 INFO  [tc.stoplight/prism:5] (pool-3-thread-1) Container stoplight/prism:5 started in PT4.400961939S
[11:37:01 AM] › [CLI] ℹ  info      GET        http://0.0.0.0:4010/pets
[11:37:01 AM] › [CLI] ℹ  info      POST       http://0.0.0.0:4010/pets
[11:37:01 AM] › [CLI] ℹ  info      GET        http://0.0.0.0:4010/pets/-8863377405594787
[11:37:01 AM] › [CLI] ▶  start     Prism is listening on http://0.0.0.0:4010
Executing &#34;/usr/lib/jvm/java-23-openjdk/bin/java -Dquarkus.http.port=8081 -Dquarkus.http.ssl-port=8444 -Dtest.url=http://localhost:8081 -Dquarkus.log.file.path=/home/languitar/src/quarkus-api-first-example/target/quarkus.log -Dquarkus.log.file.enable=true -Dquarkus.log.category.&#34;io.quarkus&#34;.level=INFO -jar /home/languitar/src/quarkus-api-first-example/target/quarkus-app/quarkus-run.jar&#34;
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,&lt; / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2024-12-04 12:37:02,899 INFO  [io.quarkus] (main) quarkus-api-first-example 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.16.4) started in 0.917s. Listening on: http://0.0.0.0:8081
2024-12-04 12:37:02,906 INFO  [io.quarkus] (main) Profile prod activated.
2024-12-04 12:37:02,907 INFO  [io.quarkus] (main) Installed features: [cdi, kotlin, rest, rest-jackson, smallrye-context-propagation, smallrye-openapi, vertx]
[11:37:04 AM] › [HTTP SERVER] post /pets ℹ  info      Request received
</span><span class="gp">[11:37:04 AM] ›     [PROXY] ℹ  info      &gt;</span><span class="w"> </span>Forwarding <span class="s2">&#34;post&#34;</span> request to http://host.testcontainers.internal:8081/pets...
<span class="go">[11:37:04 AM] ›     [PROXY] ℹ  info      The upstream call to /pets has returned 201
[11:37:04 AM] ›     [PROXY] ℹ  info      &lt; Received forward response
[11:37:04 AM] › [HTTP SERVER] get /pets ℹ  info      Request received
</span><span class="gp">[11:37:04 AM] ›     [PROXY] ℹ  info      &gt;</span><span class="w"> </span>Forwarding <span class="s2">&#34;get&#34;</span> request to http://host.testcontainers.internal:8081/pets...
<span class="go">[11:37:04 AM] ›     [PROXY] ℹ  info      The upstream call to /pets has returned 200
[11:37:04 AM] ›     [PROXY] ℹ  info      &lt; Received forward response
[11:37:04 AM] › [HTTP SERVER] post /pets ℹ  info      Request received
</span><span class="gp">[11:37:04 AM] ›     [PROXY] ℹ  info      &gt;</span><span class="w"> </span>Forwarding <span class="s2">&#34;post&#34;</span> request to http://host.testcontainers.internal:8081/pets...
<span class="go">[11:37:04 AM] ›     [PROXY] ℹ  info      The upstream call to /pets has returned 201
[11:37:04 AM] ›     [PROXY] ℹ  info      &lt; Received forward response
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 15.42 s -- in de.semipol.PetsApiIT
[11:37:05 AM] › [HTTP SERVER] get /pets/17 ℹ  info      Request received
</span><span class="gp">[11:37:05 AM] ›     [PROXY] ℹ  info      &gt;</span><span class="w"> </span>Forwarding <span class="s2">&#34;get&#34;</span> request to http://host.testcontainers.internal:8081/pets/17...
<span class="go">[11:37:05 AM] ›     [PROXY] ℹ  info      The upstream call to /pets/17 has returned 200
[11:37:05 AM] ›     [PROXY] ℹ  info      &lt; Received forward response


[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0</span></code></pre></div>
<p>From the <a href="https://quarkus.io/guides/getting-started-testing#launching-containers">Quarkus documentation on launching containers for integration tests</a> one might think that <code>PrismProxyResource</code> would have to implement <code>DevServicesContext.ContextAware</code>.
However, this is not required because the Quarkus app itself never has to reach the proxy container.
This exact integration test setup also works when running tests against a built container image of the app.</p>
<p>To check a container image with the integration test, the first thing is to enable building container images by adding the following dependency in <code>pom.xml</code></p>
<div class="listing-block"><pre class="rouge highlight"><code 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></div>
<p>Afterwards, we can launch the integration tests against a container image of our application, which is built automatically when executing:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>./mvnw verify <span class="nt">-Dquarkus</span>.container-image.build<span class="o">=</span><span class="nb">true</span> <span class="nt">-DskipITs</span><span class="o">=</span><span class="nb">false</span>
<span class="go">
</span><span class="c">...
</span><span class="go">
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0</span></code></pre></div>
<p>Why does this work without <code>DevServicesContext.ContextAware</code>?
Even when running the Quarkus app to test as a container, the HTTP port of the running app is published to the container host on the well-defined test port 8081 (if not configured differently).
Therefore, Prism can continue to connect that host port and reaches the Quarkus app, despite now being run in a container.</p></section>
<section class="doc-section level-2"><h3 id="_trading_confidence_for_test_execution_time">Trading confidence for test execution time</h3><p>We now have the option to validate API responses (and requests) in all types of tests available in Quarks.
However, launching Prism proxy adds a slight penalty on the execution time of the test suite.
Fortunately, we can now make trade-off decisions.
In case quick executions of things like unit tests are important for you, checking for compliance to the OpenAPI specification can only be used in integration tests.
That way, we trade confidence for test execution time.
In contrast, if specification compliance is very important to the project, then compliance should probably also be tested in all tests.</p></section></section>
<section class="doc-section level-1"><h2 id="_summary">Summary</h2><p>With the addition of a relatively simple Quarkus test resource and a few lines boilerplate in each API test class, we can gain a lot of confidence in whether our REST API complies with the OpenAPI specification.
This was one of the missing puzzle pieces for successfully implementing API-first development with Quarkus as described in <a href="https://www.semipol.de/posts/2024/08/api-first-development-with-quarkus-and-kotlin/">the previous blog post</a>.
What’s now missing for a complete API-first workflow is to lint the API specification so that best-practices and standards are used and to control breaking changes.</p></section>
]]></content></entry><entry><title>API-first development with Quarkus and Kotlin</title><link rel="alternate" href="https://www.semipol.de/posts/2024/08/api-first-development-with-quarkus-and-kotlin/"/><id>https://www.semipol.de/posts/2024/08/api-first-development-with-quarkus-and-kotlin/</id><published>2024-08-16T00:00:00+00:00</published><updated>2024-12-06T14:03:52+01:00</updated><summary>API-first development is a way of developing distributed systems that makes the API specifications of the system components a first-class citizen in the development process. This approach promises to better control the challenges of loosely coupled components communicating via inter-process communication so that the benefits of separating a monolith into individual components pay off sooner. In this post, I will give a brief introduction on what API-first development is and how my preferred JVM-based setup for developing microservices using the API-first principles looks like at the moment.
Table of contentsWhat is API-first developmentAPI-first development for REST APIs with OpenAPIAPI-first and code-first development with OpenAPISetting up an API-first development workflow in QuarkusAdd the API definition to the projectEnable SwaggerUIOnly serve the defined API in SwaggerUILet Quarkus determine the server in the OpenAPI specificationGenerate API stubs using the OpenAPI GeneratorImplementing a generated API resourceSummaryBibliography What is API-first developmentIn a distrusted system, such as a microservice architecture, inter-process communication plays a crucial role. But it comes at a price. Distributed systems are often harder to debug and to refactor. In a monolith, the IDE and the compiler help refactoring programming APIs such as an interface or abstract base class. A mismatch between the API provider and the consumer will usually be caught by the compiler. In a distributed system, usually no compiler helps when changing APIs and we cannot rely on it to find mismatches between consumers and providers. Without care and special testing techniques, errors will only surface at runtime, making the system more brittle and changes more costly. Therefore, it is important that:
APIs are well-designed so that breaking or incompatible changes are infrequentif required, breaking or incompatible changes happen in a controlled way that prevents API consumers from suddenly failing without prior notice.</summary><content type="html"><![CDATA[<p>API-first development is a way of developing distributed systems that makes the API specifications of the system components a first-class citizen in the development process.
This approach promises to better control the challenges of loosely coupled components communicating via inter-process communication so that the benefits of separating a monolith into individual components pay off sooner.
In this post, I will give a brief introduction on what API-first development is and how my preferred JVM-based setup for developing microservices using the API-first principles looks like at the moment.</p>
<nav id="toc" class="toc" role="doc-toc"><h2 id="toc-title">Table of contents</h2><ol class="toc-list level-1"><li><a href="#_what_is_api_first_development">What is API-first development</a></li><li><a href="#_api_first_development_for_rest_apis_with_openapi">API-first development for REST APIs with OpenAPI</a><ol class="toc-list level-2"><li><a href="#_api_first_and_code_first_development_with_openapi">API-first and code-first development with OpenAPI</a></li></ol></li><li><a href="#_setting_up_an_api_first_development_workflow_in_quarkus">Setting up an API-first development workflow in Quarkus</a><ol class="toc-list level-2"><li><a href="#_add_the_api_definition_to_the_project">Add the API definition to the project</a></li><li><a href="#_enable_swaggerui">Enable SwaggerUI</a></li><li><a href="#_only_serve_the_defined_api_in_swaggerui">Only serve the defined API in SwaggerUI</a></li><li><a href="#_let_quarkus_determine_the_server_in_the_openapi_specification">Let Quarkus determine the server in the OpenAPI specification</a></li><li><a href="#_generate_api_stubs_using_the_openapi_generator">Generate API stubs using the OpenAPI Generator</a></li><li><a href="#_implementing_a_generated_api_resource">Implementing a generated API resource</a></li></ol></li><li><a href="#_summary">Summary</a></li><li><a href="#_bibliography">Bibliography</a></li></ol></nav>
<section class="doc-section level-1"><h2 id="_what_is_api_first_development">What is API-first development</h2><p>In a distrusted system, such as a microservice architecture, inter-process communication plays a crucial role.
But it comes at a price.
Distributed systems are often harder to debug and to refactor.
In a monolith, the IDE and the compiler help refactoring programming APIs such as an interface or abstract base class.
A mismatch between the API provider and the consumer will usually be caught by the compiler.
In a distributed system, usually no compiler helps when changing APIs and we cannot rely on it to find mismatches between consumers and providers.
Without care and special testing techniques, errors will only surface at runtime, making the system more brittle and changes more costly.
Therefore, it is important that:</p>
<div class="ulist"><ul><li>APIs are well-designed so that breaking or incompatible changes are infrequent</li><li>if required, breaking or incompatible changes happen in a controlled way that prevents API consumers from suddenly failing without prior notice.</li></ul></div>
<p>Moreover, one of the benefits or distributed systems – if done right – is the higher potential to develop in parallel and with different development teams.
This is only possible if API providers and consumers have agreed on a stable API.</p>
<p>API-first development provides a solution to the aforementioned problems by making the definition of the API the first step in the development process.
Before starting to implement, provider and consumer agree on the desired API (changes) by negotiating them using a formal specification of the API (independent of the programming languages used to implement the provider or consumer).</p>
<p>This process has several benefits:</p>
<div class="ulist"><ul><li>By placing the negotiation of the required API changes up front, including a review process, the API is most likely better designed and better fits the purpose <a href="#Vasudevan2006">[Vasudevan2006]</a>.
Therefore, costly and potentially insecure breaking changes are less likely after this step.</li><li>Once defined, API provider and consumer can develop in parallel.
API providers can make use of validators such as <a href="https://docs.stoplight.io/docs/prism/72d69fb629de0-validation-proxy">prism proxy</a> to ensure that their new implementation complies with the defined API.
Consumers can make use of mock servers such as <a href="https://docs.stoplight.io/docs/prism/9bfdae61985a3-mocking-callbacks-with-prism">prism mock</a> or <a href="https://www.mock-server.com/mock_server/using_openapi.html">MockServer</a> to emulate the yet to be completed API provider for development and testing purposes.</li><li>Based on the formal specification of the API, linters can support the API definition process by alerting about potentially breaking changes or by enforcing API consistency rules.</li><li>The API specification can become a source for code generation, later on simplifying the development process. <a href="#Bryzek2018">[Bryzek2018]</a></li></ul></div>
<p>Of course, like everything in software engineering, there are also downsides to using an API-first development process.
Most notably, putting the API definition first delays the start of the implementation <a href="#Vasudevan2006">[Vasudevan2006]</a>.
Also, developers needs to learn the specification language.
Finally, developing systems using the API-first principles requires changes to the development process.
All participating developers and development teams need to agree that all API changes are performed using API-first methods.
Otherwise, the benefits of this process are lost soon.
But the same is true for many ideas in software development.
Infrastructure as code also loses its value if you constantly have to battle infrastructure drift because someone changed the setup without adapting the code…​</p></section>
<section class="doc-section level-1"><h2 id="_api_first_development_for_rest_apis_with_openapi">API-first development for REST APIs with OpenAPI</h2><p>When developing RESTful APIs, the predominant specification format is <a href="https://spec.openapis.org/oas/latest.html">OpenAPI</a>.
Despite some promising alternatives filling a few gaps that the current OpenAPI standard has (e.g., <a href="https://raml.org/">RAML</a> or <a href="https://www.asyncapi.com">AsyncAPI</a>), the most established format with the widest range of supporting tools and frameworks remains OpenAPI.
OpenAPI is a general format for describing REST APIs via YAML or JSON documents.
The <a href="https://learn.openapis.org/examples/v3.0/petstore.html">petsore example</a> gives a good overview of how an OpenAPI specification looks like.</p>
<section class="doc-section level-2"><h3 id="_api_first_and_code_first_development_with_openapi">API-first and code-first development with OpenAPI</h3><p>Using OpenAPI specifications is not limited to API-first development.
OpenAPI specifications can also be used in a process that is usually called <a href="https://swagger.io/blog/code-first-vs-design-first-api/">code-first development</a>.
Many web development frameworks offer options to directly generate the OpenAPI specification from the implemented endpoints, thereby making the specification a byproduct of the implementation.
To end up with usable specifications, this approach often requires enhancing the endpoint implementations with additional documentation or annotations to guide the OpenAPI generation process.
My personal feeling is that it is pretty hard to end up with a specification that is of similar value and rigor as a hand-crafted one.
Moreover, the required annotations often make the endpoint implementation more verbose and harder to read.
See <a href="#example-spring-boot-annotations">Required annotations for good OpenAPI specifications in Spring Boot</a> for an example of how this might pollute an otherwise simple implementation.
In contrast, <a href="#example-openapi-endpoint">Endpoint definition in an OpenAPI specification</a> shows a comparable endpoint definition specified using OpenAPI.
The specification is better readable and avoids polluting the implementation.
In any case, if you decide against going the API-first approach, generated specification are often better than having nothing at all.
However, you will also lose most of the aforementioned benefits of the general API-first process.</p>
<figure class="example-block" id="example-spring-boot-annotations"><figcaption>Example 1. Required annotations for good OpenAPI specifications in Spring Boot</figcaption>
<div class="example"><p>Here is an example of which annotations are required in Spring Boot to end up with a well-documented auto-generated OpenAPI specification.</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="java"><span class="nd">@Operation</span><span class="o">(</span><span class="n">summary</span> <span class="o">=</span> <span class="s">&#34;Get a book by its id&#34;</span><span class="o">)</span>
<span class="nd">@ApiResponses</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span>
  <span class="nd">@ApiResponse</span><span class="o">(</span><span class="n">responseCode</span> <span class="o">=</span> <span class="s">&#34;200&#34;</span><span class="o">,</span> <span class="n">description</span> <span class="o">=</span> <span class="s">&#34;Found the book&#34;</span><span class="o">,</span>
    <span class="n">content</span> <span class="o">=</span> <span class="o">{</span> <span class="nd">@Content</span><span class="o">(</span><span class="n">mediaType</span> <span class="o">=</span> <span class="s">&#34;application/json&#34;</span><span class="o">,</span>
      <span class="n">schema</span> <span class="o">=</span> <span class="nd">@Schema</span><span class="o">(</span><span class="n">implementation</span> <span class="o">=</span> <span class="nc">Book</span><span class="o">.</span><span class="na">class</span><span class="o">))</span> <span class="o">}),</span>
  <span class="nd">@ApiResponse</span><span class="o">(</span><span class="n">responseCode</span> <span class="o">=</span> <span class="s">&#34;400&#34;</span><span class="o">,</span> <span class="n">description</span> <span class="o">=</span> <span class="s">&#34;Invalid id supplied&#34;</span><span class="o">,</span>
    <span class="n">content</span> <span class="o">=</span> <span class="nd">@Content</span><span class="o">),</span>
  <span class="nd">@ApiResponse</span><span class="o">(</span><span class="n">responseCode</span> <span class="o">=</span> <span class="s">&#34;404&#34;</span><span class="o">,</span> <span class="n">description</span> <span class="o">=</span> <span class="s">&#34;Book not found&#34;</span><span class="o">,</span>
    <span class="n">content</span> <span class="o">=</span> <span class="nd">@Content</span><span class="o">)</span> <span class="o">})</span>
<span class="nd">@GetMapping</span><span class="o">(</span><span class="s">&#34;/{id}&#34;</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Book</span> <span class="nf">findById</span><span class="o">(</span><span class="nd">@Parameter</span><span class="o">(</span><span class="n">description</span> <span class="o">=</span> <span class="s">&#34;id of book to be searched&#34;</span><span class="o">)</span>
  <span class="nd">@PathVariable</span> <span class="kt">long</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">repository</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">id</span><span class="o">).</span><span class="na">orElseThrow</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">BookNotFoundException</span><span class="o">());</span>
<span class="o">}</span></code></pre></div>
<p>Source: <a class="bare" href="https://www.baeldung.com/spring-rest-openapi-documentation">https://www.baeldung.com/spring-rest-openapi-documentation</a></p></div></figure>
<figure class="example-block" id="example-openapi-endpoint"><figcaption>Example 2. Endpoint definition in an OpenAPI specification</figcaption>
<div class="example"><div class="listing-block"><pre class="rouge highlight"><code data-lang="yaml"><span class="na">paths</span><span class="pi">:</span>
  <span class="s">/books/{book_id}</span><span class="err">:</span>
    <span class="na">get</span><span class="pi">:</span>
      <span class="na">summary</span><span class="pi">:</span> <span class="s">Get a book by its id</span>
      <span class="na">parameters</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/parameters/BookId&#34;</span>
      <span class="na">responses</span><span class="pi">:</span>
        <span class="s2">&#34;</span><span class="s">200&#34;</span><span class="err">:</span>
          <span class="na">description</span><span class="pi">:</span> <span class="s">Found the book</span>
          <span class="na">content</span><span class="pi">:</span>
            <span class="na">application/json</span><span class="pi">:</span>
              <span class="na">schema</span><span class="pi">:</span>
                <span class="na">$ref</span><span class="pi">:</span> <span class="s2">&#34;</span><span class="s">#/components/schemas/Book&#34;</span>
      <span class="err">  </span><span class="s2">&#34;</span><span class="s">400&#34;</span><span class="err">:</span>
          <span class="na">description</span><span class="pi">:</span> <span class="s">Invalid id supplied</span>
        <span class="s2">&#34;</span><span class="s">404&#34;</span><span class="err">:</span>
          <span class="na">description</span><span class="pi">:</span> <span class="s">Book not found</span></code></pre></div>
<p>A definition resembling what would be generated from <a href="#example-spring-boot-annotations">Required annotations for good OpenAPI specifications in Spring Boot</a>.
While the total number of lines is larger, the definition visually less cluttered and easier to read.</p></div></figure></section></section>
<section class="doc-section level-1"><h2 id="_setting_up_an_api_first_development_workflow_in_quarkus">Setting up an API-first development workflow in Quarkus</h2><p>The remainder of this blog post describes how to set up an API-first development workflow in Quarkus (with Kotlin).
All explanations given here are glued together in the <a href="https://github.com/languitar/quarkus-api-first-example">quarkus-api-first-example</a> on my GitHub profile.
If in doubt, look into that project and experiment with it to understand how things work.
The example project uses <a href="https://maven.apache.org/">Maven</a> as the build system but things should be transferable to Gradle pretty easily.</p>
<p>The most important decision taken here is that we use code generation with the <a href="https://openapi-generator.tech/">OpenAPI Generator</a> only for generating the classes directly related to implementing the REST API inside an existing Quarkus project.
By default, most generation targets supported by OpenAPI generator would create a fully functional project including all boilerplate code including the build system, gitignore file etc.
While this sounds like an easy path to start, such an approach makes iterating and production-readiness a lot harder.
First, adapting such a project to new API changes is hard as the generator would overwrite all manual modifications and implementations done after the initial project generation.
Second, the generated projects are very opinionated and only a few configuration options exist with respect to the resulting configuration.
The opinions of the template authors might not match what you need and customizing these projects via template changes for the generator is not an easy task.
Therefore, I think the better approach is to let the generator only handle the parts of the application that are concerned with actual REST API implementation by restricting code generation to REST resource interfaces and model classes.</p>
<p>Starting from a basic Quarkus with Kotlin project similar to <a href="https://quarkus.io/guides/kotlin#creating-the-maven-project">the one bootstrapped in the official docs</a>, I’ll now explain important dependencies and configuration changes to the project.
The project later serves an implementation for the aforementioned <a href="https://learn.openapis.org/examples/v3.0/petstore.html">petstore</a> API.</p>
<section class="doc-section level-2"><h3 id="_add_the_api_definition_to_the_project">Add the API definition to the project</h3><p>The first step we need to do is to provide the API definition file in the project resources so that we can bootstrap the API-first workflow from the specification in that file.
For this purpose, the <code>petstore.yaml</code> file mentioned before is placed under <code>src/main/resources/META-INF/openapi.yaml</code>.
This is the canonical path for a pre-defined OpenAPI specification for some of the Quarkus extensions used later on.
Other locations would be possible but would require further configuration options.</p>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>The example pet store specification on learn.openapis.org, at the time of writing, is inconsistent.
The <code>Pet</code> model declares IDs to be of type integer with format int64 while the route to request individual pets declares the route’s path parameter to be of type string.
I have removed this inconsistency in the example project, which therefore uses a slightly diverging specification.</p></aside></section>
<section class="doc-section level-2"><h3 id="_enable_swaggerui">Enable SwaggerUI</h3><p>When working with an OpenAPI specification, one usually wants to provide a <a href="https://swagger.io/tools/swagger-ui/">SwaggerUI</a> based on the API specification for easier development and experimentation with the implemented API.
Quarkus can natively serve the SwaggerUI using an extension, which we add to the <code>dependencies</code> section in <code>pom.xml</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code 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-smallrye-openapi<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></div>
<p>With these changes in place, we can start the Quarkus project for the first time using:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="console"><span class="gp">$</span><span class="w"> </span>./mvnw quarkus:dev</code></pre></div>
<p>Afterwards, the new SwaggerUI is available as part of the Quarkus Dev UI under <a class="bare" href="http://localhost:8080/q/dev-ui/io.quarkus.quarkus-smallrye-openapi/swagger-ui">http://localhost:8080/q/dev-ui/io.quarkus.quarkus-smallrye-openapi/swagger-ui</a>.</p>
<div class="image-block"><img src="first-swagger-ui.png" alt="first swagger ui"/></div></section>
<section class="doc-section level-2"><h3 id="_only_serve_the_defined_api_in_swaggerui">Only serve the defined API in SwaggerUI</h3><p>By default, SwaggerUI would serve a combined specification comprising the contents of the YAML file and further endpoints declared only in the application code.
In an API-first world, this is usually not desired, because any publicly available endpoint has to be defined in the OpenAPI specification first before being implement.
To avoid this behavior, we restrict SwaggerUI to only serve the statically defined specification by adding the following line to <code>src/main/resources/application.properties</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="ini"><span class="py">mp.openapi.scan.disable</span><span class="p">=</span><span class="s">true</span></code></pre></div></section>
<section class="doc-section level-2"><h3 id="_let_quarkus_determine_the_server_in_the_openapi_specification">Let Quarkus determine the server in the OpenAPI specification</h3><p>The OpenAPI standard allows defining <code>servers</code>, which are URLs under which the API is served for clients.
These servers are selectable in SwaggerUI and used when testing requests there.
This model is nice for testing publicly deployed APIS.
However, it doesn’t work well for local development purposes.
We’d have to anticipate all potential local testing environment of different developer systems and pollute the servers array with all of them (IPv4 vs IPv6, running on a remote test host vs. localhost, etc.) so that local testing is possible.
To prevent this configuration issue, it is better to let Quarkus determine a suitable server for us depending on how the application is launched and accessed.</p>
<p>The first thing we need to do is to get rid of any manually defined servers in the <code>servers</code> array of <code>openapi.yaml</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="yaml"><span class="na">servers</span><span class="pi">:</span> <span class="pi">[]</span></code></pre></div>
<p>The second thing to do is to instruct Quarkus to add a suitable server automatically by adding another option to <code>src/main/resources/application.properties</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="ini"><span class="py">quarkus.smallrye-openapi.auto-add-server</span><span class="p">=</span><span class="s">true</span></code></pre></div>
<p>Afterwards, we get an auto-generated server that’s suitable for local development:</p>
<div class="image-block"><img src="correct-server-in-swagger-ui.png" alt="correct server in swagger ui"/></div></section>
<section class="doc-section level-2"><h3 id="_generate_api_stubs_using_the_openapi_generator">Generate API stubs using the OpenAPI Generator</h3><p>One of the main benefits of an API-first approach with an OpenAPI specification is that we can make use of the <a href="https://openapi-generator.tech/">OpenAPI Generator</a> to generate code from the specification.
This ensures that our implementation complies to the implementation and does not drift from it over time.
And it also avoids manual work for us.
Therefore, the next thing we do is to use the <a href="https://openapi-generator.tech/docs/plugins/#maven">OpenAPI Generator Maven plugin</a> to generate REST resource interfaces and model classes for use.
Afterwards, actually providing the endpoints boils down to implementing the generated interfaces using the generate model classes.</p>
<p>Setting up the OpenAPI Generator plugin is a bit involved and I’ll explain the different configuration options in detail after showing the full plugin configuration, which needs to be added to the <code>plugins</code> section in <code>pom.xml</code>:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="xml"><span class="nt">&lt;plugin&gt;</span>
    <span class="nt">&lt;groupId&gt;</span>org.openapitools<span class="nt">&lt;/groupId&gt;</span>
    <span class="nt">&lt;artifactId&gt;</span>openapi-generator-maven-plugin<span class="nt">&lt;/artifactId&gt;</span>
    <span class="nt">&lt;version&gt;</span>7.7.0<span class="nt">&lt;/version&gt;</span>
    <span class="nt">&lt;executions&gt;</span>
        <span class="nt">&lt;execution&gt;</span>
            <span class="nt">&lt;goals&gt;</span>
                <span class="nt">&lt;goal&gt;</span>generate<span class="nt">&lt;/goal&gt;</span>
            <span class="nt">&lt;/goals&gt;</span>
            <span class="nt">&lt;configuration&gt;</span>
                <span class="nt">&lt;inputSpec&gt;</span>${project.basedir}/src/main/resources/META-INF/openapi.yaml<span class="nt">&lt;/inputSpec&gt;</span> <b class="conum">1</b>
                <span class="nt">&lt;generatorName&gt;</span>kotlin-server<span class="nt">&lt;/generatorName&gt;</span> <b class="conum">2</b>
                <span class="nt">&lt;modelPackage&gt;</span>${project.groupId}.adapters.rest<span class="nt">&lt;/modelPackage&gt;</span> <b class="conum">3</b>
                <span class="nt">&lt;apiPackage&gt;</span>${project.groupId}.adapters.rest<span class="nt">&lt;/apiPackage&gt;</span> <b class="conum">3</b>
                <span class="nt">&lt;generateApiTests&gt;</span>false<span class="nt">&lt;/generateApiTests&gt;</span> <b class="conum">4</b>
                <span class="nt">&lt;generateModelTests&gt;</span>false<span class="nt">&lt;/generateModelTests&gt;</span> <b class="conum">4</b>
                <span class="nt">&lt;generateSupportingFiles&gt;</span>false<span class="nt">&lt;/generateSupportingFiles&gt;</span> <b class="conum">5</b>
                <span class="nt">&lt;configOptions&gt;</span>
                    <span class="nt">&lt;sourceFolder&gt;</span>src/main/kotlin<span class="nt">&lt;/sourceFolder&gt;</span>
                    <span class="nt">&lt;library&gt;</span>jaxrs-spec<span class="nt">&lt;/library&gt;</span> <b class="conum">6</b>
                    <span class="nt">&lt;useJakartaEe&gt;</span>true<span class="nt">&lt;/useJakartaEe&gt;</span> <b class="conum">6</b>
                    <span class="nt">&lt;interfaceOnly&gt;</span>true<span class="nt">&lt;/interfaceOnly&gt;</span> <b class="conum">7</b>
                    <span class="nt">&lt;useCoroutines&gt;</span>true<span class="nt">&lt;/useCoroutines&gt;</span> <b class="conum">8</b>
                    <span class="nt">&lt;returnResponse&gt;</span>true<span class="nt">&lt;/returnResponse&gt;</span> <b class="conum">9</b>
                <span class="nt">&lt;/configOptions&gt;</span>
            <span class="nt">&lt;/configuration&gt;</span>
        <span class="nt">&lt;/execution&gt;</span>
    <span class="nt">&lt;/executions&gt;</span>
<span class="nt">&lt;/plugin&gt;</span></code></pre><ol class="callout-list arabic"><li>We instruct OpenAPI generator to generate code from our specification residing in the Quarkus default location, which OpenAPI generator isn’t aware of without this configuration option.</li><li>As this example is a Quarkus Kotlin project, we want to generate Kotlin code for a server implementation of the API.</li><li>We have to provide a package into which the API resource interfaces and data classes for the models are generated.</li><li>We don’t need auto-generated tests for the server code.
These are usually of low value and manually written tests better reflect needs of the implementation (we usually do grey-box testing).</li><li>By default, the <code>kotlin-server</code> generator target would generate a fully-functional server project.
As explained above, we don’t want this and disable all supporting files that surround the actual API.</li><li>The <code>quarkus-rest</code> extension used in this project is based on JAXRS.
Therefore, we want the generator to generate code complying with this specification.
Moreover, we need to use the Jakarta EE namespace for the specification classes and annotations, which is the default in Quarkus.</li><li>To support iterating the API and the implementation we need a strong separation between generated code and the manual implementation.
Therefore, we let the OpenAPI generator generate interfaces for the REST resources only.
We can then provide the API implementation by implementing these interfaces in completely separate files (and a separate source tree).
That way, a new invocation of the generator will never change manual implementations we have done and we can safely iterate.</li><li>As this project uses Kotlin, it’s probably a good idea to generate route functions as coroutines in the resource interfaces so that we can freely make use of the couroutine-based ecosystem available in Kotlin.</li><li>Be default, generated functions would be of the form <code>operationId(params): ModelClass</code>.
This results in concise API implementations but limits our options to control things like response headers.
Therefore, we instruct the generator to expect instances of <code>Response</code> instead.
This is a trade-off, as we now lose type-safety in the function signatures.
In case you never need to change response headers dynamically, not using this options is probably the better way to go.</li></ol></div>

<p>With this configuration in place, a fresh run of <code>./mvnw compile</code> (or <code>./mvnw generate-sources</code>) results in the OpenAPI Generator creating two classes.
First, a model class for a Pet complying with the defined JSON format when serialized:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="k">package</span> <span class="nn">de.semipol.adapters.rest</span>

<span class="k">import</span> <span class="nn">com.fasterxml.jackson.annotation.JsonProperty</span>

<span class="kd">data class</span> <span class="nc">Pet</span> <span class="p">(</span>
    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">Long</span><span class="p">,</span>

    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;name&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">String</span><span class="p">,</span>

    <span class="nd">@JsonProperty</span><span class="p">(</span><span class="s">&#34;tag&#34;</span><span class="p">)</span>
    <span class="kd">val</span> <span class="py">tag</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">String</span><span class="p">?</span> <span class="p">=</span> <span class="k">null</span>
<span class="p">)</span></code></pre></div>
<p>Second, an interface for a REST resource providing the routes defined in the API specification:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="k">package</span> <span class="nn">de.semipol.adapters.rest;</span>

<span class="k">import</span> <span class="nn">de.semipol.adapters.rest.Error</span>
<span class="k">import</span> <span class="nn">de.semipol.adapters.rest.Pet</span>
<span class="k">import</span> <span class="nn">jakarta.ws.rs.*</span>
<span class="k">import</span> <span class="nn">jakarta.ws.rs.core.Response</span>
<span class="k">import</span> <span class="nn">java.io.InputStream</span>

<span class="nd">@Path</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">)</span>
<span class="err">@</span><span class="n">jakarta</span><span class="p">.</span><span class="k">annotation</span><span class="p">.</span><span class="nc">Generated</span><span class="p">(</span><span class="n">value</span> <span class="p">=</span> <span class="nf">arrayOf</span><span class="p">(</span><span class="s">&#34;org.openapitools.codegen.languages.KotlinServerCodegen&#34;</span><span class="p">),</span> <span class="n">comments</span> <span class="p">=</span> <span class="s">&#34;Generator version: 7.7.0&#34;</span><span class="p">)</span>
<span class="kd">interface</span> <span class="nc">PetsApi</span> <span class="p">{</span>

    <span class="nd">@POST</span>
    <span class="nd">@Path</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
    <span class="nd">@Consumes</span><span class="p">(</span><span class="s">&#34;application/json&#34;</span><span class="p">)</span>
    <span class="nd">@Produces</span><span class="p">(</span><span class="s">&#34;application/json&#34;</span><span class="p">)</span>
    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">createPets</span><span class="p">(</span> <span class="n">pet</span><span class="p">:</span> <span class="nc">Pet</span><span class="p">):</span> <span class="nc">Response</span>

    <span class="nd">@GET</span>
    <span class="nd">@Path</span><span class="p">(</span><span class="s">&#34;/pets&#34;</span><span class="p">)</span>
    <span class="nd">@Produces</span><span class="p">(</span><span class="s">&#34;application/json&#34;</span><span class="p">)</span>
    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">listPets</span><span class="p">(</span><span class="nd">@QueryParam</span><span class="p">(</span><span class="s">&#34;limit&#34;</span><span class="p">)</span>   <span class="n">limit</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">Int</span><span class="p">?):</span> <span class="nc">Response</span>

    <span class="nd">@GET</span>
    <span class="nd">@Path</span><span class="p">(</span><span class="s">&#34;/pets/{petId}&#34;</span><span class="p">)</span>
    <span class="nd">@Produces</span><span class="p">(</span><span class="s">&#34;application/json&#34;</span><span class="p">)</span>
    <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">showPetById</span><span class="p">(</span><span class="nd">@PathParam</span><span class="p">(</span><span class="s">&#34;petId&#34;</span><span class="p">)</span> <span class="n">petId</span><span class="p">:</span> <span class="n">kotlin</span><span class="p">.</span><span class="nc">String</span><span class="p">):</span> <span class="nc">Response</span>
<span class="p">}</span></code></pre></div>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>The generated source code shown here is formatted to fit into the blog post.</p></aside>
<p>We can now go along and implement this interface using a separate class.</p></section>
<section class="doc-section level-2"><h3 id="_implementing_a_generated_api_resource">Implementing a generated API resource</h3><p>Implementing the API boils down to creating a class that implements the generated <code>PetsApi</code> interface.
Before I can show how this looks like, we first need a dummy backend to store and request instances of <code>Pet</code> from.
Here’s a simple stub repository implementation <a href="#Fowler2003">[Fowler2003]</a> for pets that’s used in the example project:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="nd">@ApplicationScoped</span>
<span class="kd">class</span> <span class="nc">PetRepository</span> <span class="p">{</span>
    <span class="k">private</span> <span class="kd">val</span> <span class="py">pets</span> <span class="p">=</span> <span class="n">mutableListOf</span><span class="p">&lt;</span><span class="nc">Pet</span><span class="p">&gt;()</span>

    <span class="k">fun</span> <span class="nf">clear</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">pets</span><span class="p">.</span><span class="nf">clear</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">addPet</span><span class="p">(</span><span class="n">pet</span><span class="p">:</span> <span class="nc">Pet</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">pets</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">pet</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">listPets</span><span class="p">():</span> <span class="nc">List</span><span class="p">&lt;</span><span class="nc">Pet</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">pets</span>

    <span class="k">fun</span> <span class="nf">getPet</span><span class="p">(</span><span class="n">id</span><span class="p">:</span> <span class="nc">Long</span><span class="p">):</span> <span class="nc">Pet</span> <span class="p">=</span> <span class="n">pets</span><span class="p">.</span><span class="nf">first</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">id</span> <span class="p">==</span> <span class="n">id</span> <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<section class="admonition-block warning" role="doc-notice"><h6 class="block-title label-only"><span class="title-label">Warning: </span></h6><p>This repository implementation is a stub!
Many implementation aspects are ignored (e.g., duplicate IDs, persistence) and by using the generated <code>Pet</code> model class in what is usually the domain layer of the application, we couple the domain code to the presentation.
This is often not desirable but ignored for this example focussing on the presentation layer only.</p></section>
<p>With this repository in place, we can now implement the REST API:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="kd">class</span> <span class="nc">PetsApiImpl</span><span class="p">(</span><span class="k">private</span> <span class="kd">val</span> <span class="py">petRepository</span><span class="p">:</span> <span class="nc">PetRepository</span><span class="p">)</span> <span class="p">:</span> <span class="nc">PetsApi</span> <span class="p">{</span> <b class="conum">1</b>

    <span class="nd">@ServerExceptionMapper</span> <b class="conum">3</b>
    <span class="k">public</span> <span class="k">fun</span> <span class="nf">mapNoSuchElementException</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="nc">NoSuchElementException</span><span class="p">)</span> <span class="p">=</span>
        <span class="nc">Response</span>
            <span class="p">.</span><span class="nf">status</span><span class="p">(</span><span class="nc">Status</span><span class="p">.</span><span class="nc">NOT_FOUND</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">entity</span><span class="p">(</span><span class="nc">Error</span><span class="p">(</span><span class="nc">Status</span><span class="p">.</span><span class="nc">NOT_FOUND</span><span class="p">.</span><span class="n">statusCode</span><span class="p">,</span> <span class="n">e</span><span class="p">.</span><span class="n">message</span> <span class="o">?:</span> <span class="s">&#34;&#34;</span><span class="p">))</span>
            <span class="p">.</span><span class="nf">build</span><span class="p">()</span>

    <span class="k">override</span> <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">createPets</span><span class="p">(</span><span class="n">pet</span><span class="p">:</span> <span class="nc">Pet</span><span class="p">):</span> <span class="nc">Response</span> <span class="p">{</span>
        <span class="n">petRepository</span><span class="p">.</span><span class="nf">addPet</span><span class="p">(</span><span class="n">pet</span><span class="p">)</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="p">.</span><span class="nf">created</span><span class="p">(</span><span class="nc">URI</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span><span class="s">&#34;/pets/${pet.id}&#34;</span><span class="p">)).</span><span class="nf">build</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">override</span> <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">listPets</span><span class="p">(</span><span class="n">limit</span><span class="p">:</span> <span class="nc">Int</span><span class="p">?):</span> <span class="nc">Response</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="p">.</span><span class="nf">ok</span><span class="p">(</span><span class="n">petRepository</span><span class="p">.</span><span class="nf">listPets</span><span class="p">()).</span><span class="nf">header</span><span class="p">(</span><span class="s">&#34;x-next&#34;</span><span class="p">,</span> <span class="s">&#34;fake value&#34;</span><span class="p">).</span><span class="nf">build</span><span class="p">()</span> <b class="conum">2</b>
    <span class="p">}</span>

    <span class="k">override</span> <span class="k">suspend</span> <span class="k">fun</span> <span class="nf">showPetById</span><span class="p">(</span><span class="n">petId</span><span class="p">:</span> <span class="nc">Long</span><span class="p">):</span> <span class="nc">Response</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="p">.</span><span class="nf">ok</span><span class="p">(</span><span class="n">petRepository</span><span class="p">.</span><span class="nf">getPet</span><span class="p">(</span><span class="n">petId</span><span class="p">)).</span><span class="nf">build</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></div>
<div class="olist arabic"><ol class="arabic"><li>We create an implementation class for the API that implements the generated interface.</li><li>Only when returning <code>Response</code> instances, we are able to modify response header values dynamically such as needed for the exemplary pagination header.</li><li>Fulfilling the contract for error responses is usually done by mapping domain exceptions (or due to the stub implementation, general JDK exceptions) to appropriate responses using framework features.</li></ol></div>
<p>The resulting implementation is pretty concise and easy to read.
The generated interface ensures that the implementation provides the required routes with matching input parameters.
Iterating the specification is easy and free from loss of manually implemented code.
When the OpenAPI specification is modified, the manually implemented endpoints remain untouched and the compiler will spot the most severe discrepancies that need to be addressed.
For instance, if a new route is added, we cannot forget to implement it, because otherwise the interface is not implemented correctly.
This gives a lot of automated support for ensuring consistent and complete API implementations, complying with the specification.</p></section></section>
<section class="doc-section level-1"><h2 id="_summary">Summary</h2><p>With a few plugins and suitable configuration options, an API-first development workflow can easily set up for Quarkus.
The resulting projects gives a lot of developer support that prevents an implementation from drifting from the specification.
However, the initial setup shown here is not perfect and of course there are more challenges to tackle and costs to consider.</p>
<p>First, the OpenAPI generator is not perfect and some valid specifications result in awkward or unusable generated code.
For instance, <a href="https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-polymorphism/">polymorphism</a> usually results in struggles that need manual intervention.
The outcome is usually on the positive side if the specification is part of the service itself and not taken from somewhere else.
In this case, generator problems can be worked around by a mix of tweaking generator templates, making use of <a href="https://openapi-generator.tech/docs/templating/#extensions">vendor extensions</a> in the templates, and – in the worst case – by modelling the API specification in a way that works around these issues.
If the specification is immutable and not an asset of the project itself, the resulting trade-off decision might go against a use of the OpenAPI generator to avoid these corner cases.</p>
<p>Second, the setup shown here delegates the task of ensuring consistency of implementation and specification to the Kotlin compiler.
However, not all mismatches are detectable here.
For instance, the method signatures of <code>listPets</code> do not enforce the <code>x-next</code> response header.
Therefore, we need further means to gain more confidence in the match between implementation and specification.
One option is described in <a href="https://www.semipol.de/posts/2024/12/testing-openapi-specification-compliance-in-quarkus-with-prism/">the next blog post</a>.</p></section>
<section class="doc-section level-1"><h2 id="_bibliography">Bibliography</h2><div class="ulist bibliography"><ul class="bibliography"><li><a id="Vasudevan2006" aria-hidden="true"></a>[Vasudevan2006] Vasudevan, Keshav. &#34;Design First or Code First: What’s the Best Approach to API Development?&#34; Swagger.io, February 21, 2017. <a class="bare" href="https://swagger.io/blog/api-design/design-first-or-code-first-api-development/">https://swagger.io/blog/api-design/design-first-or-code-first-api-development/</a>.</li><li><a id="Bryzek2018" aria-hidden="true"></a>[Bryzek2018] Bryzek, Michael. &#34;Design Microservice Architectures the Right Way.&#34; Presented at the QCon New York, New York, NY, USA, September 10, 2018. <a class="bare" href="https://www.youtube.com/watch?v=j6ow-UemzBc">https://www.youtube.com/watch?v=j6ow-UemzBc</a>.</li><li><a id="Fowler2003" aria-hidden="true"></a>[Fowler2003] Fowler, Martin. &#34;Repository.&#34; martinfowler.com, March 5, 2003. <a class="bare" href="https://martinfowler.com/eaaCatalog/repository.html">https://martinfowler.com/eaaCatalog/repository.html</a>.</li></ul></div></section>
]]></content></entry><entry><title>Tales from the commit log</title><link rel="alternate" href="https://www.semipol.de/posts/2021/11/tales-from-the-commit-log/"/><id>https://www.semipol.de/posts/2021/11/tales-from-the-commit-log/</id><published>2021-11-05T00:00:00+00:00</published><updated>2024-12-09T14:32:28+01:00</updated><summary>A piece of software never exists in isolation and without context. The problem to solve and the reasoning and experience of its programmers shape the implementation and are important information for future developers. Even well-written code cannot convey all of this by itself. Therefore, further means of communicating such information are required. Code comments and external documentation are the obvious choices. However, with Git we also have the chance to design the commit log in a way that it deliberately tells a story about the implementation that is not visible from the code itself.
Table of contentsWhy code and change sets need to communicateRecording history vs. telling a storyProperties of good commitsCreate cohesive commitsExplain what has been done and WHYCreating a clean commit historyBibliography Why code and change sets need to communicateProgramming is a form of human communication, mostly with other humans; incidentally also with the computer by instructing it to execute a function for us. Therefore, when implementing something we carefully need to consider how to communicate what and how things are done, similar to when we talk to each other about a manual task using natural language. We need to negotiate why and how we do things to ensure that everyone understand what to do and in which way. Otherwise, misinterpretation, confusion, and conflicts are pre-programmed.
With current software development techniques such as pull/merge requests, the phrase that code is read much more often than it is written or changed is probably even more valid than it ever used to be. Reading only makes fun and delivers the required insights if the literature you are reading is well written and not a convoluted mess of illogical mysteries. Similarly, reviewing a pull request only works well if the proposed changes are presented in a way that is understandable.
Clean and self-documenting code is an important technique to ensure a reasonable reading experience. However, the code itself mostly explains what and how something is realized. The really important pieces of information usually hide behind "why" questions. Why did I use this design over the more obvious one? Why this algorithm and not the other one? Why is this special case needed to fulfill our business requirements? Why do we need to make this change at all? These are actually the important pieces of information that will likely cause confusion sooner or later if omitted. Bugs might be introduced in future refactorings if business requirements and their special cases are not known to someone reworking the code. New features might break the intended design if it wasn’t clearly presented. Finally, a pull request review is much more productive and also more pleasing for the reviewer if requirements, design choices, and motivations are known.
Code comments can answer many of these issues if done properly and much has been written about how to create useful comments (e.g. [Atwood2006], [McConnell2004] chapter 32, [Ousterhout2018]). Good and concise recommendations are:
Comments augment the code by providing information at a different level of detail. Some comments provide information at a lower, more detailed, level than the code; these comments add precision by clarifying the exact meaning of the code. Other comments provide information at a higher, more abstract, level than the code; these comments offer intuition, such as the reasoning behind the code, or a simpler and more abstract way of thinking about the code.
— [Ousterhout2018]</summary><content type="html"><![CDATA[<p>A piece of software never exists in isolation and without context.
The problem to solve and the reasoning and experience of its programmers shape the implementation and are important information for future developers.
Even well-written code cannot convey all of this by itself.
Therefore, further means of communicating such information are required.
Code comments and external documentation are the obvious choices.
However, with Git we also have the chance to design the commit log in a way that it deliberately tells a story about the implementation that is not visible from the code itself.</p>
<nav id="toc" class="toc" role="doc-toc"><h2 id="toc-title">Table of contents</h2><ol class="toc-list level-1"><li><a href="#_why_code_and_change_sets_need_to_communicate">Why code and change sets need to communicate</a></li><li><a href="#_recording_history_vs_telling_a_story">Recording history vs. telling a story</a></li><li><a href="#_properties_of_good_commits">Properties of good commits</a><ol class="toc-list level-2"><li><a href="#_create_cohesive_commits">Create cohesive commits</a></li><li><a href="#_explain_what_has_been_done_and_why">Explain what has been done and WHY</a></li></ol></li><li><a href="#_creating_a_clean_commit_history">Creating a clean commit history</a></li><li><a href="#_bibliography">Bibliography</a></li></ol></nav>
<section class="doc-section level-1"><h2 id="_why_code_and_change_sets_need_to_communicate">Why code and change sets need to communicate</h2><p>Programming is a form of human communication, mostly with other humans; incidentally also with the computer by instructing it to execute a function for us.
Therefore, when implementing something we carefully need to consider how to communicate what and how things are done, similar to when we talk to each other about a manual task using natural language.
We need to negotiate why and how we do things to ensure that everyone understand what to do and in which way.
Otherwise, misinterpretation, confusion, and conflicts are pre-programmed.</p>
<p>With current software development techniques such as pull/merge requests, the phrase that code is read much more often than it is written or changed is probably even more valid than it ever used to be.
Reading only makes fun and delivers the required insights if the literature you are reading is well written and not a convoluted mess of illogical mysteries.
Similarly, reviewing a pull request only works well if the proposed changes are presented in a way that is understandable.</p>
<p>Clean and self-documenting code is an important technique to ensure a reasonable reading experience.
However, the code itself mostly explains what and how something is realized.
The really important pieces of information usually hide behind &#34;why&#34; questions.
<em>Why did I use this design over the more obvious one?</em>
<em>Why this algorithm and not the other one?</em>
<em>Why is this special case needed to fulfill our business requirements?</em>
<em>Why do we need to make this change at all?</em>
These are actually the important pieces of information that will likely cause confusion sooner or later if omitted.
Bugs might be introduced in future refactorings if business requirements and their special cases are not known to someone reworking the code.
New features might break the intended design if it wasn’t clearly presented.
Finally, a pull request review is much more productive and also more pleasing for the reviewer if requirements, design choices, and motivations are known.</p>
<p>Code comments can answer many of these issues if done properly and much has been written about how to create useful comments (e.g. <a href="#Atwood2006">[Atwood2006]</a>, <a href="#McConnell2004">[McConnell2004]</a> chapter 32, <a href="#Ousterhout2018">[Ousterhout2018]</a>).
Good and concise recommendations are:</p>
<div class="quote-block"><blockquote><p>Comments augment the code by providing information at a different level of detail. Some comments provide information at a lower, more detailed, level than the code; these comments add precision by clarifying the exact meaning of the code. Other comments provide information at a higher, more abstract, level than the code; these comments offer intuition, such as the reasoning behind the code, or a simpler and more abstract way of thinking about the code.</p><footer>— <cite><a href="#Ousterhout2018">[Ousterhout2018]</a></cite></footer></blockquote></div>
<p>or more compact</p>
<div class="quote-block"><blockquote><p>Comments should say things about the code that the code can’t say about itself—at the summary level or the intent level.</p><footer>— <cite><a href="#McConnell2004">[McConnell2004]</a>, p. 817</cite></footer></blockquote></div>
<p>So, the essence is always that we need further forms of explaining the things that the code itself cannot tell.
While comments can well explain the current structure of the code at a certain point in time, they are actually pretty bad at explaining the evolution of a piece of software.
Having a long change list at the beginning of each source file is probably not a good idea.
What if that file vanishes or is split up at some point in time?
This is where the commit log of version control systems such as Git comes into play as an important tool for communication.</p></section>
<section class="doc-section level-1"><h2 id="_recording_history_vs_telling_a_story">Recording history vs. telling a story</h2><p>The commit log in version control systems is the primary means of documenting the evolution of a software projects.
Before Git, systems such as CVS or SVN didn’t have real options to manipulate the commit log after the fact.
Whenever a commit was formed, it was more or less set in stone.
Anything that needed to be reworked or fixed afterwards was a new commit and iteration was not possible.
Therefore, one could easily end up with a commit log that could look like the following:</p>
<div class="literal-block"><pre>Implement cool new feature, also refactor foo
Fix compilation issue introduced in previous commit
Fix typos in new code comments and fix old bug in tape ejection
Continue work
Change feature implementation from switch case to state pattern
Address review comments
TEMP will continue tomorrow
Finalize second feature</pre></div>
<p>Such a commit log <em>documents the editing history</em>.
This history definitely contains valuable information that goes beyond what the source code shows.
However, is also contains a lot of noise that hides the essential messages such as the implemented features and their design decisions.
In a pull request review such a commit log does not give the reviewer a concise picture of what has been done.
When digging out old commits for debugging or understanding, a half-baked commit with message &#34;TEMP will continue tomorrow&#34; will leave the reader puzzled at best.</p>
<p>Some parts of this commit log could have been better even when using VCSs without rebasing features.
For instance, TEMP commits could have been avoided at all and some commits could have been made more atomic and with better commit messages.
But humans still make errors and need means to correct and improve.
At least feedback from a code review could have never been incorporated into existing commits after the fact.
Therefore, even with great editing care, when rebasing isn’t available or used, the commit log will continue to be a record of editing history.
As such, it will never be an optimal tool for deliberate communication with other programmers.</p>
<p>With Git (and some more esoteric VCSs) including interactive rebasing support, we are now in the fortunate situation that commits are not immutable anymore and can be changed once new insights have been gained.
Therefore, we can now <em>use the commit log to tell a story</em> about our implementation and the reasoning behind it, similarly to how code comments can be used.
That way, the commit log becomes a tool that can be used consciously to document things the code itself cannot tell.
By being a series of sequential code states, the commit log is particularly well-suited for describing the evolution of software and contained features / bug fixes.</p>
<p>Going back to the previous example, the commit log could have easily been rewritten to this more concise and descriptive version</p>
<div class="literal-block"><pre>Decouple foo by introducing the observer pattern
Fix null pointer issue when ejecting tape
Implement cool new feature
Implement second feature</pre></div>
<p>This gives a much cleaner and less cluttered view on what has actually been done.
A pull request reviewer easily gets a high-level view on what really is contained inside a pull request.
By having well-structured commits, the review of a PR with considerable size also becomes tractable because commits can be reviewed in isolation.
The commit message body of each commit is the place where important <em>why</em> questions are answered.
That way, a reviewer can understand the motivations and overarching decisions before looking at the first line of code.
Confusion and misunderstanding are less likely in this situation and feedback becomes more valuable because the context for the proposed changes is clear.
Also, from the perspective of someone digging up an old commit such a state gives more insights because each commit tells a cohesive story and can be understood in isolation.</p></section>
<section class="doc-section level-1"><h2 id="_properties_of_good_commits">Properties of good commits</h2><p>When is a commit log suitable to aid in the typical reading tasks for code?
What are the properties of good commits to achieve this?
To my mind, there are two important aspects.</p>
<section class="doc-section level-2"><h3 id="_create_cohesive_commits">Create cohesive commits</h3><p>The first important aspect is to decide what forms a good commit.
To my mind, the principles that lead to a good software architecture also apply to commits: <a href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)">cohesion</a>, <a href="https://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a>, or the <a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">single responsibility principle</a> <a href="#Martin2014">[Martin2014]</a>.
A commit is comprehensible if it does only one thing.
That one thing can easily be described in the commit message and the commit can be understood without distractions and side tracks.
Thus, each commit should be a change set with high cohesion and a single responsibility.
If multiple things need to be done, apply separation of concerns and split up the work into multiple commits, one for each concern.
This leads to more but smaller commits.
Apart from usually being more comprehensible, such commits are also nicer targets for cherry-picking or reverts with less potential for conflicts.
So, good commits and the ability to split work into small units also align with the ideas of agile software development, where many small increments are favored.
It takes some practice understanding how to separate work into distinct commits.
A good hint that work should be (have been) split is if the subject of the commit message is hard to find because the single purpose of the commit is not clear or important side tracks exist.</p></section>
<section class="doc-section level-2"><h3 id="_explain_what_has_been_done_and_why">Explain what has been done and WHY</h3><p>Apart from forming small and cohesive commits, the most important tool in each commit for communicating is the commit message.
A lot has been written about how to create good commit messages.
A good overview of different references is given in the blog post <a href="https://chris.beams.io/posts/git-commit/">How to Write a Git Commit Message</a>.
Many of the references put a lot of emphasis on the style of the message.
A cohesive and readable commit style ensures that the actual content can easily be discovered, especially when working with the Git command line.
However, what is even more important is the content of the message.
We want to use commit messages to guide a reader through the code and its evolution.
Therefore, the commit message must clearly describe <em>what</em> was done and <em>why</em>.
The <em>what</em> can often already be solved with the commit subject line, maybe a short additional paragraph.
If not, the commit is probably too big.
What should take more place is answering the <em>why</em> questions.
Try to imagine what a future reader might want to know why something was done and in exactly this way and provide these answers upfront here in the commit message.
It’s much cheaper taking a few minutes to do so than spending hours debugging because the important information is lost or impossible to find later on.
Not including answers to any <em>why</em> question is the most common issue of bad commit messages that I have observed over the years.</p></section></section>
<section class="doc-section level-1"><h2 id="_creating_a_clean_commit_history">Creating a clean commit history</h2><p>The key to achieving a commit history that can be read like a book is iteration.
When things don’t look well, you need to know the tools to improve the situation.
For Git this is interactive rebasing and amending.
Unfortunately, these tools need a bit of practice before they can be used fluently.
I recommend the respective <a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History">section on rewriting history in the git book</a> or the tutorial <a href="https://hackernoon.com/beginners-guide-to-interactive-rebasing-346a3f9c3a6d">Beginner’s Guide to Interactive Rebasing</a> as a good starting point for learning interactive rebasing.
Just as when learning test-driven development, take some time to experiment with the tools on a toy project.</p>
<p>So, whenever you propose some changes via a PR, first, take some time to review your commit history and clean it up in case something looks awkward or doesn’t explain the <em>why</em> questions before submitting the PR.
Moreover, once you receive feedback, most of the time the proposed changes belong to one of the commits you proposed.
So, instead of creating a new commit &#34;address all PR comments&#34;, which doesn’t form a cohesive unit, add the requested changes to the existing commits where possible.
Of course, some review feedback can best be addressed with a new commit, because the resulting changes form a cohesive unit.
But especially small cleanup tasks don’t deserve their own commits and the commit log can be made more concise and descriptive by fixing up the original commits.
Sometimes it even a good idea to completely rebuild the commits in the PR if larger changes become necessary.
Don’t be afraid to do this.</p>
<p>Finally, in case your feature branch gets outdated, try to rebase it on <code>main</code> instead of merging.
Linear commit histories are much easier to understand than many interleaved merge commits.
Only if rebasing becomes too complicated, resort to a merge commit instead.</p>
<p>In any case, if something goes wrong while rebasing, nothing is lost.
A messed up rebasing attempt can always be recovered with a <code>git rebase --abort</code>.</p>
<section class="admonition-block caution" role="doc-notice"><h6 class="block-title label-only"><span class="title-label">Caution: </span></h6><p>You should not change history on any permanent branch such as <code>main</code> or <code>v2.0</code>.
All things discussed here are a tool for cleaning up proposed changes.
Once they have been accepted and become part of the mainline, commits should be treated as immutable.
Recovering a local Git clone from a changed upstream history is possible, but brings a lot of trouble and user will not be happy if this happens.</p></section></section>
<section class="doc-section level-1"><h2 id="_bibliography">Bibliography</h2><div class="ulist bibliography"><ul class="bibliography"><li><a id="Atwood2006" aria-hidden="true"></a>[Atwood2006] Atwood, Jeff. “Code Tells You How, Comments Tell You Why.” Coding Horror (blog), December 18, 2006. <a class="bare" href="https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/">https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/</a>.</li><li><a id="Martin2014" aria-hidden="true"></a>[Martin2014] Martin, Robert C. Agile Software Development, Principles, Patterns, and Practices. 1st ed. Pearson New International Edition. Harlow: Pearson, 2014.</li><li><a id="McConnell2004" aria-hidden="true"></a>[McConnell2004] McConnell, Steve. Code Complete: A Practical Handbook of Software Construction. 2nd ed. Redmond, WA: Microsoft Press, 2004.</li><li><a id="Ousterhout2018" aria-hidden="true"></a>[Ousterhout2018] Ousterhout, John K. A Philosophy of Software Design. 1st ed. Palo Alto, CA: Yaknyam Press, 2018.</li></ul></div></section>
]]></content></entry><entry><title>On writing useful (unit) tests</title><link rel="alternate" href="https://www.semipol.de/posts/2021/08/on-writing-useful-unit-tests/"/><id>https://www.semipol.de/posts/2021/08/on-writing-useful-unit-tests/</id><published>2021-08-12T00:00:00+00:00</published><updated>2021-09-12T21:00:44+02:00</updated><summary>Throughout the years I have seen a lot of people struggling with writing useful and readable test cases. And I have also seen a lot of existing test code that has more resemblance with a bowl of spaghetti than it helps ensuring software quality. While some say that writing tests at all is better than not having automated tests, well-structured test code is vital to achieving most of the benefits claimed by the TDD community. As structuring tests seems to be a real problem for many, this post collects some personal advices on how to create a clean test code base that helps beyond technically checking program correctness.
Table of contentsThe benefits of well-structured testsTests are a means of communicationTests as a tool for debuggingPreconditions for good testsAbstractionDependency injectionGuidelines for writing test casesVerify one aspect per test caseUse test case names to express readable requirementsTest your business, not someone else’sClarify requirements with syntax and features, don’t dilute themWhat to test and what not to testHow to provide test doubles: stubs and mocksConclusionBibliography The benefits of well-structured testsWhy does the structure of test code actually matter? Why should one bother with achieving clean test cases if a convoluted test function in the end verifies the same aspects of the code? There are (at least) two good reasons that explain why investing work in the structure of test cases is important.
Note: This blog post focuses on techniques regarding tests that are written in a typical general-purpose programming language with tools such as xUnit-like frameworks. This usually isn’t the case only for unit tests. Also higher levels in the testing pyramid are often realized this way and the general recommendations given here are also applicable on this level. I do not specifically address tests realized using other, more declarative formalisms such as BDD-style testing. Still, some things probably apply there as well.
Tests are a means of communicationAlthough reliably verifying that code performs and continues to perform the intended function is probably the primary reason for writing automated tests, well-structured tests can serve more purposes for developers, most of them boiling down to communication. The disputable Uncle Bob Martin has coined a famous quote in this regard:
Indeed, the ratio of time spent reading versus writing is well over 10:1. We are constantly reading old code as part of the effort to write new code. …​ so making it easy to read makes it easier to write.
— [Martin2009] p. 14</summary><content type="html"><![CDATA[<p>Throughout the years I have seen a lot of people struggling with writing useful and readable test cases.
And I have also seen a lot of existing test code that has more resemblance with a bowl of spaghetti than it helps ensuring software quality.
While some say that writing tests at all is better than not having automated tests, well-structured test code is vital to achieving most of the benefits claimed by the TDD community.
As structuring tests seems to be a real problem for many, this post collects some personal advices on how to create a clean test code base that helps beyond technically checking program correctness.</p>
<nav id="toc" class="toc" role="doc-toc"><h2 id="toc-title">Table of contents</h2><ol class="toc-list level-1"><li><a href="#_the_benefits_of_well_structured_tests">The benefits of well-structured tests</a><ol class="toc-list level-2"><li><a href="#_tests_are_a_means_of_communication">Tests are a means of communication</a></li><li><a href="#_tests_as_a_tool_for_debugging">Tests as a tool for debugging</a></li></ol></li><li><a href="#_preconditions_for_good_tests">Preconditions for good tests</a><ol class="toc-list level-2"><li><a href="#_abstraction">Abstraction</a></li><li><a href="#di">Dependency injection</a></li></ol></li><li><a href="#_guidelines_for_writing_test_cases">Guidelines for writing test cases</a><ol class="toc-list level-2"><li><a href="#_verify_one_aspect_per_test_case">Verify one aspect per test case</a></li><li><a href="#_use_test_case_names_to_express_readable_requirements">Use test case names to express readable requirements</a></li><li><a href="#_test_your_business_not_someone_elses">Test your business, not someone else’s</a></li><li><a href="#_clarify_requirements_with_syntax_and_features_dont_dilute_them">Clarify requirements with syntax and features, don’t dilute them</a></li></ol></li><li><a href="#_what_to_test_and_what_not_to_test">What to test and what not to test</a></li><li><a href="#_how_to_provide_test_doubles_stubs_and_mocks">How to provide test doubles: stubs and mocks</a></li><li><a href="#_conclusion">Conclusion</a></li><li><a href="#_bibliography">Bibliography</a></li></ol></nav>
<section class="doc-section level-1"><h2 id="_the_benefits_of_well_structured_tests">The benefits of well-structured tests</h2><p>Why does the structure of test code actually matter?
Why should one bother with achieving clean test cases if a convoluted test function in the end verifies the same aspects of the code?
There are (at least) two good reasons that explain why investing work in the structure of test cases is important.</p>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>This blog post focuses on techniques regarding tests that are written in a typical general-purpose programming language with tools such as xUnit-like frameworks.
This usually isn’t the case only for unit tests.
Also higher levels in the testing pyramid are often realized this way and the general recommendations given here are also applicable on this level.
I do not specifically address tests realized using other, more declarative formalisms such as BDD-style testing.
Still, some things probably apply there as well.</p></aside>
<section class="doc-section level-2"><h3 id="_tests_are_a_means_of_communication">Tests are a means of communication</h3><p>Although reliably verifying that code performs and continues to perform the intended function is probably the primary reason for writing automated tests, well-structured tests can serve more purposes for developers, most of them boiling down to communication.
The disputable Uncle Bob Martin has coined a famous quote in this regard:</p>
<div class="quote-block"><blockquote><p>Indeed, the ratio of time spent reading versus writing is well over 10:1.
We are constantly reading old code as part of the effort to write new code.
…​
so making it easy to read makes it easier to write.</p><footer>— <cite><a href="#Martin2009">[Martin2009]</a> p. 14</cite></footer></blockquote></div>
<p>(Unit) tests play an important role in guiding a reading developer through a code base.
If written with care, they tell stories about the requirements of the system under test, its architecture, and noteworthy corner cases to consider.
The test code gives a second perspective on the system and frees readers from analyzing the actual implementation to understand its behavior and requirements.
This is only possible if the author of the test cases intended the tests to convey this meaning and to fulfill the goal of guiding others through the code.
To my understanding, communicating with test cases is one of the most important aspects about creating useful test code.
Similar to code comments, there’s always more knowledge about a system than is told by its direct implementation and tests play an important role in communicating the additional information.
Of course, as already noted by Eric Evans, any code should always do its best to tell the correct story:</p>
<div class="quote-block"><blockquote><p>The assertions in a test are rigorous, but the story told by variable names and the organization of the code is not.
Good programming style keeps this connection as direct as possible, but it is still an exercise in self-discipline.
It takes fastidiousness to write code that doesn’t just do the right thing but also says the right thing.</p><footer>— <cite><a href="#Evans2004">[Evans2004]</a> p. 40</cite></footer></blockquote></div>
<p>Efficiently communicating requirements and telling the story of the system that is not or cannot be conveyed by the production code is one of the most important aspects of tests apart from its function as an automated verification.</p></section>
<section class="doc-section level-2"><h3 id="_tests_as_a_tool_for_debugging">Tests as a tool for debugging</h3><p>Another useful benefit of well-written tests is that they can help finding the source of bugs, especially the ones introduced during refactorings or changes to existing code.
A badly written test case that fails cannot provide more information than &#34;this huge mess of code doesn’t work anymore after your changes&#34;.
However, with nicely arranged single-purpose test cases the message of a failing test case is much more granular and helps the developer by saying &#34;most things work, only this special case isn’t handled properly anymore after your refactoring.&#34;
Such a message makes it much easier to correct the introduced bug and usually avoids a lot of additional debugging work.</p></section></section>
<section class="doc-section level-1"><h2 id="_preconditions_for_good_tests">Preconditions for good tests</h2><p>Although this might sound surprising, the most important techniques for achieving well-structured tests are not directly related to the test code.
Instead, the key for being able to write good tests at all lies in the structure of the tested code.
Highly coupled code, mixing multiple concerns, is as hard to test as it is hard to comprehend or to maintain.
Therefore, applying well-known design patterns and techniques to the tested code base is the primary means for enabling good tests.
Therefore, I can very much confirm the well-known claim of the TDD community that TDD leads to a better software architecture.
However, this only works of some basics of good design are known.
While software architecture and code structure fill books and decades of discussions and a comprehensive discussion is out of scope here, I will highlight two techniques that are of severe importance for being able to test.
Surprisingly, most miscarried testing attempts I have seen in the past were the result of ignoring these basic software engineering principles: <em>abstraction</em> and <em>dependency injection</em>.</p>
<section class="doc-section level-2"><h3 id="_abstraction">Abstraction</h3><p>A key principle of software engineering is being able to reason about a specific problem by avoiding distractions from lower-level programming details.
If I implement a complex algorithm for allocating parcels to carriers, I don’t want to think about network transport errors while finding out the capacity of each carrier in the course of this algorithm.
Therefore, a common technique is to abstract from the ugly and unimportant details through a class or interface.
Introducing an appropriate abstraction for &#34;find out the carrier capacity&#34; lifts reasoning in the capacity planing algorithm to a single level of …​ abstraction and removes the lower-level networking details from the reasoning process.
By following this route, I am – in turn – able to write tests that focus on a single level of abstraction without mixing business problems with infrastructure concerns.
Moreover, I can test business (capacity planning) and infrastructure (network communication) concerns in distinct tests.
This makes the implementations and the tests easier to formulate and to understand.</p>
<p>Apart from simplifying reasoning, abstraction brings most value if technically realized using interface thinking as already described in 1995 in the classic gang of four book with their &#34;principle of reusable object-oriented design&#34;:</p>
<div class="quote-block"><blockquote><p>Program to an interface, not an implementation.</p><footer>— <cite><a href="#GammaEtAl1995">[GammaEtAl1995]</a> p. 18</cite></footer></blockquote></div>
<p>That means our abstraction for &#34;find out the carrier capacity&#34; is an interface resembling the level of reasoning required for the capacity planning algorithm and the actual realization with the ugly details of network programming will then be an implementation of this interface:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="java"><span class="c1">// The abstraction at the level of the algorithm.</span>
<span class="c1">// We are only concerned about requesting capacities for carriers.</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">CapacityRequestStrategy</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCapacity</span><span class="o">(</span><span class="nc">String</span> <span class="n">carrierId</span><span class="o">);</span>
<span class="o">}</span>

<span class="c1">// One implementation of the abstraction</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">NetworkedCapacityRequestStrategy</span> <span class="kd">implements</span> <span class="nc">CapacityRequestStrategy</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCapacity</span><span class="o">(</span><span class="nc">String</span> <span class="n">carrierId</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// all the ugly HTTP-details here</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="c1">// The algorithm implementations is free from HTTP details</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CapacityPlanner</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">CapacityRequestStrategy</span> <span class="n">requestStrategy</span> <span class="o">=</span> <span class="nc">NetworkedCapacityRequestStrategy</span><span class="o">()</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">planParcels</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">parcelsRemain</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">carrier</span> <span class="o">:</span> <span class="n">availableCarriers</span><span class="o">)</span> <span class="o">{</span>
                <span class="c1">// No networking details here!</span>
                <span class="kd">final</span> <span class="kt">int</span> <span class="n">capacity</span> <span class="o">=</span> <span class="n">requestStrategy</span><span class="o">.</span><span class="na">getCapacity</span><span class="o">(</span><span class="n">carrier</span><span class="o">);</span>
                <span class="c1">// do some magic to distribute parcels</span>
                <span class="c1">// ...</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre></div>
<p>Introducing such abstractions avoids having to deal with multiple concerns in the same unit to test and therefore also enables to formulate test cases reflecting the different concerns.
Consequently, test become easier, because concerns are separated and each test only deals with a single concern and less cases to look at.</p></section>
<section class="doc-section level-2"><h3 id="di">Dependency injection</h3><p>Given the code shown above, one might ask how to actually write a test for the capacity planning algorithm that doesn’t need mixing abstraction levels.
<code>CapacityPlanner</code> still depends on the concrete network-based <code>CapacityRequestStrategy</code> implementation.
We would have to employ fancy things like stubbing the HTTP API used to determine capacities to actually test this class, thereby again resorting to mixing abstraction levels.
Yuck…​
Fortunately, a cure for this issue is pretty easy: dependency injection.
Instead of directly instantiating the <code>NetworkedCapacityRequestStrategy</code> inside the <code>CapacityPlanner</code>, let someone else provide an appropriate instance to the planner by passing it to the planner’s constructor:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CapacityPlanner</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">CapacityRequestStrategy</span> <span class="n">requestStrategy</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">CapacityPlanner</span><span class="o">(</span><span class="n">requestStrategy</span> <span class="nc">CapacityRequestStrategy</span><span class="o">)</span> <span class="o">{</span>
      <span class="k">this</span><span class="o">.</span><span class="na">requestStrategy</span> <span class="o">=</span> <span class="n">requestStrategy</span><span class="o">;</span>
    <span class="o">}</span>


    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">planParcels</span><span class="o">()</span> <span class="o">{</span>
        <span class="c1">// ...</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre></div>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>Dependency injection does not need framework features like dependency containers and <code>@Autowired</code> annotations.
Even in its fundamental form – manual constructor injection – most of its benefits are already present.</p></aside>
<p>Enabling dependency injection on a tested unit opens up the opportunity to install a <em>test double</em> <a href="#Fowler2006">[Fowler2006]</a> inside the automated tests that never has to deal with the complexity of networking:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="java"><span class="c1">// This is a test double for the production CapacityRequestStrategy</span>
<span class="kd">class</span> <span class="nc">ConstantCapacityStrategy</span> <span class="kd">implements</span> <span class="nc">CapacityRequestStrategy</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kt">int</span> <span class="n">capacity</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">ConstantCapacityStrategy</span><span class="o">(</span><span class="kt">int</span> <span class="n">capacity</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">capacity</span> <span class="o">=</span> <span class="n">capacity</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCapacity</span><span class="o">(</span><span class="nc">String</span> <span class="n">carrierId</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">capacity</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="c1">// This test can now be written without having to think about HTTP</span>
<span class="kd">class</span> <span class="nc">CapacityPlannerTest</span> <span class="o">{</span>
    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="nf">rejectsParcelsIfNoCapacityRemains</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">planner</span> <span class="o">=</span> <span class="nc">CapacityPlanner</span><span class="o">(</span><span class="nc">ConstantCapacityStrategy</span><span class="o">(</span><span class="mi">0</span><span class="o">));</span>

        <span class="n">assertThrows</span><span class="o">(</span>
            <span class="nc">NoMoreCapacityException</span><span class="o">.</span><span class="na">class</span><span class="o">,</span>
            <span class="o">()</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="n">planner</span><span class="o">.</span><span class="na">planParcels</span><span class="o">()</span> <span class="o">}</span>
        <span class="o">)</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre></div>
<p>Installing test doubles is a real pain without dependency injection, because mocking would be necessary, which is pretty error-prone and usually depends on low-level programming language constructs, thereby bloating test cases with technical details.
Moreover, without an appropriate abstraction, the installed test double would again leak details into the algorithm discussions.
If an <code>HttpClient</code> were injected instead of an abstraction, I could still install a double, but providing the appropriate behavior in the double would violate the abstraction level suitable for the test and the implementation by resorting to networking again.</p>
<aside class="sidebar"><h6 class="block-title">Dependency injection and separation of concerns</h6><p>Dependency injection is a form of <em>separation of concerns</em>.
It separates the concern of knowing how to use something from the concern of knowing how to select and create that thing to use.</p></aside>
<p>Now that the preconditions for being able to write useful tests are met, I can outline my recommendations on how to write the tests themselves.</p>
<aside class="admonition-block tip" role="doc-tip"><h6 class="block-title label-only"><span class="title-label">Tip: </span></h6><p>For a much more detailed discussion on how abstraction and dependency injection foster testability refer to the excellent <a href="#PercivalGregory2020">[PercivalGregory2020]</a>, chapter 3.
The online version of this book can be read freely at <a class="bare" href="https://www.cosmicpython.com">https://www.cosmicpython.com</a>.</p></aside></section></section>
<section class="doc-section level-1"><h2 id="_guidelines_for_writing_test_cases">Guidelines for writing test cases</h2><p>Apart from the fact that writing good tests is much easier if the code is structured well, the following sections describe a few guidelines that I would recommend following when actually writing the test cases.</p>
<section class="doc-section level-2"><h3 id="_verify_one_aspect_per_test_case">Verify one aspect per test case</h3><p>Often, one can find test cases that look like this:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="c1"># floating point equality should be handled properly in real code
</span><span class="k">def</span> <span class="nf">test_it_works</span><span class="p">():</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">1.0</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">2.0</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">0.5</span>
    <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
        <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span></code></pre></div>
<p>This test fails as a debugging aid, because the only feedback I get when something is broken is that…​ something is broken.
The feedback on the level of failing test cases isn’t more specific, because there’s only on test case that either fails or succeeds as a whole.
Wouldn’t it be much better if there was direct feedback from test execution that everything works apart from handling division by zero?</p>
<p>To avoid this trap it is much better to write one test case (function) per tested condition.
A much better version with the same assertions could look like:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">test_same_numerator_and_denominator_is_one</span><span class="p">():</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">1.0</span>

<span class="k">def</span> <span class="nf">test_numerator_higher_than_denominator_is_above_one</span><span class="p">():</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">2.0</span>

<span class="k">def</span> <span class="nf">test_numerator_lower_than_denominator_is_below_one</span><span class="p">():</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">)</span> <span class="o">==</span> <span class="mf">0.5</span>

<span class="k">def</span> <span class="nf">test_division_by_zero_is_rejected</span><span class="p">():</span>
    <span class="k">with</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
        <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span></code></pre></div>
<p>Now, in case my implementation of <code>divide</code> does the math correctly but I just messed up with the exception handling, test results will immediately tell this picture and I know where to start debugging:</p>
<div class="listing-block"><pre class="rouge highlight"><code>test.py::test_same_numerator_and_denominator_is_one PASSED             [ 25%]
test.py::test_numerator_higher_than_denominator_is_above_one PASSED    [ 50%]
test.py::test_numerator_lower_than_denominator_is_below_one PASSED     [ 75%]
test.py::test_division_by_zero_is_rejected FAILED                      [100%]</code></pre></div>
<p>Besides providing valuable debugging aids, building test cases per tested aspect also helps communicating requirements on the tested code effectively.
I can now use the test case names to communicate what I require from my code to fulfill its technical, and more importantly, business value.
Without such test cases, these requirements are often only implicitly represented in the code base.
The test code therefore provides additional documentation and explanations that would otherwise be missing, but it cannot become outdated such as comments or external documentation could.</p>
<aside class="sidebar"><h6 class="block-title">One assertion per test case</h6><p>Sometimes one reads the rule to use only one assert statement per test case.
This is probably meant as a similar guideline.
However, for my liking this rule is too narrow and too technical.
Sometimes, asserting a single requirement really needs multiple closely related comparisons.
As long as the resulting assertions form a cohesive logical block, I am fine with having them inside the same test case.
Of course, encapsulating the set of assertions in a utility method might be good approach to fulfill this rule again with the benefit of providing a descriptive name.</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">assert_is_person</span><span class="p">(</span><span class="n">candidate</span><span class="p">,</span> <span class="n">expected</span><span class="p">):</span>
    <span class="k">assert</span> <span class="n">candidate</span><span class="p">.</span><span class="n">forename</span> <span class="o">==</span> <span class="n">expected</span><span class="p">.</span><span class="n">forename</span>
    <span class="k">assert</span> <span class="n">candidate</span><span class="p">.</span><span class="n">surname</span> <span class="o">==</span> <span class="n">expected</span><span class="p">.</span><span class="n">surname</span></code></pre></div></aside>
<p>So, in case some of the following conditions match a test function or method, the test case should probably be split:</p>
<div class="ulist"><ul><li>Many assertions on different properties exist.</li><li>It’s hard to describe what is tested in a short sentence.</li><li>Assertions are validated conditionally (<code>if foo: assert …​</code>).
This is a telltale sign that multiple requirements are tested in a single test case.</li></ul></div></section>
<section class="doc-section level-2"><h3 id="_use_test_case_names_to_express_readable_requirements">Use test case names to express readable requirements</h3><p>As a follow up on the previous rule of using test cases to verify individual requirements, another important aspect for the effective communication of requirements is that they are actually readable as natural language from the code.
Humans are much better at understanding natural language than they are at reading highly abbreviated code.</p>
<p>Imagine the division by zero example from above were tested like this:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">test_exception</span><span class="p">():</span>
    <span class="k">with</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
        <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span></code></pre></div>
<p>If this test fails, would you know which requirement is currently unmet in case test reports show the following?</p>
<div class="listing-block"><pre class="rouge highlight"><code>test.py::test_exception FAILED                      [100%]</code></pre></div>
<p>Probably not.</p>
<p>Therefore, use test case names to effectively communicate the imposed requirement on the system under test with natural language.
A good test case name includes a verb and can be read as a sentence clearly expressing the verified requirement such as in:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">test_division_by_zero_is_rejected</span><span class="p">():</span>
    <span class="c1"># ...</span></code></pre></div>
<p>Some languages such as Kotlin allow making this even more readable by supporting (close to) arbitrary characters in method names:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="kotlin"><span class="nd">@Test</span>
<span class="k">fun</span> <span class="nf">`division</span> <span class="k">by</span> <span class="n">zero</span> <span class="k">is</span> <span class="nf">rejected`</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// ...</span>
<span class="p">}</span></code></pre></div>
<p>Especially when testing the actual business logic of a system, such a way of naming is of real value, because then business experts or the product owner can understand whether the developers have realized the correct requirements by browsing through the test case names (guided by the developers).
In case a requirement was forgotten during implementation, this should become clear to business experts, because they can spot the gap in the natural language specification of what is tested.
Therefore, by merely naming test cases correctly, a larger steps towards acceptance testing with value for non-technical stakeholders can be taken.
Of course, also the next developer of a system or the future self will value expressive test cases that explain the system and its requirements clearly.</p></section>
<section class="doc-section level-2"><h3 id="_test_your_business_not_someone_elses">Test your business, not someone else’s</h3><p>From time to time I’ve stumbled across a pretty interesting testing pattern.
Instead of verifying the own requirements, tests were written against framework and language features.
For instance, one case in Python looked close to this one:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">my_function</span><span class="p">(</span><span class="n">a_param</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nf">isinstance</span><span class="p">(</span><span class="n">a_param</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">&#34;</span><span class="s">unsupported type</span><span class="sh">&#34;</span><span class="p">)</span>
    <span class="k">return</span> <span class="mi">42</span>

<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span>
    <span class="sh">&#34;</span><span class="s">param_value</span><span class="sh">&#34;</span><span class="p">,</span>
    <span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="n">re</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="sa">r</span><span class="sh">&#39;</span><span class="s">.*</span><span class="sh">&#39;</span><span class="p">),</span> <span class="p">...]</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">test_my_function_rejects_other_types</span><span class="p">(</span><span class="n">param_value</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
    <span class="k">with</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
        <span class="nf">my_function</span><span class="p">(</span><span class="n">param_value</span><span class="p">)</span></code></pre></div>
<p>The affected project had decided to use <a href="https://www.python.org/dev/peps/pep-0484/">Python type hints</a> and <a href="https://mypy.readthedocs.io/">mypy</a> was used strictly.
Therefore, all tooling was set up to write Python close to what a statically typed language would look and feel like.
Yet, the test authors somehow repeated a lot of what the tooling was already enforcing using unit tests.
Apart from the question where to stop in this specific case (there are indefinitely more types to test here), this approach largely increases the amount of test code to maintain and test runtime increases while creating close to no benefits.
You should generally trust the tools you select to an appropriate level or you probably shouldn’t use them.
Doing someone else’s work by verifying their implementation shifts a large burden on your own code base that will eventually result in more maintenance work without ever ensuring that your code actually continues to meet its own requirements.</p>
<p>One can say that the previous example at least exercises your own code and verifies that a single conditional works as expected.
Even worse are situations like the following one.</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">class</span> <span class="nc">TestMyNetworkedServiceAdapter</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">test_requests_works</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">with</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ConnectionError</span><span class="p">):</span>
            <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">&#34;</span><span class="s">http://unknown-host</span><span class="sh">&#34;</span><span class="p">)</span></code></pre></div>
<p>Such experiments – most likely used to understand the functioning of an upstream library – remain in the test code surprisingly often.
This is really nothing more than code bloat and doesn’t help at all for your own project.
So just avoid this.</p>
<p>Of course, there are times when some bug or peculiarity of a used library is causing trouble for your code.
But you have probably noticed this because of some missed requirement for your own code.
Therefore, whenever possible, try to find a test case that reproduces issues with used tools through special cases of calling your own code.
That way these special case tests contribute to the set of requirements imposed by your tests on the system under test and they remain valid even if you later decide to completely drop the buggy dependency.
Not having to change test code alongside production code changes is always a good thing and reduces necessary work during refactorings.</p></section>
<section class="doc-section level-2"><h3 id="_clarify_requirements_with_syntax_and_features_dont_dilute_them">Clarify requirements with syntax and features, don’t dilute them</h3><p>Some test framework provide versatile features for writing tests in concise ways.
Especially <a href="https://docs.pytest.org">pytest</a> has accumulated an enormous ecosystem of plugins for solving various (repetitive) tasks through syntactic sugar.
The general recommendation with fancy tooling is to use it as a means of improving the documentation quality of test code and not for the sake of applying all plugins that are available.
For example, despite using the common feature of parametrizing test cases for reducing the amount of test code, the following test function still weakens the documentation capabilities of the test:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="nd">@pytest.mark.parametrize</span><span class="p">(</span>
    <span class="p">[</span><span class="sh">&#34;</span><span class="s">numerator</span><span class="sh">&#34;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">denominator</span><span class="sh">&#34;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">expected_value</span><span class="sh">&#34;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">expect_exception</span><span class="sh">&#34;</span><span class="p">],</span>
    <span class="p">[</span>
        <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
        <span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
        <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
        <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
    <span class="p">]</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">test_divide</span><span class="p">(</span><span class="n">numerator</span><span class="p">,</span> <span class="n">denominator</span><span class="p">,</span> <span class="n">expected_value</span><span class="p">,</span> <span class="n">expect_exception</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">expect_exception</span><span class="p">:</span>
        <span class="n">pytest</span><span class="p">.</span><span class="nf">raises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
            <span class="nf">divide</span><span class="p">(</span><span class="n">numerator</span><span class="p">,</span> <span class="n">denominator</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="n">numerator</span><span class="p">,</span> <span class="n">denominator</span><span class="p">)</span> <span class="o">==</span> <span class="n">expected_value</span></code></pre></div>
<p>While maintaining less code is always something valuable to consider, less code but with higher complexity and lower self-documentation abilities is probably not worth achieving.
This version of the tests is still better than the initial <code>test_it_works</code> version, because the test runner reports success and failure for parameter combinations individually and debugging is easier, but the requirements are diluted.
Therefore, use such fancy feature for the purpose if making the requirement descriptions stronger, not weaker.</p>
<p>A good example where parametrization is beneficial is to increase coverage within a single requirement:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="nd">@pytest.mark.parametrize</span><span class="p">(</span>
    <span class="p">[</span><span class="sh">&#34;</span><span class="s">numerator</span><span class="sh">&#34;</span><span class="p">,</span> <span class="sh">&#34;</span><span class="s">denominator</span><span class="sh">&#34;</span><span class="p">],</span>
    <span class="p">[</span>
        <span class="n">pytest</span><span class="p">.</span><span class="nf">param</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="sh">&#34;</span><span class="s">basic case</span><span class="sh">&#34;</span><span class="p">),</span>
        <span class="n">pytest</span><span class="p">.</span><span class="nf">param</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="sh">&#34;</span><span class="s">ne 1.0 works</span><span class="sh">&#34;</span><span class="p">),</span>
        <span class="n">pytest</span><span class="p">.</span><span class="nf">param</span><span class="p">(</span><span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="sh">&#34;</span><span class="s">both values negative</span><span class="sh">&#34;</span><span class="p">),</span>
        <span class="n">pytest</span><span class="p">.</span><span class="nf">param</span><span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">1.5</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="sh">&#34;</span><span class="s">fractional</span><span class="sh">&#34;</span><span class="p">),</span>
    <span class="p">]</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">test_same_numerator_and_denominator_is_one</span><span class="p">(</span><span class="n">numerator</span><span class="p">,</span> <span class="n">denominator</span><span class="p">):</span>
    <span class="k">assert</span> <span class="nf">divide</span><span class="p">(</span><span class="n">numerator</span><span class="p">,</span> <span class="n">denominator</span><span class="p">)</span> <span class="o">==</span> <span class="mf">1.0</span></code></pre></div>
<p>By using named parameters we can even increase the ability of the test cases to explain their exact requirements.</p></section></section>
<section class="doc-section level-1"><h2 id="_what_to_test_and_what_not_to_test">What to test and what not to test</h2><p>While the aforementioned guidelines mostly focussed on the design of individual test cases, there is also the question which tests to write and what will be the target of these tests.
Tests are an extremely valuable tool greatly helping in the development process.
Not writing tests is rarely a good option for close to any software project.
Yet, test code is as important as the actual production code and therefore any test that is written adds to the size of the code base and increases maintenance efforts.
Fortunately, implementing software is a creative process with a lot of freedom and whenever we want to realize a new requirement or fix a bug, we have the freedom to decide where and how to test it to weigh the benefits of tests with the drawbacks of adding more code.
In this regard, <a href="#PercivalGregory2020">[PercivalGregory2020]</a> provides an interesting perspective on this problem:</p>
<div class="quote-block"><blockquote><p>Every line of code that we put in a test is like a blob of glue, holding the system in a particular shape.
The more low-level tests we have, the harder it will be to change things.</p><footer>— <cite><a href="#PercivalGregory2020">[PercivalGregory2020]</a>, p. 73</cite></footer></blockquote></div>
<p>Based on this idea they propose to favor higher-level unit tests when possible, and to drop down to testing individual units for specific problems.
They also call this &#34;testing in high and low gear&#34;.
In the end, the test code will be a larger collection of loosely coupled tests using higher-level abstractions such as DDD application services, enhanced with a set of individual unit tests for covering and gaining confidence in complex or tricky cases.
The low-level tests are highly coupled to the implementation code and therefore prone to changes alongside refactorings, but they will be relatively few.
On the other end, the higher-level tests are also more likely to contribute to the aforementioned aspect of documenting business requirements (<a href="#PercivalGregory2020">[PercivalGregory2020]</a>, p. 74).
The proper functioning of a getter method is close to irrelevant to the business perspective, but whether I can pay in money and then request the final amount (indirectly through that getter) is a lot more relevant.</p>
<p>This perspective has a close relationship to the distinction between <em>solitary</em> and <em>sociable</em> unit tests <a href="#Fowler2014">[Fowler2014]</a>.
Testing on the higher level, including (parts of) the object graph below the high-level entrypoint, will result in a sociable unit test.
The tested unit will include (most) parts of its production object graph and socially interacts with these real objects instead of being in solitude created via test doubles.
Testing on high gear therefore prefers sociable unit tests.</p>
<p>How would it look like to test on the high level?
Here’s a simplified example code base:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">class</span> <span class="nc">Currency</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">euros</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">cents</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="c1"># assign members
</span>
    <span class="k">def</span> <span class="nf">subtract</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">Currency</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Currency</span><span class="p">:</span>
        <span class="c1"># some actual implementations goes here
</span>
<span class="k">class</span> <span class="nc">BankAccount</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">balance</span><span class="p">:</span> <span class="n">Currency</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">self</span><span class="p">.</span><span class="n">balance</span> <span class="o">=</span> <span class="n">balance</span>

    <span class="k">def</span> <span class="nf">pay_out</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">desired</span><span class="p">:</span> <span class="n">Currency</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">new_balance</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">balance</span><span class="p">.</span><span class="nf">subtract</span><span class="p">(</span><span class="n">desired</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">new_balance</span><span class="p">.</span><span class="nf">is_negative</span><span class="p">():</span>
            <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">()</span>
        <span class="n">self</span><span class="p">.</span><span class="n">balance</span> <span class="o">=</span> <span class="n">new_balance</span></code></pre></div>
<p>Testing in low gear would mean:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">class</span> <span class="nc">TestCurrency</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">test_subtract_works</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">assert</span> <span class="nc">Currency</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="nf">subtract</span><span class="p">(</span><span class="nc">Currency</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">50</span><span class="p">))</span> <span class="o">==</span> <span class="nc">Currency</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span></code></pre></div>
<p>Using an explicit <code>subtract</code> method is cumbersome.
Python provides operators and I could easily implement addition and subtraction operators for the <code>Currency</code> class.
But my test for <code>Currency</code> is highly coupled to the specifics of how this class is implemented and would need changes to reflect the new operators along this refactoring, thereby adding work to the refactoring task.</p>
<p>The high gear approach instead would look like this:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">class</span> <span class="nc">TestBankAccount</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">test_paying_out_works_if_balance_is_high_enough</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">account</span> <span class="o">=</span> <span class="nc">BankAccount</span><span class="p">(</span><span class="nc">Currency</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

        <span class="n">account</span><span class="p">.</span><span class="nf">pay_out</span><span class="p">(</span><span class="nc">Currency</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">50</span><span class="p">))</span>

        <span class="k">assert</span> <span class="n">account</span><span class="p">.</span><span class="n">balance</span> <span class="o">==</span> <span class="nc">Currency</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span></code></pre></div>
<p>In high gear I have simply left out the detailed test for the <code>Currency</code> class, assuming that its proper functionality can be assured when my higher-level tests succeed.
Code coverage is a good hint to find out if high-level tests cover my lower-level units sufficiently or not.
This high-gear test is not coupled to the exact set of methods available on the <code>Currency</code> class.
Refactoring <code>subtract</code> to an operator would be invisible to this test and it could simply remain as is, causing less work during the refactoring.</p>
<p>The downside of this approach is that when something fails, I lose the exact feedback where the failure comes from.
Fortunately, testing as performed by developers is not a form of black-box testing.
I can try to judge from the underlying code structure and complexity if detailed feedback will be required or not.
If things are complex, add some low-gear tests to get targeted requirements and debugging feedback.
If the internal structure of a higher-level unit is quite simple and high-level testing does not hinder development and debugging much, then avoid adding low-level tests that do not add much benefit.</p>
<p>An important note on this procedure is that this mainly applies to testing the business logic of your code base.
Even in high-gear sociable unit tests you should provide test doubles for persistence and IO.
Otherwise, runtimes of your unit tests will start to increase and the benefit of instant feedback will be lost.
Moreover, especially network protocols can have many interesting error conditions that are hard to test from a high-level business perspective.
For these things your are better off isolating them in solitary <em>narrow integration tests</em> <a href="#Fowler2018">[Fowler2018]</a>.
Here, you can easily construct all kinds of intricate failure situations, which is often necessary to ensure the proper functioning of such adapters to external systems.</p>
<aside class="admonition-block tip" role="doc-tip"><h6 class="block-title label-only"><span class="title-label">Tip: </span></h6><p><a href="#Richardson2018">[Richardson2018]</a>, chapter 9 nicely outlines how separating the different test types results in a healthy test pyramid in the context of microservices.</p></aside></section>
<section class="doc-section level-1"><h2 id="_how_to_provide_test_doubles_stubs_and_mocks">How to provide test doubles: stubs and mocks</h2><p><a href="#di">Dependency injection</a> enables us to effectively swap out production collaborators for a tested unit with an implementation tailored to the specific test.
These replacements are called <em>test doubles</em> <a href="#Fowler2006">[Fowler2006]</a> and different techniques exist for creating such doubles.
The most prominent ones are <em>stubs</em> and <em>mocks</em>.
The term stub is used with slightly varying meanings in different place.
The common use of the word <em>stub</em> doesn’t distinguish clearly between <em>stubs</em> and <em>fakes</em> as defined in <a href="#Fowler2006">[Fowler2006]</a>.
Any kind of implementation, either providing canned answers to expected calls, or providing a minimalistic implementation of the full protocol, is often blurred under the name <em>stub</em>.</p>
<p>On the other end of the spectrum are <em>mocks</em>.
These test doubles are usually created through special mocking libraries in a declarative way by expressing the expected calls and potential answers to them.
The second aspects lets mocks also act as stubs.
However, as already outlined in <a href="#Fowler2007">[Fowler2007]</a>, there’s still an important difference: due to the fact that exact call sequences are used to define their behavior, mocks are coupled stronger to the exact way the tested unit interacts with the test double than <em>fakes</em> would be.
Mocks primarily verify if the protocol spoken between the tested unit and the mock works as expected.
When using stubs, the exact call sequences are of lower importance, because only the outcome is verified, not the steps towards this outcome.
Therefore, stubs allow greater freedom for refactoring without having to change the test code, whereas mocks usually exhibit more coupling with the production code (<a href="#PercivalGregory2020">[PercivalGregory2020]</a>, p. 51).
Moreover, stubs (fakes) are often easier to comprehend.
I can give meaningful names to my stubs and their implementations is usual and simple code that’s easy to read.
On the other end, the mock declarations (when using typical mocking frameworks) are often harder to read:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="n">mock</span> <span class="o">=</span> <span class="nc">MagicMock</span><span class="p">(</span><span class="n">autospec</span><span class="o">=</span><span class="n">SomeStrategy</span><span class="p">)</span>
<span class="n">mock</span><span class="p">.</span><span class="n">get_name</span><span class="p">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="sh">&#34;</span><span class="s">static-error</span><span class="sh">&#34;</span>
<span class="n">mock</span><span class="p">.</span><span class="n">compute_stuff</span><span class="p">.</span><span class="n">side_effect</span> <span class="o">=</span> <span class="nc">ValueError</span><span class="p">()</span></code></pre></div>
<p>That’s ok’ish to read, but a manual stub implementation (or fake implementation, to be precise) is easier to comprehend in most cases:</p>
<div class="listing-block"><pre class="rouge highlight"><code data-lang="python"><span class="k">class</span> <span class="nc">RaisingStrategyFake</span><span class="p">(</span><span class="n">SomeStrategy</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get_name</span><span class="p">():</span>
        <span class="k">return</span> <span class="sh">&#34;</span><span class="s">static-error</span><span class="sh">&#34;</span>

    <span class="k">def</span> <span class="nf">compute_stuff</span><span class="p">():</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">()</span></code></pre></div>
<p>5 instead of 3 code lines.
An acceptable price given the gained clarity.</p>
<p>Another problem with mocks is that the declarations of desired functionality and expected calls are usually repeated (with slight variations depending on the actual test case) throughout the test code.
Refactorings therefore often result in huge change sets in the test code, because mocking code has to be adapted close to everywhere.</p>
<p>So what is the recommendation here?
First, if your code base is testable and uses correct abstractions with dependency injection, then using stubs is an easy task.
This avoids one of the primary reasons for using mocks in dynamic languages such as Python, where mocks and monkey patching are used to overcome such design deficiencies.
Therefore, my general recommendation – in line with <a href="#PercivalGregory2020">[PercivalGregory2020]</a> – is to use stubs whenever possible and when correct abstractions exist.
If these abstractions are lacking, it might be time to add them.</p>
<p>However, also mock-style testing has its role.
Especially on the boundaries of a system, where interactions with third-party libraries or systems exist (i.e. ports and adapters), using mocks as a means of exercising and triggering specific boundary conditions is easier.
Moreover, for protocol adapters, expecting certain calls is a typical way of thinking and an essential aspect of verifying that the protocol is obeyed by the implementation.
Such a requirement naturally maps to the mock-style behavior verification (&#34;When a new product is POSTed, the <code>createProduct</code> method on my <code>ProductManagementService</code> must be called.&#34;, &#34;When requesting an HTTP resource, first open a channel, second, initiate TLS, …​&#34;).
Therefore, using mocks with their focus on the spoken protocol is always a good idea when the actual interaction protocol is what matters.
This pretty much leads to the testing strategy outlined in <a href="#Richardson2018">[Richardson2018]</a>, p. 309.</p>
<aside class="sidebar"><h6 class="block-title">How to test DDD application services</h6><p><a href="#Richardson2018">[Richardson2018]</a> and <a href="#PercivalGregory2020">[PercivalGregory2020]</a> disagree on how to test DDD-like application services.
<a href="#PercivalGregory2020">[PercivalGregory2020]</a> understand them as being part of the business logic, providing the entrypoints at a layer of abstraction that is suitable for acceptance testing.
With dependency injection allowing to replace actual infrastructure dependencies easily, they prefer to drive high-gear sociable tests using these services.
Hence, mocking and solitary tests wouldn’t be used here.
On the other end, <a href="#Richardson2018">[Richardson2018]</a> understand these services as a glue layer between the actual application with its technical integrations and the business code.
Being some kind of thin adapter, <a href="#Richardson2018">[Richardson2018]</a> prefers using solitary tests with mocks to focus on the interaction of application services with the actual business code.</p>
<p>As far as I can tell, the different views here largely stem from the underlying technology that is used.
<a href="#PercivalGregory2020">[PercivalGregory2020]</a> operate in Python, where no universally accepted application framework such as Spring Boot exists, that implies a certain structure on the implementation.
Their implementation is structured completely according to their design ideas and consequently application services are free from infrastructure concerns (that are not hidden behind suitable abstractions).
In the Java world described in <a href="#Richardson2018">[Richardson2018]</a>, the probably over-used annotation system with things like <code>@Transactional</code> leads to some infrastructure concerns leaking further into application services.
Moreover, some of the mechanisms of frameworks such as Spring Boot reduce work in typical implementations at the price of some further leaky abstractions (for instance, JPA-annotations on entities).
Therefore, application services in Java tend to be closer to the supporting infrastructure of an application and viewing them as adapters is an understandable perspective.</p></aside></section>
<section class="doc-section level-1"><h2 id="_conclusion">Conclusion</h2><p>Hopefully, the explanations in this post have at least shown that it is important to think about how to write good test cases.
Well-structured test cases provide many benefits and once the mechanics needed to achieve them have become part of your coding muscle memory, the initial overhead of writing clean test code becomes negligible.
Ultimately, clean test code is something many people including yourself will value sooner or later and should never be neglected.</p></section>
<section class="doc-section level-1"><h2 id="_bibliography">Bibliography</h2><div class="ulist bibliography"><ul class="bibliography"><li><a id="Evans2004" aria-hidden="true"></a>[Evans2004] Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley, 2004.</li><li><a id="Fowler2006" aria-hidden="true"></a>[Fowler2006] Fowler, Martin. “TestDouble.” martinfowler.com, January 17, 2006. <a class="bare" href="https://martinfowler.com/bliki/TestDouble.html">https://martinfowler.com/bliki/TestDouble.html</a>.</li><li><a id="Fowler2007" aria-hidden="true"></a>[Fowler2007] Fowler, Martin. “Mocks Aren’t Stubs.” martinfowler.com, January 2, 2007. <a class="bare" href="https://martinfowler.com/articles/mocksArentStubs.html">https://martinfowler.com/articles/mocksArentStubs.html</a>.</li><li><a id="Fowler2014" aria-hidden="true"></a>[Fowler2014] Fowler, Martin. “UnitTest.” martinfowler.com, May 05, 2014. <a class="bare" href="https://martinfowler.com/bliki/UnitTest.html">https://martinfowler.com/bliki/UnitTest.html</a>.</li><li><a id="Fowler2018" aria-hidden="true"></a>[Fowler2018] Fowler, Martin. “IntegrationTest.” martinfowler.com, Jan. 16, 2018. <a class="bare" href="https://martinfowler.com/bliki/IntegrationTest.html">https://martinfowler.com/bliki/IntegrationTest.html</a>.</li><li><a id="GammaEtAl1995" aria-hidden="true"></a>[GammaEtAl1995] Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional Computing Series. Boston, Mass.: Addison-Wesley, 1995.</li><li><a id="Martin2009" aria-hidden="true"></a>[Martin2009] Martin, Robert C. Clean Code: A Handbook of Agile Software Craftsmanship. Upper Saddle River, NJ: Prentice Hall, 2009.</li><li><a id="PercivalGregory2020" aria-hidden="true"></a>[PercivalGregory2020] Percival, Harry and Gregory, Bob. Architecture patterns with Python: enabling test-driven development, domain-driven design, and event-driven microservices. Sebastopol, CA: O’Reilly, 2020.</li><li><a id="Richardson2018" aria-hidden="true"></a>[Richardson2018] Richardson, Chris. Microservices patterns: with examples in Java. Shelter Island, New York: Manning Publications, 2019.</li></ul></div></section>
]]></content></entry><entry><title>Debugging sporadic connectivity issues of Docker containers</title><link rel="alternate" href="https://www.semipol.de/posts/2018/09/debugging-sporadic-connectivity-issues-of-docker-containers/"/><id>https://www.semipol.de/posts/2018/09/debugging-sporadic-connectivity-issues-of-docker-containers/</id><published>2018-09-18T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>At work we have started to set up new continuous integration servers. We have decided to build the whole setup based on into individual Jenkins instance managed via Docker. Moreover, most build slaves on the instances are dynamically-created Docker containers themselves. To spawn up these slaves, the Jenkins masters need write access to the Docker socket. Of course, this would be a security implication if they had access to the socket of the main Docker daemon on the host that operates all services, including the Jenkins instances themselves. Thus, we added a second daemon to the host just for the purpose of executing the volatile build slaves. However, we soon noticed that containers executed on this additional daemon frequently showed DNS resolution errors. The remainder of this post will explain the details of how we tried to track down this problem with all the ugly details being involved there.</summary><content type="html"><![CDATA[<p>At work we have started to set up new continuous integration servers.
We have decided to build the whole setup based on into individual <a href="https://jenkins.io">Jenkins</a> instance managed via <a href="https://www.docker.com">Docker</a>.
Moreover, most build slaves on the instances are dynamically-created <a href="https://www.docker.com">Docker</a> containers themselves.
To spawn up these slaves, the <a href="https://jenkins.io">Jenkins</a> masters need write access to the <a href="https://www.docker.com">Docker</a> socket.
Of course, this would be a security implication if they had access to the socket of the main <a href="https://www.docker.com">Docker</a> daemon on the host that operates all services, including the <a href="https://jenkins.io">Jenkins</a> instances themselves.
Thus, we added a second daemon to the host just for the purpose of executing the volatile build slaves.
However, we soon noticed that containers executed on this additional daemon frequently showed DNS resolution errors.
The remainder of this post will explain the details of how we tried to track down this problem with all the ugly details being involved there.</p>
<h2 id="docker-setup">Docker setup</h2>
<p>I will first start to explain the details of the setup that we use, which is necessary to understand some parts of the bug hunt.
The server I am talking about is using Debian testing as its host system with <a href="https://www.docker.com">Docker</a> being installed using the provided Debian packages.
This daemon uses the automatically created <code>docker0</code> bridge (plus some additional networks).
For launching a completely disparate daemon to be used for <a href="https://jenkins.io">Jenkins</a> slaves, a different bridge network is required.
Unfortunately, <a href="https://www.docker.com">Docker</a> itself <a href="https://docs.docker.com/engine/reference/commandline/dockerd/">cannot configure anything else apart from <code>docker0</code></a>:</p>
<blockquote>
<p>The <code>-b</code>, <code>--bridge=</code> flag is set to <code>docker0</code> as default bridge network. It is created automatically when you install Docker. If you are not using the default, you must create and configure the bridge manually or just set it to ‘none’: <code>--bridge=none</code></p>
</blockquote>
<p>Therefore, we had to manually create a bridge device for this daemon, which we did using the Debian network infrastructure:</p>
<pre tabindex="0"><code>auto dockerbrjenkins
iface dockerbrjenkins inet static
    address 10.24.0.1
    netmask 255.255.255.0
    bridge_ports none
</code></pre><p>Therefore, apart from separating the socket and runtime directories of the two daemons, one important difference is that the main daemon creates the bridge device on its own and the daemon for CI slaves uses a pre-created bridge.</p>
<h2 id="tracing-it-down">Tracing it down</h2>
<p>What we have observed is that from time to time builds in the spawned <a href="https://www.docker.com">Docker</a> containers failed with DNS resolutions errors.
Thus, the first thing we did was to manually start a container on the same daemon in which we tried to count how often DNS resolution failed by frequently resolving the same host.
This wasn&rsquo;t very often.
Out of 450,000 requests across a range of two days only 33 or so failed.
This didn&rsquo;t match the expectation, because build failures seemed to occur more often.
However, at least we saw some errors.</p>
<p>Due to the manually created bridge network, the internal DNS server of <a href="https://www.docker.com">Docker</a> is not involved and the containers <code>/etc/resolve.conf</code> directly points to DNS servers configured on the host system.
Therefore, the first suspicion was that the configured DNS servers had sporadic problems.
Because of firewall settings, no external DNS servers could be reached for a comparison of error rates on the affected server.
However, executing the same long-running experiment directly on the host and not in a <a href="https://www.docker.com">Docker</a> container showed no resolution errors at all.
Therefore, the DNS servers could not be the reason and the problem was reduced to the affected host system.</p>
<p>One thing that was still strange with the experiment so far was the low error rate and the observation that most resolution problems in production appeared at night.
This is the time were nightly builds were running on the <a href="https://jenkins.io">Jenkins</a> instances.
Hence, I restarted the periodic DNS resolution task and triggered one of the nightly builds and it immediately became apparent that the running builds increase the chance for DNS resolutions errors.</p>
<p>In order to get <a href="https://jenkins.io">Jenkins</a> out of the issue, I tried to mimic what Jenkins does on the <a href="https://www.docker.com">Docker</a> side by starting a loop that frequently creates new containers and removes them shortly after again:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#66d9ef">while</span> true
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;next&#34;</span>
</span></span><span style="display:flex;"><span>  docker -H unix:///var/run/docker-jenkins.sock run --rm debian:latest bash -c <span style="color:#e6db74">&#34;sleep 2&#34;</span>
</span></span><span style="display:flex;"><span>  sleep <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Creating and removing containers was sufficient to increase the DNS resolution errors again.</p>
<p>This was the point in time where we had the idea to replicate this setup to the main <a href="https://www.docker.com">Docker</a> daemon.
Interestingly, the same loop that constantly adds and removes containers didn&rsquo;t affect DNS resolution on this <a href="https://www.docker.com">Docker</a> daemon.
Therefore, we somehow came to the conclusion that this must be related to the different network bridges used by the two daemons.
Of course, comparing all parameters of the bridges using <code>ip addr</code>, <code>brctl</code>, etc. didn&rsquo;t show any important differences in the parameterization of the bridges.</p>
<h2 id="looking-at-network-packages">Looking at network packages</h2>
<p>In order to find out what is actually going on, another experiment we did was to record the network communication on the system using <code>tcpdump</code>.
Looking at the wireshark visualization of the packages you can see the following:</p>
<figure>
    <img loading="lazy" src="dns-success.png"
         alt="Package transmission pattern of successful DNS requests"/> <figcaption>
            <p>Package transmission pattern of successful DNS requests</p>
        </figcaption>
</figure>

<p>So, what is visible here is that the packages are first sent from the container&rsquo;s IP (10.x) to the DNS server and something remaps them to originate from the public IP address of the host system (x.136).
These requests are then answered by the DNS servers and routed back the same way to the container.
Packages appear multiple times due to recording all interfaces of the system.</p>
<p>In case of the unsuccessful request, the pattern of packages changes:</p>
<figure>
    <img loading="lazy" src="dns-failure.png"
         alt="Package transmission pattern of failing DNS requests"/> <figcaption>
            <p>Package transmission pattern of failing DNS requests</p>
        </figcaption>
</figure>

<p>Suddenly, nothing maps the requests to originate from the public IP address of the server and the requests never get replies.
So, effectively the requests are stuck at the bridge network (10.x) and never reach the outer word.
The DNS lookup then iterates all available DNS server, but with no success.</p>
<p>Why do are packages transformed the way visible in the first image?
Because the bridge device has no configured upstream interface and <a href="https://www.docker.com">Docker</a> itself instead configures <code>iptables</code> to perform NAT and forwarding.
This somehow seems to break down in case containers are added and removed.
Therefore, another suspicion we had was that <a href="https://www.docker.com">Docker</a> reconfigures <code>iptables</code> with every container change and this results in short outages.
So, we removed this possibility.</p>
<h2 id="removing-docker-iptables-handling">Removing docker iptables handling</h2>
<p><a href="https://www.docker.com">Docker</a> can be configured to not handle <code>iptables</code> at all using <code>--iptables=false</code>.
Hence, we set it up that way and configured the required <code>iptables</code> rules by hand instead via:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>iptables -A FORWARD -o brtest -i externalinterface -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -A FORWARD -i brtest -o externalinterface -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -t nat -A POSTROUTING -j MASQUERADE -s 10.24.0.0/24 -d 0.0.0.0/0
</span></span></code></pre></div><p>However, nothing changed and DNS requests were still interrupted while containers were added and removed.</p>
<h2 id="completely-eliminating-docker-from-the-replication">Completely eliminating Docker from the replication</h2>
<p>As described before, the only real difference in terms of networking between the two daemons is how the bridge interface was created.
Since we couldn&rsquo;t find any real difference in the bridge properties, the next thing that we tried was to find out whether the issue could be reproduced with the bridge device itself and without any <a href="https://www.docker.com">Docker</a> involved.</p>
<p>So the first thing was to replace the loop spawning new temporary containers with something that replicates network devices joining the bridge and leaving it again.
This is what <a href="https://www.docker.com">Docker</a> does internally using <code>veth</code> devices.
Hence, the loop for interrupting DNS migrated to this one:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#66d9ef">while</span> true
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;next&#34;</span>
</span></span><span style="display:flex;"><span>    ip link add vethtest0 type veth peer name vethtest1
</span></span><span style="display:flex;"><span>    brctl addif brtest vethtest0
</span></span><span style="display:flex;"><span>    sleep <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    brctl delif brtest vethtest0
</span></span><span style="display:flex;"><span>    ip link del vethtest0
</span></span><span style="display:flex;"><span>    sleep <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p><code>brtest</code> is the name of bridge device the daemon is using.
This was also sufficient to reproduce the observed DNS resolution errors.</p>
<p>The next step was to also remove the <a href="https://www.docker.com">Docker</a> container in which DNS resolution is tested and to replace it with something that limits the DNS traffic to the bridge device.
Here, Linux networking namespaces come into play.
<a href="https://www.docker.com">Docker</a> uses them internally as well.
Basically, the idea is to create a virtual namespace of network devices in which only a limited set of devices is visible to processes that are executed inside the namespace.
A virtual <code>veth</code> pair can then be used to attach to the bridge on the host side and to provide a single device that only communicates via the bridge in an isolated namespace for testing DNS resolution.
This way it is ensured that resolution never directly communicates with the outside world.</p>
<p>For easy replication, we have automated the whole setup and test through the following bash script:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>set -e
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># teardown</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> cleanup <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    set +e
</span></span><span style="display:flex;"><span>    brctl delif brtest vethtest0
</span></span><span style="display:flex;"><span>    ip link del vethtest0
</span></span><span style="display:flex;"><span>    iptables -t nat -D POSTROUTING -j MASQUERADE -s 10.12.10.0/24 -d 0.0.0.0/0
</span></span><span style="display:flex;"><span>    iptables -D FORWARD -i brtest -o enp0s31f6 -j ACCEPT
</span></span><span style="display:flex;"><span>    iptables -D FORWARD -o brtest -i enp0s31f6 -j ACCEPT
</span></span><span style="display:flex;"><span>    ip link delete veth0
</span></span><span style="display:flex;"><span>    ip link set down brtest
</span></span><span style="display:flex;"><span>    brctl delbr brtest
</span></span><span style="display:flex;"><span>    ip netns del test
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>trap cleanup EXIT
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ip netns add test
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>brctl addbr brtest
</span></span><span style="display:flex;"><span>ip addr add 10.12.10.1/24 dev brtest
</span></span><span style="display:flex;"><span>ip link set up dev brtest
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ip link add veth0 type veth peer name veth1
</span></span><span style="display:flex;"><span>ip link set veth1 netns test
</span></span><span style="display:flex;"><span>brctl addif brtest veth0
</span></span><span style="display:flex;"><span>ip link set up dev veth0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ip netns exec test ip addr add 10.12.10.42/24 dev veth1
</span></span><span style="display:flex;"><span>ip netns exec test ip link set up dev veth1
</span></span><span style="display:flex;"><span>ip netns exec test ip route add default via 10.12.10.1 dev veth1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># change external interface name</span>
</span></span><span style="display:flex;"><span>iptables -A FORWARD -o brtest -i enp0s31f6 -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -A FORWARD -i brtest -o enp0s31f6 -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -t nat -A POSTROUTING -j MASQUERADE -s 10.12.10.0/24 -d 0.0.0.0/0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> true; <span style="color:#66d9ef">do</span> ip netns exec test python3 -c <span style="color:#e6db74">&#34;import socket; socket.gethostbyname(&#39;example.org&#39;)&#34;</span> <span style="color:#f92672">&amp;&amp;</span> echo success; sleep 1; <span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Even without <a href="https://www.docker.com">Docker</a> the errors still appear.
This was the point where we basically gave up and <a href="https://lists.openwall.net/netdev/2018/09/19/74">requested help on the Linux netdev mailing list</a>.</p>
<h2 id="the-solution">The solution</h2>
<p>Fortunately, Ido Schimmel soon had <a href="https://lists.openwall.net/netdev/2018/09/19/99">an answer to the request</a>:</p>
<blockquote>
<p>The MAC address of the bridge (&lsquo;brtest&rsquo; in your example) is inherited
from the bridge port with the &ldquo;smallest&rdquo; MAC address. Thus, when you
generate veth devices with random MACs and enslave them to the bridge,
you sometimes change the bridge&rsquo;s MAC address as well. And since the
bridge is the default gateway sometimes packets are sent to the wrong
MAC address.</p>
</blockquote>
<p>So the culprit here was to not assign a fixed MAC address to the manually created bridge device.
The default behavior of constructing a MAC address from the (potentially changing) attached ports is actually pretty unexpected to us and I wonder what the original motivation for this was.
However, with this information, network communication is finally stable.</p>]]></content></entry><entry><title>autosuspend 2.0: Additions for Waking Up a System</title><link rel="alternate" href="https://www.semipol.de/posts/2018/07/autosuspend-2.0-additions-for-waking-up-a-system/"/><id>https://www.semipol.de/posts/2018/07/autosuspend-2.0-additions-for-waking-up-a-system/</id><published>2018-07-29T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since a few years I am maintaining autosuspend, a small daemon that automatically suspends a Linux system in case no activity is detected. With version 2.0 I have added support for scheduled wake ups based on configurable checks for pending activities.</summary><content type="html"><![CDATA[<p>Since a few years I am maintaining <a href="https://github.com/languitar/autosuspend">autosuspend</a>, a small daemon that automatically suspends a Linux system in case no activity is detected.
With version 2.0 I have added support for scheduled wake ups based on configurable checks for pending activities.</p>
<p>So far, <code>autosuspend</code> has been pretty useful to suspend a server in case it was not in use.
However, what was missing was to wake up the system again to perform some schedule actions.
This was a long-standing user request and with version 2.0 I finally implemented this feature.
In addition to the existing configurable checks for currently ongoing activities that should prevent suspending the system, there are now additional checks for scheduled future activities.
Common examples include backups, planned TV recordings with software such as <a href="https://tvheadend.org/">Tvheadend</a>, or general times at which the system should be usable without delays.
These requested cases have now been implemented.
Thus, the <code>autosuspend</code> logic has been changed to first periodically check for current activities.
If no activity exists for a specified time and the system is going to suspend, the new checks for scheduled activities are used to determine the closest time in the future at which the system is needed again.
If this time is far enough in the future, so that it&rsquo;s worth suspending, a wake up shortly before the pending activity is scheduled (using an RTC alarm) and the system is suspended.
Otherwise, if the pending activity is close enough, the system will just wait for it while staying awake.
All timeouts are configurable, of course.</p>
<p>In addition to this new feature, many small details have been improved and new checks have been added.
The <a href="https://autosuspend.readthedocs.io/en/v2.0.1/changelog.html">changelog</a> gives an overview on the noteworthy changes.
With the addition of scheduled wake ups, <code>autosuspend</code> is probably <a href="https://github.com/languitar/autosuspend/issues/29#issuecomment-392076226">&ldquo;the most versatile solution&rdquo;</a> for suspending and waking up a system.</p>
<p>A new package for Archlinux has been pushed to <a href="https://aur.archlinux.org/packages/autosuspend/">AUR</a> and for Debian the updated package is currently going through <a href="https://buildd.debian.org/status/package.php?p=autosuspend">unstable</a>.
In case someone would be willing to contribute packages for other distributions, I&rsquo;d be glad to hear about that.
In case of issues or feature requests, please use the <a href="https://github.com/languitar/autosuspend/issues">issue tracking in the Github project</a>.</p>]]></content></entry><entry><title>LaTeX Best Practices: Lessons Learned from Writing a PhD Thesis</title><link rel="alternate" href="https://www.semipol.de/posts/2018/06/latex-best-practices-lessons-learned-from-writing-a-phd-thesis/"/><id>https://www.semipol.de/posts/2018/06/latex-best-practices-lessons-learned-from-writing-a-phd-thesis/</id><published>2018-06-12T00:00:00+00:00</published><updated>2021-05-02T16:27:56+02:00</updated><summary>A few weeks ago I submitted my PhD thesis, which I have written in LaTeX. LaTeX is probably the best and most established open-source type setting solution for academical purposes, but it is also a relic from ancient times. The syntax is a more or less a nightmare, you need to remember many small things to create typographically correct documents, the compilation process is a mess, and an enormous amount of packages for all kinds of things exists and you need to know which of the packages is currently the best alternative for your needs. For the quite sizable document that I have written, I took a reasonable amount of time to find out how to do all these things properly and this blog post will summarize my (subjective) set of best practices that I have applied for my document. This is not a complete introduction to LaTeX but rather a somewhat structured list of thing to (not) do and packages (not) to use. So you need to know at least the basics of LaTeX.</summary><content type="html"><![CDATA[<p>A few weeks ago I submitted my PhD thesis, which I have written in <a href="https://www.latex-project.org/">LaTeX</a>.
<a href="https://www.latex-project.org/">LaTeX</a> is probably the best and most established open-source type setting solution for academical purposes, but it is also a relic from ancient times.
The syntax is a more or less a nightmare, you need to remember many small things to create typographically correct documents, the compilation process is a mess, and an enormous amount of packages for all kinds of things exists and you need to know which of the packages is currently the best alternative for your needs.
For the quite sizable document that I have written, I took a reasonable amount of time to find out how to do all these things properly and this blog post will summarize my (subjective) set of best practices that I have applied for my document.
This is not a complete introduction to <a href="https://www.latex-project.org/">LaTeX</a> but rather a somewhat structured list of thing to (not) do and packages (not) to use.
So you need to know at least the basics of <a href="https://www.latex-project.org/">LaTeX</a>.</p>
<nav class="toc">
    <h2 class="toc-title">Table of Contents</h2>

    <nav id="TableOfContents">
  <ul>
    <li><a href="#building-latex-documents">Building LaTeX Documents</a></li>
    <li><a href="#generating-images-and-other-files">Generating Images and Other Files</a></li>
    <li><a href="#file-conventions">File Conventions</a>
      <ul>
        <li><a href="#properly-use-utf-8">Properly Use UTF-8</a></li>
        <li><a href="#put-each-sentence-on-a-single-line">Put Each Sentence on a Single Line</a></li>
      </ul>
    </li>
    <li><a href="#citations">Citations</a>
      <ul>
        <li><a href="#basic-configuration">Basic Configuration</a></li>
        <li><a href="#database-entries">Database Entries</a></li>
        <li><a href="#advanced-citation-commands">Advanced Citation Commands</a></li>
        <li><a href="#filtering-and-mapping-bibliographies">Filtering and Mapping Bibliographies</a></li>
      </ul>
    </li>
    <li><a href="#achieving-typographically-correct-results">Achieving Typographically Correct Results</a>
      <ul>
        <li><a href="#dashes">Dashes</a></li>
        <li><a href="#spaces">Spaces</a></li>
        <li><a href="#quotation-marks">Quotation Marks</a></li>
        <li><a href="#hyphenation-of-hyphenated-words">Hyphenation of Hyphenated Words</a></li>
      </ul>
    </li>
    <li><a href="#useful-packages-to-achieve-consistency">Useful Packages to Achieve Consistency</a>
      <ul>
        <li><a href="#physical-units-and-numbers">Physical Units and Numbers</a></li>
        <li><a href="#printing-dates-and-times">Printing Dates and Times</a></li>
        <li><a href="#inline-enumerations">Inline Enumerations</a></li>
      </ul>
    </li>
    <li><a href="#detecting-and-handling-warnings-bad-boxes">Detecting and Handling Warnings (Bad Boxes)</a>
      <ul>
        <li><a href="#filtering-warnings">Filtering Warnings</a></li>
        <li><a href="#obviously-visible-bad-box-warnings">Obviously Visible Bad Box Warnings</a></li>
        <li><a href="#underful-hbox-warnings">Underful hbox Warnings</a></li>
        <li><a href="#micro-typographic-improvements">Micro-Typographic Improvements.</a></li>
      </ul>
    </li>
    <li><a href="#cross-references">Cross-References</a>
      <ul>
        <li><a href="#hyperrefs-autoref-command">hyperref&rsquo;s autoref Command</a></li>
        <li><a href="#automatically-pointing-to-pages">Automatically Pointing to Pages</a></li>
        <li><a href="#hyperlinks-to-floats-and-not-their-captions">Hyperlinks to Floats and not their Captions</a></li>
      </ul>
    </li>
    <li><a href="#code-listings">Code Listings</a></li>
    <li><a href="#pretty-tables">Pretty Tables</a></li>
    <li><a href="#linting">Linting</a>
      <ul>
        <li><a href="#linting-for-latex-issues">Linting for LaTeX Issues</a></li>
        <li><a href="#prose-linting">Prose Linting</a></li>
      </ul>
    </li>
    <li><a href="#conclusion">Conclusion</a></li>
    <li><a href="#updates">Updates</a></li>
  </ul>
</nav>
</nav>

<h2 id="building-latex-documents">Building LaTeX Documents</h2>
<p>The first thing you have to do before being able to see a <a href="https://www.latex-project.org/">LaTeX</a> document is to compile your document into (probably) a PDF.
This process is a total mess in <a href="https://www.latex-project.org/">LaTeX</a> and depending on the features and packages you use, requires multiple iterations of calling the compiler with some call to utility programs at the right time in between.
This is highly complicated and hard to get right.
Don&rsquo;t even dare to create a custom Makefile for this purpose.
I have seen countless examples of broken Makefiles for <a href="https://www.latex-project.org/">LaTeX</a> that miss parts of these iterations, swallow important messages, or do not recover from errors.
Instead, use an established build tool specifically crafted for <a href="https://www.latex-project.org/">LaTeX</a>.
A few options exist such as <a href="https://launchpad.net/rubber">rubber</a> (Ever tried googling for latex and rubber to get help?), <a href="https://github.com/cereda/arara">arara</a> or <a href="https://github.com/aclements/latexrun">latexrun</a>.
However, my impression with all of them is that they are more or less unmaintained and lack important features.
Thus, the only viable option is to use the Perl-based <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a>, which is one of the oldest build tools.
It is included in every major <a href="https://www.latex-project.org/">LaTeX</a> distribution.</p>
<p><a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> is configured through a <code>latexmkrc</code> file besides your main document..
This file is a Perl script.
Probably the first thing you have to do is to set PDF mode (who still uses DVI?):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>$pdf_mode <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span></code></pre></div><p>In case your project contains custom classes that need to be added to the tex search path, you can use something like:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>$ENV{<span style="color:#e6db74">&#39;TEXINPUTS&#39;</span>}<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;./texmf//:&#39;</span>;
</span></span></code></pre></div><p>Btw, the double slash instructs <a href="https://www.latex-project.org/">LaTeX</a> to also search all subfolders of the specified <code>texmf</code> folder.</p>
<p>After configuring <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a>, you have multiple options how to compile your document.
If you want a single compilation run, a <code>latexmk main.tex</code> should be enough.
However, the real power of <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> is continuous compilation.
If you start it with <code>latexmk -pvc main.tex</code>, <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> compiles your document, opens a PDF viewer and from then on continuously monitors your document (with all included files and images) for changes and updates your preview on the fly.</p>
<p>In case something got stuck and you need to clean your document folder from intermediate files, you can of course use your VCS (<code>git clean -fdx</code>) or <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> via <code>latexmk -C main.tex</code>.</p>
<h2 id="generating-images-and-other-files">Generating Images and Other Files</h2>
<p>One common issue that often arises is that you have some images or other artifacts that should end up in the document, but they are in a format that is not compatible with <a href="https://www.latex-project.org/">LaTeX</a>.
Thus, you first have to convert them to a different format (for instance, PDF for vector graphics or JPEG for pixel images).
People usually do this conversion manually and put the resulting files into their VCS, too.
But as usual with generated files, in case someone changes the source image, you have to remember to manually regenerate the <a href="https://www.latex-project.org/">LaTeX</a>-compatible output file, too.</p>
<p>With <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> you can get rid of this manual and error-prone process by letting the build tool do the conversion automatically.
For this, you have to configure conversion rules in the <code>latexmkrc</code> file.
These rules used file extensions.
In case a document contains a reference to <code>foo.pdf</code> (e.g., an <code>\includegraphics{foo.pdf}</code>) and this file doesn&rsquo;t exist in the source tree, <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> uses the available conversion rules to find a file with the same basename that can be generated into the desired PDF file.
For instance, automatically converting SVG vector images and <a href="http://www.graphviz.org/">Graphviz</a> <code>.dot</code> files to PDF can be achieved with these rules in the <code>latexmkrc</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>add_cus_dep(<span style="color:#e6db74">&#39;svg&#39;</span>, <span style="color:#e6db74">&#39;pdf&#39;</span>, <span style="color:#ae81ff">0</span>, <span style="color:#e6db74">&#39;svg2pdf&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">sub</span> <span style="color:#a6e22e">svg2pdf</span> {
</span></span><span style="display:flex;"><span>    system(<span style="color:#e6db74">&#34;inkscape --export-area-drawing --export-pdf=\&#34;$_[0].pdf\&#34; \&#34;$_[0].svg\&#34;&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>add_cus_dep(<span style="color:#e6db74">&#39;dot&#39;</span>, <span style="color:#e6db74">&#39;pdf&#39;</span>, <span style="color:#ae81ff">0</span>, <span style="color:#e6db74">&#39;dot2pdf&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">sub</span> <span style="color:#a6e22e">dot2pdf</span> {
</span></span><span style="display:flex;"><span>    system(<span style="color:#e6db74">&#34;dot -T pdf -o \&#34;$_[0].pdf\&#34; \&#34;$_[0].dot\&#34;&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You can even generate <a href="https://www.latex-project.org/">LaTeX</a> sources from other documents in case you have tools that output the required <code>.tex</code> files.
I have used this to automatically convert online questionnaires to TeX for the appendix of my thesis using my own <a href="https://github.com/languitar/quexmltolatex">quexmltolatex</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>add_cus_dep(<span style="color:#e6db74">&#39;quexml&#39;</span>, <span style="color:#e6db74">&#39;tex&#39;</span>, <span style="color:#ae81ff">0</span>, <span style="color:#e6db74">&#39;quexml2tex&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">sub</span> <span style="color:#a6e22e">quexml2tex</span> {
</span></span><span style="display:flex;"><span>    system(<span style="color:#e6db74">&#34;quexmltolatex -p \&#34;${\basename($_[0])}\&#34; \&#34;$_[0].quexml\&#34; &gt; \&#34;$_[0].tex\&#34;&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Another currently popular tool for diagrams is <a href="https://www.draw.io/">draw.io</a>.
With the following rule and my own <a href="https://github.com/languitar/drawio-batch">drawio-batch</a> you can automatically convert those diagrams to PDF:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>add_cus_dep(<span style="color:#e6db74">&#39;xml&#39;</span>, <span style="color:#e6db74">&#39;pdf&#39;</span>, <span style="color:#ae81ff">0</span>, <span style="color:#e6db74">&#39;drawio2pdf&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">sub</span> <span style="color:#a6e22e">drawio2pdf</span> {
</span></span><span style="display:flex;"><span>    system(<span style="color:#e6db74">&#34;drawio-batch -f pdf \&#34;$_[0].xml\&#34; \&#34;$_[0].pdf\&#34;&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>For further useful conversion rules, have a look at <a href="https://github.com/e-dschungel/latexmk-config">this GitHub repository</a>.</p>
<p>After configuring images for automatic generation, remember to exclude the generated outputs from your VCS (<code>.gitignore</code>).
In case you want <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> to clean up the generated images on <code>-C</code> as well, the following setting is required:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>$cleanup_includes_cusdep_generated <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span></code></pre></div><h2 id="file-conventions">File Conventions</h2>
<h3 id="properly-use-utf-8">Properly Use UTF-8</h3>
<p>In ancient times, using non-ASCII characters in <a href="https://www.latex-project.org/">LaTeX</a> documents was a nightmare and special codes like <code>\&quot;a</code> had to be used in case you wanted an <code>ä</code>.
This is still documented this way in many places on the internet, despite being horrible to type and to read.</p>
<p>Nowadays, you can more or less safely use common umlauts etc. by using UTF-8 encoded files with the correct header declaration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-tex" data-lang="tex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[utf8]</span>{inputenc}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[T1]</span>{fontenc}
</span></span></code></pre></div><p>Another common source for problems with umlauts is the bibliography.
The ancient <a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a> has many issues with UTF-8.
However, <a href="https://github.com/plk/biblatex">BibLaTeX</a> and <a href="http://biblatex-biber.sourceforge.net/">biber</a> (see below) are designed to work with UTF-8.</p>
<h3 id="put-each-sentence-on-a-single-line">Put Each Sentence on a Single Line</h3>
<p>Apart from using UTF-8 consistently, I recommend following the convention of placing a single sentence of your document per line of the source file.
The rationale is that this make VCS diffs easily readable without requiring additional options like <code>--word-diff</code> for git to track changes.
This would be necessary if you put each paragraph into a single line or, even worse, if you configure your editor to automatically rewrap paragraphs at something like 80 characters line length.
<strong>Don&rsquo;t do this.</strong>
Even a single change at the beginning of a paragraph can reformat the whole paragraph then, resulting in massive and unreadable diffs.</p>
<h2 id="citations">Citations</h2>
<p>Citations are a necessity for scientific work and <a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a> has been used since ages for generating the necessary bibliographies and citations.
Most conference templates still use it today.
However, <a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a> has some serious issues.
Apart from the aforementioned lack of UTF-8 support, modifying style files is hard and it lacks support for many important fields in the database entries.
Thus, there are some replacements for <a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a>, with <a href="https://ctan.org/pkg/natbib">natbib</a> previously being a good guess.
However, nowadays <a href="https://github.com/plk/biblatex">BibLaTeX</a> (mind the difference, which Google loves to swallow) is probably the most versatile and handy solution you can and should use.</p>
<h3 id="basic-configuration">Basic Configuration</h3>
<p>The most important thing to do is to use <a href="https://github.com/plk/biblatex">BibLaTeX</a> together with the <a href="http://biblatex-biber.sourceforge.net/">biber</a> <code>.bib</code> file processor instead of the old <code>bibtex</code> binary.
Only this way you gain full UTF-8 support, document validation, filtering capabilities.
Thus, you should load the package at least with the <code>backend=biber</code> option (should be the default in modern versions).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-tex" data-lang="tex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[backend=biber,style=alphabetic]</span>{biblatex}
</span></span></code></pre></div><p>This way, you can use UTF-8 safely in your <code>.bib</code> files.</p>
<h3 id="database-entries">Database Entries</h3>
<p><a href="https://github.com/plk/biblatex">BibLaTeX</a> has an extended set of entry types and fields in the database, which is very well documented in the &ldquo;Database Guide&rdquo; section of the <a href="http://mirrors.ctan.org/macros/latex/contrib/biblatex/doc/biblatex.pdf">BibLaTeX manual</a>.
For instance, new types include <code>@online</code> for websites, <code>@patent</code> for patents, <code>@standard</code> for standardization documents, and <code>@report</code> for research reports.
Moreover, many new fields for entries exist that make filtering the database easier and give bibliography and citation styles more possibilities to include the relevant information in an appropriate format.
Especially the <code>doi</code> field is important nowadays support readers in finding the exact publications you are referring to.
A more ore less complete entry for a conference paper for <a href="https://github.com/plk/biblatex">BibLaTeX</a> might look like this:</p>
<pre tabindex="0"><code>@inproceedings{Yu2015,
    author = {Yu, Jingjin and Aslam, Javed and Karaman, Sertac and Rus, Daniela},
    bookpagination = {page},
    booktitle = {IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
    date = {2015},
    doi = {10.1109/IROS.2015.7354122},
    eventdate = {2015-09-28/2015-10-02},
    eventtitle = {2015 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
    isbn = {978-1-4799-9994-1},
    pages = {5279--5286},
    publisher = {IEEE},
    title = {Anytime planning of optimal schedules for a mobile sensing robot},
    venue = {Hamburg, Germany}
}
</code></pre><p>All database entries are based on a declared schema, which can also be validated by <a href="http://biblatex-biber.sourceforge.net/">biber</a> using the <code>--validate-datamodel</code> command line switch.
This can be enabled in the <code>latexmkrc</code> file by overriding the default <a href="http://biblatex-biber.sourceforge.net/">biber</a> call:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>$biber <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;biber --validate-datamodel %O %S&#39;</span>;
</span></span></code></pre></div><p>This way, errors in the bibliography database will automatically be reported.</p>
<p>Regarding the contents of individual entry fields in the database, there are still some common pitfalls and illogical things being documented in other places:</p>
<ul>
<li>
<p>Double curly braces instruct <a href="https://github.com/plk/biblatex">BibLaTeX</a>/<a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a> to interpret a string or value exactly as written.
You don&rsquo;t want to do this everywhere automatically.
For instance, this prevents name parsing and <code>{{Peter Miller}}</code> will not be sorted along his surname, neither will his forename be abbreviated in styles that do so.
Moreover, setting paper title in double curly braces will also disable the automatic title case in the IEEE style.</p>
</li>
<li>
<p>In case you are citing documents in different languages, define at least the <code>langid</code> field of the entry to ensure that proper hyphenation is used in the bibliography.
<code>langid</code> is passed to the [babel] package.
Thus, all identifiers that [babel] supports are accepted here (e.g., <code>american</code>, <code>french</code>, <code>british</code>).</p>
</li>
<li>
<p>The same identifiers can also be used in the <code>language</code> field to add a note to bibliography entries in case a cited document is in a different language than the document itself.
Unfortunately, the values here are not validated by <a href="http://biblatex-biber.sourceforge.net/">biber</a>.
You can add the following code to your preamble to ensure that the provided language is known by <a href="https://github.com/plk/biblatex">BibLaTeX</a> (hopefully this will still work in the future):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\makeatletter</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\DeclareIndexListFormat</span>{language}{<span style="color:#75715e">%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">\ifboolexpr</span>{ test {<span style="color:#66d9ef">\ifbibstring</span>{#1}} or test {<span style="color:#66d9ef">\ifbibstring</span>{lang#1}} }
</span></span><span style="display:flex;"><span>    {}
</span></span><span style="display:flex;"><span>    {<span style="color:#66d9ef">\blx</span>@warning@noline{Unknown language &#39;#1&#39; in &#39;language&#39; field of<span style="color:#66d9ef">\MessageBreak</span> &#39;<span style="color:#66d9ef">\thefield</span>{entrykey}&#39;}}}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\AtDataInput</span>{<span style="color:#66d9ef">\indexlist</span>{language}}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\makeatother</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="advanced-citation-commands">Advanced Citation Commands</h3>
<p>Although you could continue to simply use <code>\cite</code> to cite bibliography content, <a href="https://github.com/plk/biblatex">BibLaTeX</a> has a lot more utility commands to simplify common situations.
Generally, it is a good idea to switch over to the <code>\autocite</code> command.
The behavior of this command (inline citation, footnote, etc.) can be configured using a pacakge option.
Thus, you can easily change the way citations are printed with a single change to package options.</p>
<p>In case you want to use a publication as a subject or object in a sentence, <code>\textcite</code> can be used.
This command will automatically insert (depending on the configured citation style) something like the author names so that a real subject exists.
For instance, &ldquo;\Textcite{Foo1999} shows that&rdquo; might result in: &ldquo;Foo and Bar [FB99] shows that&rdquo;.
The capitalized versions of the commands ensure that the resulting text starts with a capital letter at the beginning of sentences.</p>
<p>It is also possible to extract individual keys from bibliography entries using special citations commands.
In case you want to highlight a seminal book or something like that you can use <code>\citetitle</code> and author names can be gathered using <code>\citeauthor</code>.
This way, things are not duplicated and potential typos can be corrected in a single place.</p>
<h3 id="filtering-and-mapping-bibliographies">Filtering and Mapping Bibliographies</h3>
<p>Often, you do not maintain your <code>.bib</code> file manually but instead you use a reference manager like Mendeley or Citavi.
Thus, you only have limited control of what will end up in the generated file.
For instance, the entry <code>Yu2015</code> shown above is generated by Citavi and contains a huge level of details.
<a href="https://github.com/plk/biblatex">BibLaTeX</a> will happily print all available details in the bibliography and thus even the conference dates will be printed.
This might be acceptable for a longer document, but in a space-limited conference paper, this eats all your space and might also violate the publication guidelines.
You could delete the offending keys for the <code>.bib</code> file manually, but that has to be redone every time you regenerate the database.
Moreover, if you share the <code>.bib</code> file between different documents with different requirements on the printed fields, this won&rsquo;t work at all.</p>
<p>Fortunately, <a href="https://github.com/plk/biblatex">BibLaTeX</a> in combination with <a href="http://biblatex-biber.sourceforge.net/">biber</a> allows declaring filters and maps to fix up such issues.
In your preamble you can use something like the following to delete fields depending on the entry types:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\DeclareSourcemap</span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\maps</span><span style="color:#a6e22e">[datatype=bibtex]</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">% remove fields that are always useless
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">\map</span>{
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=abstract, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=pagetotal, null]</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">% remove URLs for types that are primarily printed
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">\map</span>{
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{software}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{online}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{report}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{techreport}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{standard}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{manual}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pernottype</span>{misc}
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=url, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=urldate, null]</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">\map</span>{
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\pertype</span>{inproceedings}
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">% remove mostly redundant conference information
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=venue, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=eventdate, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=eventtitle, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">% do not show ISBN for proceedings
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=isbn, null]</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">% Citavi bug
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=volume, null]</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>As you can see with the <code>volume</code> field in <code>@inproceedings</code>, this can also be used to fix at least some of the annoying errors that most reference managers do.
Btw, for Citavi, be sure to use the export style for <a href="https://github.com/plk/biblatex">BibLaTeX</a> and not the <a href="https://en.wikipedia.org/wiki/BibTeX">BibTeX</a> one.</p>
<p>Another useful application for source maps is to find your own publication in a list of publications based on the author name for printing a separate list of these publications.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\map</span><span style="color:#a6e22e">[overwrite=true]</span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldsource=author, match=Wienke, final]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\step</span><span style="color:#a6e22e">[fieldset=keywords, fieldvalue=ownpub]</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>With this map, every publication containing my surname in the <code>author</code> field gets the keyword <code>ownpub</code>.
I can then use something along the following lines to put my own publications in front of the general bibliography:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\printbibliography</span><span style="color:#a6e22e">[heading=bibintoc,keyword=ownpub,title={Own publications}]</span>{}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\printbibliography</span><span style="color:#a6e22e">[heading=bibintoc,notkeyword=ownpub,title={Other publications}]</span>{}
</span></span></code></pre></div><h2 id="achieving-typographically-correct-results">Achieving Typographically Correct Results</h2>
<p>In some situations you have to know what you are doing to achieve results that correctly reflect the rules of typography.
Some of those are of general nature, but some also are specific to <a href="https://www.latex-project.org/">LaTeX</a>.</p>
<h3 id="dashes">Dashes</h3>
<p>Typography knows different types of dashes and not every dash you will be using is represented as a minus sign in the source code.
<a href="https://www.latex-project.org/">LaTeX</a> know the following dashes:</p>
<ul>
<li><code>-</code>: a hyphen so combine compound words or for hyphenation</li>
<li><code>--</code>: en-dash, somewhat longer than the hyphen</li>
<li><code>---</code>: em-dash, even longer</li>
</ul>
<p>Different people promote different rules for when to use these different dashes.
Just have a look at <a href="https://tex.stackexchange.com/questions/3819/dashes-vs-vs">this Stackexchange question</a> to get an impression of the different schools, pick the convention that you like best and apply it consistently.
Knowing the difference and using the different visual pauses the dashes types create in the text flow consistently and with purpose is the most important aspect.</p>
<h3 id="spaces">Spaces</h3>
<p><a href="https://www.latex-project.org/">LaTeX</a> distinguishes between different types of spaces.
Depending on the conventions commonly used in different countries, spaces between words might smaller than the ones between sentences.
Thus, <a href="https://www.latex-project.org/">LaTeX</a> must be able to distinguish these two types.
Generally, a space is treated as an inter-word space as long as the character before the space is <em>not</em> a period.
A period is thus interpreted as the end of a sentence and the following space is assumed to be an inter-sentence space.
Thus, if you use an abbreviation with a period at the end, you have instructed <a href="https://www.latex-project.org/">LaTeX</a> that this period does not end the current sentence by <em>escaping</em> the following space:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>This is a sentence w.<span style="color:#66d9ef">\ </span>a forced inter-word space.
</span></span></code></pre></div><p>If you don&rsquo;t do this, you randomly get larger spaces after abbreviations that interrupt the visual flow.</p>
<p>One exception to this rule is if the period is preceded by a capital letter.
In this case, <a href="https://www.latex-project.org/">LaTeX</a> assumes an abbreviation and continues to use an inter-word space.
You can reverse this behavior by placing an <code>\@</code> before the period.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>This is done by XYZ<span style="color:#66d9ef">\@</span>. This is a new sentence.
</span></span></code></pre></div><p>If you are using common abbreviations in English, e.g. this one, i.e. exempli gratia, you can use the <a href="https://ctan.org/pkg/foreign">foreign</a> package to get commands that handle the spacing correctly:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[abbreviations,british]</span>{foreign}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>This is an example, <span style="color:#66d9ef">\eg</span>{} spacing is right here.
</span></span></code></pre></div><p><code>british</code> in the package options here means that no comma is placed automatically behind the abbreviations.</p>
<h3 id="quotation-marks">Quotation Marks</h3>
<p>Placing correct quotation marks requires some thought, especially in other languages than English.
For instance, in German you would have to type this to get correct opening and closing marks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\glqq</span>{}this is the quoted text<span style="color:#66d9ef">\grqq</span>{}
</span></span></code></pre></div><p>If you want to avoid remembering how each language and publisher style handles quotation marks, simply use the <a href="https://ctan.org/pkg/csquotes">csquotes</a> package, which automatically selects the correct way for the current document language:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\textquote</span>{this is the quoted text}
</span></span></code></pre></div><p>If the quotation is actually from another publication that has to be cited, you can use the following shortcut to also get the correct citation through <a href="https://github.com/plk/biblatex">BibLaTeX</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\textcquote</span><span style="color:#a6e22e">[42]</span>{Yu2015}{this is the quoted text}
</span></span></code></pre></div><p>As you can see, this also supports the typical pre and post notes for <a href="https://github.com/plk/biblatex">BibLaTeX</a> citation commands to place page numbers.</p>
<p>If your quotation is a sentence that ends with a period, some languages have different rules whether to include the period in the quotation marks or not.
<a href="https://ctan.org/pkg/csquotes">csquotes</a> can handle these cases automatically (and with configuration options), but you have to indicate the final period manually:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\textcquote</span><span style="color:#a6e22e">[42]</span>{Yu2015}[.]{This is the quoted text and a full sentence with period}
</span></span></code></pre></div><p>Finally, it is common to strip some parts of quoted material or add annotations to make it understandable in the current context.
<a href="https://ctan.org/pkg/csquotes">csquotes</a> provides command for these purposes so that you do not have to remember the exact rules in each language.
For instance, to replace some fraction with a summary you can use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\textcquote</span><span style="color:#a6e22e">[42]</span>{Yu2015}[.]{This is <span style="color:#66d9ef">\textelp</span>{garbage} with  period}
</span></span></code></pre></div><p><code>\textins</code> adds an annotation without indicating the omission of material.</p>
<h3 id="hyphenation-of-hyphenated-words">Hyphenation of Hyphenated Words</h3>
<p><a href="https://www.latex-project.org/">LaTeX</a> usually automatically hyphenates words automatically.
However, this behavior is switched off as soon as the work contains a hyphen to create a compound word such as <code>architecture-aware</code>.
Suddenly, <a href="https://www.latex-project.org/">LaTeX</a> will not hyphenate the individual parts, despite knowing hyphenation patterns for them.
This will likely result in overfull hbox warnings.
The same will also happen for other special characters such as <code>/</code>.</p>
<p>To avoid this issue, the <a href="https://ctan.org/pkg/hyphenat">hyphenat</a> package provides commands that still allow hyphenation of individual parts.
Thus, <code>architecture/building-aware</code> becomes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>architecture<span style="color:#66d9ef">\fshyp</span>{}building<span style="color:#66d9ef">\hyp</span>{}aware
</span></span></code></pre></div><p>Not exactly nice to read, but it does the job.</p>
<h2 id="useful-packages-to-achieve-consistency">Useful Packages to Achieve Consistency</h2>
<p>Some things require consistency and are repetitive and I will shortly introduce some packages for such cases.</p>
<h3 id="physical-units-and-numbers">Physical Units and Numbers</h3>
<p>In case you are typesetting numbers with physical units or numbers in general, some typographic rules have to be followed for a correct representation.
Fortunately, the <a href="https://ctan.org/pkg/siunitx">siunitx</a> package implements these rules, selects appropriate ones automatically, and makes them configurable globally.
For software engineers, the following package option also load binary units:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[binary-units=true]</span>{siunitx}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\sisetup</span>{detect-all}
</span></span></code></pre></div><p>The second line detect all features of the document font to adapt the number formatting accordingly.
Afterwards, you can do such crazy things and everything will be set correctly:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>We measure in <span style="color:#66d9ef">\si</span>{<span style="color:#66d9ef">\kilogram\metre\per\second</span>}.
</span></span><span style="display:flex;"><span>The brightness was <span style="color:#66d9ef">\SI</span>{.23e7}{<span style="color:#66d9ef">\candela</span>}.
</span></span><span style="display:flex;"><span>The experiment resulted in <span style="color:#66d9ef">\SIlist</span>{0.13;0.67;0.80}{<span style="color:#66d9ef">\milli\metre</span>}.
</span></span><span style="display:flex;"><span>We need <span style="color:#66d9ef">\numlist</span>{10;30;50;70} participants.
</span></span><span style="display:flex;"><span>The angle was <span style="color:#66d9ef">\ang</span>{12.3}.
</span></span></code></pre></div><h3 id="printing-dates-and-times">Printing Dates and Times</h3>
<p>If you have to mention dates and times frequently, the <a href="https://ctan.org/pkg/datetime2">datetime2</a> package provides macros to do this consistently:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[useregional]</span>{datetime2}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">% ...
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>We took the measurements at <span style="color:#66d9ef">\DTMDate</span>{2017-08-07}.
</span></span></code></pre></div><h3 id="inline-enumerations">Inline Enumerations</h3>
<p>In case a) you like code structure, b) use inline enumerations, and c) want a package for this, use <a href="https://ctan.org/pkg/paralist">paralist</a>.
This sentence could then be realized as:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>In case
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\begin</span>{inparaenum}[a)]
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\item</span> you like code structure,
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\item</span> use inline enumerations, and
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\item</span> want a package for this, use paralist.
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{inparaenum}
</span></span></code></pre></div><h2 id="detecting-and-handling-warnings-bad-boxes">Detecting and Handling Warnings (Bad Boxes)</h2>
<p><a href="https://www.latex-project.org/">LaTeX</a> is very strict about its typographic rules and in case it can&rsquo;t make some part of your document fit into the typographic rules, it will generate a warning and will break the rules in the result document.
The common result is that line of text will flow out of the text border because no valid hyphenation would result in resolving all constraints.
This is a common cause for the &ldquo;Overfull hbox warnings&rdquo; most people see and ignore in their documents.
While some obviously need fixing, because the page margin gets flooded, others are harder to spot.</p>
<p>So what to do about these issues?
First of all, these warnings shouldn&rsquo;t exist in the final document and in case one of them appears, you should be able to easily spot them.
This is best achieved if usually there are no warnings at all.
However, many packages create some warnings when being included that can simply not be solved and are acceptable.
These warnings flood the error window of your editor and make it hard to detect the actual problems.</p>
<h3 id="filtering-warnings">Filtering Warnings</h3>
<p>To avoid that acceptable warnings hide unacceptable ones, you can use the <a href="https://ctan.org/pkg/silence">silence</a> package for hiding warnings based on the source package and string matching for the warning message.
As several unfixable warnings appear already when importing packages, it is usually a good idea to include the silence package as the first package:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\RequirePackage</span>{silence}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{scrreprt}{Usage of package `titlesec&#39;}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{scrreprt}{Activating an ugly workaround}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{titlesec}{Non standard sectioning command detected}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{microtype}{protrusion codes list}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{latexfont}{Font}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\WarningFilter</span>{latexfont}{Some font shapes}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\documentclass</span><span style="color:#a6e22e">[...]</span>{...}
</span></span></code></pre></div><h3 id="obviously-visible-bad-box-warnings">Obviously Visible Bad Box Warnings</h3>
<p>As said, while some overfull hbox warnings can easily be spotted, other are harder to catch.
However, when adding the following line to your preamble, a thick black bar marks every line that even slightly violates margins.
This makes spotting them much easier.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\overfullrule</span>=2cm
</span></span></code></pre></div><p>The following image shows the visual result of this setting in case of an overfull hbox.</p>
<figure>
    <img loading="lazy" src="latex-overfullrule.png"
         alt="Effect of overfullrule in LaTeX"/> <figcaption>
            <p>Effect of using overfullrule in LaTeX</p>
        </figcaption>
</figure>

<h3 id="underful-hbox-warnings">Underful hbox Warnings</h3>
<p>In contrast to the previous examples, where <a href="https://www.latex-project.org/">LaTeX</a> created lines that were too long, you sometimes also get &ldquo;underfull hbox&rdquo; warnings.
This happens in case something doesn&rsquo;t fill the space it should.
A common source for this are manual line breaks using <code>\\</code>.
If you can, avoid these and use better suited constructs where possible.
At least, don&rsquo;t end a paragraph with a forced line break (<code>\\</code> followed by an empty line).
This will always create a warning.</p>
<h3 id="micro-typographic-improvements">Micro-Typographic Improvements.</h3>
<p>Even though <a href="https://www.latex-project.org/">LaTeX</a> is already pretty good at producing high-quality documents, a single package can still greatly improve the situation: <a href="https://ctan.org/pkg/microtype">microtype</a>.
This package improves the visual appearance of the documents by fiddling with the different spacings on the level of individual letters.
This creates a document where the visual weight of the different letters is reflected in the way they are laid out on the page.
For instance, the text borders get much smoother this way.
Another side effect is, that documents with <a href="https://ctan.org/pkg/microtype">microtype</a> being enabled usually have less bad boxes.</p>
<p>As a small example, this document compares the layouting of the same text in two narrow columns:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\documentclass</span><span style="color:#a6e22e">[a5paper,twocolumn]</span>{article}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[english]</span>{babel}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{blindtext}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{geometry}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\geometry</span>{
</span></span><span style="display:flex;"><span>    a4paper,
</span></span><span style="display:flex;"><span>    total={100mm,257mm},
</span></span><span style="display:flex;"><span>    left=55mm,
</span></span><span style="display:flex;"><span>    top=55mm,
</span></span><span style="display:flex;"><span>    columnsep=2.8cm,
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[activate={true,nocompatibility},final,tracking=true,kerning=true,factor=1100,stretch=10,shrink=10]</span>{microtype}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\begin</span>{document}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\microtypesetup</span>{activate=false}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\blindtext</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\newpage</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\microtypesetup</span>{activate={true,nocompatibility}}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\blindtext</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{document}
</span></span></code></pre></div><p>The compiled result is the following:</p>
<figure>
    <img loading="lazy" src="latex-microtype.png"
         alt="Effect of microtype in LaTeX"/> <figcaption>
            <p>Comparison of text layout without (left) and with microtype (right).</p>
        </figcaption>
</figure>

<p>While the left column without <a href="https://ctan.org/pkg/microtype">microtype</a> enabled produces 4 underfull hbox warnings, the right one has only one.
Moreover, the right border looks a lot less jerky with <a href="https://ctan.org/pkg/microtype">microtype</a>, partially because less words are hyphenated.
So, whenever possible, it is a good idea to enable <a href="https://ctan.org/pkg/microtype">microtype</a>.
However, remember that at some places little shifts of individual words and letters might not be desirable.
For instance, the table of contents might be a place where you may want to temporarily disable protrusion using <code>\microtypesetup{protrusion=false}</code>.</p>
<h2 id="cross-references">Cross-References</h2>
<p>Cross-references are a common feature in close to any document.
As soon as you have a floating figure, you probably want to reference it from the text.
I&rsquo;ve seen countless documents where people manually added the type of the reference target to the reference.
Something along the following lines:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>Please refer to Fig.~<span style="color:#66d9ef">\ref</span>{fig:xyz}.
</span></span></code></pre></div><p>First of all, you have to remember to put a non-breaking space (<code>~</code>) to avoid splitting this.
Second, you have to remember for each type of reference, how you refer to it for being consistent.
Was it &ldquo;Figure&rdquo;, &ldquo;figure&rdquo;, &ldquo;Fig.&rdquo;, or &ldquo;fig.&rdquo;?
An if you decide to change this convention afterwards, this some manual work across the whole document.
Fortunately, there are different packages that solve this problem</p>
<h3 id="hyperrefs-autoref-command">hyperref&rsquo;s autoref Command</h3>
<p>In smaller documents and in case you have no desperate need to modify the default, the <code>\autoref</code> command provided by the popular <a href="https://ctan.org/pkg/hyperref">hyperref</a> package is a solid choice.
The previous example would reduce to:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>Please refer to <span style="color:#66d9ef">\autoref</span>{fig:xyz}.
</span></span></code></pre></div><p>Much easier and automatically consistent.</p>
<p>In case you want to change the way a figure is called, this can be done via the following code in the preamble:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\addto\extrasenglish</span>{<span style="color:#66d9ef">\def\figureautorefname</span>{Fancy figure}}
</span></span></code></pre></div><p>In case you want more flexibility, <a href="https://ctan.org/pkg/cleveref">cleveref</a> is a solid package choice.</p>
<h3 id="automatically-pointing-to-pages">Automatically Pointing to Pages</h3>
<p>In longer documents that are primarily provided in printed form, referring to the number of a figure or chapter might not be enough to make the document easily readable.
In case the chapter or figure is further away than the facing page, the reader has to start searching for it and providing a page number will make this much easier.
Of course, you can to this manually:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span>Please refer to <span style="color:#66d9ef">\autoref</span>{fig:test} on the facing page.
</span></span><span style="display:flex;"><span>Please refer to <span style="color:#66d9ef">\autoref</span>{fig:bla} on page <span style="color:#66d9ef">\pageref</span>{fig:bla}.
</span></span></code></pre></div><p>But how do you know whether the floating figure really ends up at the facing page or isn&rsquo;t placed on same page as your reference?
In that case, adding a page number just looks silly.
The package <a href="https://ctan.org/pkg/varioref">varioref</a> automates the process of adding these page references.
If something close, it adds things like &ldquo;on the previous/next/page page&rdquo;, if targets are further ways, a page number is added.
All this with some automatic variations to avoid sounding repetitive.</p>
<p>For using <a href="https://ctan.org/pkg/varioref">varioref</a>, it is best combined with <a href="https://ctan.org/pkg/hyperref">hyperref</a> and <a href="https://ctan.org/pkg/cleveref">cleveref</a>, but a specific order of package imports has to be used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{varioref}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{hyperref}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{cleveref}
</span></span></code></pre></div><p>Afterwards, you can use <code>\vref</code> or <code>\Vref</code> to get the automatic references.</p>
<p>Please be warned, <a href="https://ctan.org/pkg/varioref">varioref</a> is a monster with a disputable maintenance state and some ugly errors that can happen.
Yet, I am not aware of a better alternative.
Due to the nature of how <a href="https://www.latex-project.org/">LaTeX</a> documents are compiled incrementally, you might end up in endless compile loops.
Imagine the following situation:</p>
<ul>
<li><code>\vref</code> to a figure sees that this figure is currently placed on the facing page.
This, it adds the text &ldquo;on the facing page&rdquo;, which is quite long.</li>
<li>The next call to <code>pdflatex</code> sees the long addition and as a result, the figure moves on page further, references are invalidated again.</li>
<li><a href="https://ctan.org/pkg/varioref">varioref</a> now sees that the figure is two pages further.
Thus, it decides to use &ldquo;on page 8&rdquo; instead, which is shorter.</li>
<li>The next compile iteration of <code>pdflatex</code> sees the shorter text and the figure flips back to the facing page.</li>
</ul>
<p>This process can now continue from the beginning and never stops.
Generally, this is a problem that can always appear in <a href="https://www.latex-project.org/">LaTeX</a> in case the delayed processing on invalidated references significantly changes the amount of text that is produced.
So, in case <a href="http://personal.psu.edu/jcc8//software/latexmk-jcc/">latexmk</a> stops compiling your document with an error message that the maximum number of passes was exceeded, this is a likely source.
The only option to cure this is to change your document in such a way that the reference target will not move around.</p>
<p>As it is sometimes hard to find out which reference causes this issue, you might add the following code to your preamble:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\makeatletter</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\def\@</span>testdef #1#2#3{<span style="color:#75715e">%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">\def\reserved</span>@a{#3}<span style="color:#66d9ef">\expandafter</span> <span style="color:#66d9ef">\ifx</span> <span style="color:#66d9ef">\csname</span> #1@#2<span style="color:#66d9ef">\endcsname</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">\reserved</span>@a  <span style="color:#66d9ef">\else</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\typeout</span>{^^Jlabel #2 changed:^^J<span style="color:#75715e">%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">\meaning\reserved</span>@a^^J<span style="color:#75715e">%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">\expandafter\meaning\csname</span> #1@#2<span style="color:#66d9ef">\endcsname</span>^^J}<span style="color:#75715e">%
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">\@</span>tempswatrue <span style="color:#66d9ef">\fi</span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\makeatother</span>
</span></span></code></pre></div><p>At each compile run, this will spit out all references that changed in a compile run.
Compare these outputs between the different compiler invocations (<code>diff</code>) to find the offending labels.</p>
<h3 id="hyperlinks-to-floats-and-not-their-captions">Hyperlinks to Floats and not their Captions</h3>
<p>If you use <a href="https://ctan.org/pkg/hyperref">hyperref</a> and provide PDFs digitally, you get nice clickable links.
However, for floating environments like figures, these links usually point to the caption text and not to the top of the environment.
Thus, it might happen that clicking a link makes the PDF viewer scroll to the caption and the image above is cut off.
Your can avoid these issues by loading the package <a href="https://ctan.org/pkg/hypcap">hypcap</a>, which needs to be imported after <a href="https://ctan.org/pkg/hyperref">hyperref</a>.</p>
<h2 id="code-listings">Code Listings</h2>
<p>Providing code listings is a common task in case you are in a technical discipline.
The <a href="https://ctan.org/pkg/listings">listings</a> package with its <code>lstlisting</code> environment and <code>lstinputlisting</code> command is a common and simple solutions for this.
However, providing good code highlights is a hard problem and the rules used by this package are pretty simple.
Other, standalone code highlighters provide much better highlights.
The <a href="https://github.com/gpoore/minted">minted</a> package includes the pretty well-known highlighter <a href="http://pygments.org/">Pygments</a> to provide nicer highlights.
Just have a look at the output of this test document:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-latex" data-lang="latex"><span style="display:flex;"><span><span style="color:#66d9ef">\documentclass</span><span style="color:#a6e22e">[a4paper]</span>{article}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span><span style="color:#a6e22e">[english]</span>{babel}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{color}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\definecolor</span>{bluekeywords}{rgb}{0.13, 0.13, 1}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\definecolor</span>{greencomments}{rgb}{0, 0.5, 0}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\definecolor</span>{redstrings}{rgb}{0.9, 0, 0}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\definecolor</span>{graynumbers}{rgb}{0.5, 0.5, 0.5}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{listings}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\lstset</span>{
</span></span><span style="display:flex;"><span>    columns=fullflexible,
</span></span><span style="display:flex;"><span>    commentstyle=<span style="color:#66d9ef">\color</span>{greencomments},
</span></span><span style="display:flex;"><span>    keywordstyle=<span style="color:#66d9ef">\color</span>{bluekeywords},
</span></span><span style="display:flex;"><span>    stringstyle=<span style="color:#66d9ef">\color</span>{redstrings},
</span></span><span style="display:flex;"><span>    numberstyle=<span style="color:#66d9ef">\color</span>{graynumbers},
</span></span><span style="display:flex;"><span>    basicstyle=<span style="color:#66d9ef">\ttfamily\small</span>,
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{minted}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\begin</span>{document}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\section*</span>{listings}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\lstinputlisting</span><span style="color:#a6e22e">[language=python]</span>{test.py}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\section*</span>{minted}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\inputminted</span>{python}{test.py}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{document}
</span></span></code></pre></div><p>For <a href="https://ctan.org/pkg/listings">listings</a>, this is the minimal setup required to get colored output with an editor-like appearance.
For minted, the defaults already provide nice results:</p>
<figure>
    <img loading="lazy" src="latex-code-highlighting.png"
         alt="Comparison of listings and minted for highlighting Python code"/> <figcaption>
            <p>Comparison of listings and minted for highlighting Python code</p>
        </figcaption>
</figure>

<p><a href="http://pygments.org/">Pygments</a> does a much better job at highlighting things nicely with the default setup.</p>
<p>As <a href="https://github.com/gpoore/minted">minted</a> relies on an external program for highlighting, of course, you need to ensure that <a href="http://pygments.org/">Pygments</a> is installed.
Moreover, the <a href="https://www.latex-project.org/">LaTeX</a> compiler has to be instructed to allow calls to external programs.
This can be done in the <code>latexmkrc</code> file by redefining the compiler call to include the <code>-shell-escape</code> flag:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>$pdflatex <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;pdflatex -shell-escape -interaction=nonstopmode&#39;</span>;
</span></span></code></pre></div><h2 id="pretty-tables">Pretty Tables</h2>
<p>For getting nicely looking tables, you should at least use the <a href="https://ctan.org/pkg/booktabs">booktabs</a> package, which defines different rules for the top, the bottom, and in between tables.
The package documentation gives some basic hints on how to design tables correctly.
Basically, common advices boil down to:</p>
<ul>
<li>No vertical lines whenever possible</li>
<li>Horizontal lines only at the top and bottom of the table and to separate the header and footer</li>
</ul>
<p>Others have written good and more detailed guides:</p>
<ul>
<li><a href="https://www.inf.ethz.ch/personal/markusp/teaching/guides/guide-tables.pdf">Small Guide to Making Nice Tables</a></li>
<li><a href="http://mirrors.ctan.org/macros/latex/contrib/booktabs/booktabs.pdf">Publication quality tables in LaTeX</a></li>
<li><a href="https://imgur.com/gallery/ZY8dKpA">How to make your tables less terrible</a>: a nice animation, less than a minute</li>
</ul>
<h2 id="linting">Linting</h2>
<p>As you have seen, there are a few common pitfalls and a lot of things you have to remember when using <a href="https://www.latex-project.org/">LaTeX</a>.
At least for some of the typical issues, linters exist that try to point them out automatically.
A good editor should be able to integrate these linters in a way that you get instant feedback.</p>
<h3 id="linting-for-latex-issues">Linting for LaTeX Issues</h3>
<p>For issues regarding the use of <a href="https://www.latex-project.org/">LaTeX</a> itself, I recommend <a href="http://www.nongnu.org/chktex/">chktex</a>, which comes with any major <a href="https://www.latex-project.org/">LaTeX</a> distribution.
It produces warnings like these:</p>
<ul>
<li>Warning 12 in ./chapters/middleware.tex line 605: Interword spacing (`\ &lsquo;) should perhaps be used.</li>
<li>Warning 8 in ./chapters/faultdetection.tex line 136: Wrong length of dash may have been used.</li>
<li>Warning 17 in ./appendix/collected-metrics.tex line 629: Number of `(&rsquo; doesn&rsquo;t match the number of `)&rsquo;!</li>
<li>Warning 1 in ./chapters/dashboard.tex line 170: Command terminated with space.</li>
<li>Warning 46 in ./chapters/prediction.tex line 452: Use ( &hellip; ) instead of $ &hellip; $.</li>
</ul>
<h3 id="prose-linting">Prose Linting</h3>
<p>Apart from linting the technical use of <a href="https://www.latex-project.org/">LaTeX</a>, it is also a good idea to look through your prose for common issues.
The least and probably well-accepted thing to use is a spell checker.
But there are more and interesting tools to use for this purpose as well.</p>
<h4 id="grammar-checks-with-languagetool">Grammar Checks with LanguageTool</h4>
<p>For finding grammar errors in <a href="https://www.latex-project.org/">LaTeX</a> documents you can use the pretty good <a href="https://languagetool.org/">LanguageTool</a>.
This grammar checker works on plain text files.
Obviously, <a href="https://www.latex-project.org/">LaTeX</a> is not plain text with all the commands in between.
If your editor doesn&rsquo;t have a reasonable integration of <a href="https://languagetool.org/">LanguageTool</a> that strips away all the command (while preserving the exact line and column positions of words), you can take the scripts in <a href="https://gist.github.com/languitar/2037fccd8520586639aa9f1227bbf8e6">this gist</a> as a starting point for a preprocessor and integration with <a href="https://languagetool.org/">LanguageTool</a>.
<code>detex.py</code> strips away a manually curated list of commands and replaces them with plain text representations that preserve the exact position in the source file (adds multiple spaces if necessary).
<code>detex-python.py</code> is a replacement for the <a href="https://languagetool.org/">LanguageTool</a> binary that automatically pipes the target file through <code>detex.py</code> before handing the stripped down text to <a href="https://languagetool.org/">LanguageTool</a> for grammar checking.
If you are lucky, you can configure your editor to use this script instead of the original <a href="https://languagetool.org/">LanguageTool</a> binary.
Obviously, the set of replaced commands needs to be matched with what you use in your document.
The extra effort this takes is well worth it, as <a href="https://languagetool.org/">LanguageTool</a> is pretty good at spotting even more complex grammar issues.</p>
<h4 id="content-linting-with-vale">Content Linting with Vale</h4>
<p>At least for the English language, there are also multiple tools to actually lint the content of your text for common issues such as weasel words, passive voice, potentially offensive speech, etc.
While many exist, my verdict was that all relevant ones can be replaced with <a href="https://github.com/errata-ai/vale">Vale</a>, which uses a set of different styles to search for common problems.
The default configuration is pretty lax and doesn&rsquo;t check much, so you need to search through the <a href="https://github.com/errata-ai/vale/tree/master/styles">styles folder</a> and select additional styles to apply to your text.
These can be put directly into your project and a <code>.vale</code> file is the configuration for the linter.
What I have been using was this config:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#a6e22e">StylesPath</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">.vale-styles</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">MinAlertLevel</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">suggestion</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[*]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">BasedOnStyles</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">vale, proselint, TheEconomist, 18F, PlainLanguage, mystuff</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">proselint.Annotations</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">write-good.E-Prime</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">write-good.Passive</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TheEconomist.UnexpandedAcronyms</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TheEconomist.Punctuation</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">18F.UnexpandedAcronyms</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">18F.Abbreviations</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">18F.Contractions</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PlainLanguage.Contractions</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PlainLanguage.Slash</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">NO</span>
</span></span></code></pre></div><p>In <code>mystuff</code> I created a custom style to remind myself for being consistent.
For instance, <code>.vale-style/mystuff/Lists.yml</code> checks that list items start with a capital letter:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">extends</span>: <span style="color:#ae81ff">existence</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">message</span>: <span style="color:#e6db74">&#34;Use capital letters for list items&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">ignorecase</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">level</span>: <span style="color:#ae81ff">warning</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">raw</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#ae81ff">\\item(\[.*?\])?\s+([[:lower:]])</span>
</span></span></code></pre></div><p><code>.vale-styles/mystuff/ConsistentSpelling.yml</code> was used to check that common terms that I used were written consistently:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">extends</span>: <span style="color:#ae81ff">substitution</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">message</span>: <span style="color:#ae81ff">Use &#39;%s&#39; instead of &#39;%s&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">ignorecase</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">level</span>: <span style="color:#ae81ff">warning</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">swap</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">meta data</span>: <span style="color:#ae81ff">metadata</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">data set</span>: <span style="color:#ae81ff">dataset</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">data sets</span>: <span style="color:#ae81ff">datasets</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">meta model</span>: <span style="color:#ae81ff">metamodel</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">meta models</span>: <span style="color:#ae81ff">metamodels</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">timeseries</span>: <span style="color:#ae81ff">time series</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">data is</span>: <span style="color:#ae81ff">data are</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">open source</span>: <span style="color:#ae81ff">open-source</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">opensource</span>: <span style="color:#ae81ff">open-source</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">run-time</span>: <span style="color:#ae81ff">runtime</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">run time</span>: <span style="color:#ae81ff">runtime</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">front-end</span>: <span style="color:#ae81ff">front end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">front-ends</span>: <span style="color:#ae81ff">front ends</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">javascript</span>: <span style="color:#ae81ff">JavaScript</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">Java Script</span>: <span style="color:#ae81ff">JavaScript</span>
</span></span></code></pre></div><p><a href="https://github.com/errata-ai/vale">Vale</a> doesn&rsquo;t handle <a href="https://www.latex-project.org/">LaTeX</a> commands.
Thus, you also need to put the <code>detex.py</code> before the call to <a href="https://github.com/errata-ai/vale">Vale</a>.
However, once this is set up, extending rules is pretty simple and greatly helps to enforce consistency.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I hope this somewhat random list of things regarding writing documents in <a href="https://www.latex-project.org/">LaTeX</a> helps someone to improve his writing experience and the final document.Probably, many things are missing here, but there are a lot of further resources around.
One important issue here is to look for recent articles and blog posts.
Even for such an ancient tool like <a href="https://www.latex-project.org/">LaTeX</a> the ecosystem is evolving and better packages appear, others become unmaintained, and some are just not needed anymore with more modern distributions.</p>
<p>In case you have remarks, corrections, or further hints what to add here, feel free to contact me via mail.</p>
<h2 id="updates">Updates</h2>
<ul>
<li>2018-06-14: Hints for good tables added</li>
<li>2018-06-18: Fix notation for escaping periods after capital letter abbreviations. A backslash was missing.</li>
<li>2021-02-13: Updated link for the booktabs manual.</li>
</ul>]]></content></entry><entry><title>Coding Python in Neovim with IPython as a REPL</title><link rel="alternate" href="https://www.semipol.de/posts/2017/03/coding-python-in-neovim-with-ipython-as-a-repl/"/><id>https://www.semipol.de/posts/2017/03/coding-python-in-neovim-with-ipython-as-a-repl/</id><published>2017-03-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Most of the time at work I am currently doing machine learning / data science using the Python ecosystem. My editor of choice for working in Python has become Neovim, which really works well for autocompletion and linting based on Neomake, UltiSnips, deoplete and deoplete-jedi. However, one thing I have been missing was a tight integration with the IPython / Jupyter Console REPL in order to quickly experiment with new code fragments in a fashion like SLIME for Emacs: simply select a few lines of code and send them to IPython using a command / binding. Finally, I have found something that works well, which I will explain here.</summary><content type="html"><![CDATA[<p>Most of the time at work I am currently doing machine learning / data science using the <a href="https://www.python.org/">Python</a> ecosystem.
My editor of choice for working in Python has become <a href="https://neovim.io">Neovim</a>, which really works well for autocompletion and linting based on <a href="https://github.com/neomake/neomake">Neomake</a>, <a href="https://github.com/SirVer/ultisnips">UltiSnips</a>, <a href="https://github.com/Shougo/deoplete.nvim">deoplete</a> and <a href="https://github.com/zchee/deoplete-jedi">deoplete-jedi</a>.
However, one thing I have been missing was a tight integration with the <a href="https://ipython.org/">IPython</a> / <a href="https://jupyter-console.readthedocs.io/en/latest/">Jupyter Console</a> REPL in order to quickly experiment with new code fragments in a fashion like <a href="https://common-lisp.net/project/slime/">SLIME</a> for <a href="https://www.gnu.org/software/emacs/">Emacs</a>: simply select a few lines of code and send them to <a href="https://ipython.org/">IPython</a> using a command / binding.
Finally, I have found something that works well, which I will explain here.</p>
<h2 id="first-try-vim-slime">First try: vim-slime</h2>
<p>The first Vim plugin that I have been using in order to replicate a SLIME-like behavior was <a href="https://github.com/jpalardy/vim-slime">vim-slime</a>, which uses tools like screen or <a href="https://tmux.github.io/">tmux</a> to get the text into the target REPL application.
That means you have to start <a href="https://ipython.org/">IPython</a> inside <a href="https://tmux.github.io/">tmux</a> and then configure <a href="https://github.com/jpalardy/vim-slime">vim-slime</a> to connect to a specific session.
While this works reasonably, it adds a <a href="https://tmux.github.io/">tmux</a> or screen layer around your <a href="https://ipython.org/">IPython</a> experience with all the clunky keyboard shortcuts that you have to remember then.
It gets even worse if you want to use the <a href="https://neovim.io">Neovim</a> terminal, which adds another layer of escape sequences around this. Also, it feels quite weird to start <a href="https://tmux.github.io/">tmux</a> inside the <a href="https://neovim.io">Neovim</a> terminal just for this purpose.
Finally, with some changes to <a href="https://ipython.org/">IPython</a> over the time, suddenly some heuristics for sending multi-line text stopped working correctly and I assume this might happen over and over again.</p>
<h2 id="principled-approach-nvim-ipy">Principled approach: nvim-ipy</h2>
<p>Therefore, my second attempt was to try something more principled.
Since <a href="https://jupyter.org/">Jupyter</a> started to appear in the <a href="https://www.python.org/">Python</a> ecosystem, where <a href="https://ipython.org/">IPython</a> is just a Kernel and several clients can attach to a running kernel, it would be nice if there was a way for <a href="https://neovim.io">Neovim</a> to directly connect a running <a href="https://ipython.org/">IPython</a> kernel and send input there.
<a href="https://github.com/bfredl/nvim-ipy">nvim-ipy</a> implements this for <a href="https://neovim.io">Neovim</a> as a <a href="https://www.python.org/">Python</a> plugin.
However, there are several drawbacks of this particular implementation that lead me to stop using it:</p>
<ol>
<li>The implementation quality of this particular plugin is quite low and a lot of corner-cases (e.g. reconnecting to a new kernel without restarting Vim) are not handled, which reduced the user experience.</li>
<li>Getting the correct kernel in combination with virtualenvs and <a href="https://conda.io/miniconda.html">Miniconda</a> is quite complex with kernel registries etc.</li>
<li>Most important, this plugin open a buffer for the output that is produced when sending code to the <a href="https://ipython.org/">IPython</a> kernel you are connected to.
This buffer is not a usual <a href="https://ipython.org/">IPython</a> REPL that can be used easily.
So, what you have to do is to start <a href="https://jupyter-console.readthedocs.io/en/latest/">Jupyter Console</a> somewhere and connect the Vim plugin to this instance.
Consequently, you have two window representing the same kernel, but the inputs you send to this kernel via Vim and the respective outputs are only visible in the created buffer and cannot be reused in the normal console session.
That means you always have two observe two different windows and are constantly missing execute code for interactive changes in the REPL.</li>
</ol>
<h2 id="finally-ironnvim">Finally: iron.nvim</h2>
<p>With the aforementioned drawbacks, I finally moved to <a href="https://github.com/hkupty/iron.nvim">iron.nvim</a>.
This doesn&rsquo;t use the kernel API of <a href="https://jupyter.org/">Jupyter</a> but instead starts <a href="https://ipython.org/">IPython</a> inside a <a href="https://neovim.io">Neovim</a> terminal and multiple other REPLs and languages are supported, too.
This means that the additional buffer of <a href="https://github.com/bfredl/nvim-ipy">nvim-ipy</a> is gone and executed code fragments are directly available in he history of the REPL and als tmux isn&rsquo;t needed anymore.
<a href="https://github.com/hkupty/iron.nvim">iron.nvim</a> also correctly picks up <a href="https://ipython.org/">IPython</a> from <a href="https://conda.io/miniconda.html">Miniconda</a> via a correctly set <code>PATH</code> variable.</p>
<figure>
    <img loading="lazy" src="neovim-ipython.gif"
         alt="Screencast of using iron.nvim in Neovim"/> 
</figure>

<p>Btw., in case you are interested in my <a href="https://neovim.io">Neovim</a> configuration: it is available on Github: <a href="https://github.com/languitar/config-vim">languitar/config-vim</a>.</p>]]></content></entry><entry><title>Android: manually restoring apps from a TWRP backup</title><link rel="alternate" href="https://www.semipol.de/posts/2016/07/android-manually-restoring-apps-from-a-twrp-backup/"/><id>https://www.semipol.de/posts/2016/07/android-manually-restoring-apps-from-a-twrp-backup/</id><published>2016-07-30T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since an issue with the keyboard freezing for Android disk encryption was fixed in the Omnirom code base, I was able to upgrade my system again. Unfortunately, the system didn&rsquo;t boot anymore without a factory reset. Therefore, I finally found out to manually restore individual apps from a system backup performed with TWRP.</summary><content type="html"><![CDATA[<p>Since an issue with the keyboard freezing for Android disk encryption was fixed in the Omnirom code base, I was able to upgrade my system again.
Unfortunately, the system didn&rsquo;t boot anymore without a factory reset.
Therefore, I finally found out to manually restore individual apps from a system backup performed with TWRP.</p>
<p>The backup option of TWRP produces different files for the different partitions of your device.
These files are (for backups without compression) simple tar archives of the data on your phone.
In case of large volumes, the archives might be split into multi-part tar archives.
A listing of the backup directory might look like this:</p>
<pre tabindex="0"><code>boot.emmc.win
boot.emmc.win.md5
data.ext4.win000
data.ext4.win000.md5
data.ext4.win001
data.ext4.win001.md5
data.ext4.win002
data.ext4.win002.md5
data.info
recovery.log
system.ext4.win
system.ext4.win.md5
system.info
</code></pre><p>The app data is stored inside the data partition.
So the first step is to extract this partition:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>tar -xvf data.ext4.win000
</span></span></code></pre></div><p>This will result in a folder called <code>data</code> which will eventually contain the application data in the subfolder <code>data</code> (yes, same name).
In order to push data from individual application to the phone we first need to restart adb on the phone with root permissions:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>adb root
</span></span></code></pre></div><p>Afterwards, individual application data folders can be pushed to the telephone, e.g.:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>adb push data/data/com.example.app /data/data/com.example.app
</span></span></code></pre></div><p>Now the harder part begins.
Android uses a single Unix user per application.
First, the pushed files need to become owned bu the user of the application.</p>
<p>For this purpose, first the user id of the application needs to be found out.
For this purpose the application needs to be installed already.
On the phone, e.g. through <code>adb shell</code> do:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dumpsys package com.example.app | grep userId
</span></span></code></pre></div><p>This will print out the user id of the app, with which the files can be changed:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chown -R $id:$id /data/data/com.example.app
</span></span></code></pre></div><p>This is still not sufficient for the app to function properly again.
If you try to launch the app now, chances are high that it complains about SQLite databases not being readable.
This seems to be caused by SELinux, which is used by Android.
The SELinux attributes of the files need to be restore, as described <a href="https://newspaint.wordpress.com/2016/05/03/restoring-selinux-labels-after-restoring-from-data-backup-to-android/">here</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>restorecon -Rv /data/data/com.example.app
</span></span></code></pre></div><p>Finally, the app should be restored.</p>]]></content></entry><entry><title>Linux-based Home Entertainment System</title><link rel="alternate" href="https://www.semipol.de/posts/2016/05/linux-based-home-entertainment-system/"/><id>https://www.semipol.de/posts/2016/05/linux-based-home-entertainment-system/</id><published>2016-05-20T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since two or three years I am experimenting with different solutions for my personal home entertainment system. Now that the solution has become quite stable I am going to describe my current setup and its evolution in this blog post hoping that someone might find it useful.</summary><content type="html"><![CDATA[<p>Since two or three years I am experimenting with different solutions for my personal home entertainment system.
Now that the solution has become quite stable I am going to describe my current setup and its evolution in this blog post hoping that someone might find it useful.</p>
<p>Everything started with an old Android telephone that I didn&rsquo;t need anymore and the idea that online music streaming and remote control for music replay might be a nice idea.
I put XBMC (now Kodi) on that phone with some music on the SD card and a remote on my new phone and then things started to evolve.
Setting up an Android device so that it automatically powers up with XBMC running and switches off when not needed anymore worked somehow but was quite cumbersome at that time.
Also, the music on the SD card never matched my actual music library and parallel maintenance was annoying.
So I got a small NAS, put the music on that NAS and found and automatic SMB mounting solution for Android.
It worked, but sound quality of the audio jack of the phone actually wasn&rsquo;t too good and administration was annoying.
So I switched to a Raspberray Pi with XBMC and also connected it to my TV via the HDMI port.
However, XBMC was sluggish on the Pi, so I tried MPD instead, which was blazing fast but soon lacked several features with my ideas of what can be done with such a system evolving.
Therefore, I replaced my Pi and the ready-made Synology NAS with a custom-built Linux-based NAS, which is also the media center server, connected to my TV and my stereo sound system.
This is now the current state of the hardware evolution.</p>
<figure>
    <img loading="lazy" src="NAS.png"
         alt="Schematic overview of my current NAS / home entertainment system setup."/> 
</figure>

<p>On my custom-built server I am running the following software:</p>
<ul>
<li>Archlinux as the operating system</li>
<li>SMB and NFS for file sharing to other clients</li>
<li><a href="https://www.mopidy.com/">Mopidy</a> as the media center connected to an external USB audio interface (Behringer U-Control UCA202 USB Audio Interface)</li>
<li><a href="https://github.com/badaix/snapcast">snapcast</a> for multi-room audio replay from Mopidy</li>
<li><a href="https://kodi.tv/">Kodi</a> for videos</li>
<li><a href="https://github.com/languitar/autosuspend">autosuspend</a> for automatic hibernation</li>
</ul>
<p>I decided to use two different solutions for audio and video in parallel because:</p>
<ul>
<li>Mopidy has working <a href="https://github.com/mopidy/mopidy-spotify">Spotify support</a></li>
<li>Can be completely controlled without requiring a TV for certain</li>
<li>Further streaming plugins for web radio etc. exist</li>
<li>On the other hand, Kodi is very nice for handling video tasks</li>
</ul>
<p>As remote controls for Mopidy I use the command-line based <a href="http://rybczak.net/ncmpcpp/">ncmpcpp</a> on OS X and Linux and <a href="http://remotedy.com/">Remotedy</a> for Android, which works slightly better than MPD-based clients.
For Kodi most things can be done with the official Android remote control <a href="http://kodi.wiki/view/Kore">Kore</a>.
Only for some URL sharing tasks <a href="http://yatse.tv/redmine/projects/yatse">Yatse</a> works better.</p>
<p>While Mopidy can be started as a system service, I opted to start Kodi as an autostart application of a special user of my system, which is automatically logged in.
That way, I can also use the system as a normal computer using a wireless keyboard.
I also had to configure pulse to ignore the external USB soundcard so that Mopidy / snapcast could use it without problems.</p>
<p>Finally, snapcast is the newest addition to the setup.
It allows synchronized replay of audio on multiple devices as e.g. Sonos but for free.
Mopidy outputs the audio to snapcast for distributed replay and one snapcast client already runs on the NAS to feed the external audio interface.
I have set up a second client on the Raspberry Pi (also running Archlinux ARM) and connected it to other loudspeakers in my kitchen.
The snapclient is started as a system service and automatically (re-)connects to the server so that just switching on the system results in an instant replay.
An Android app allows to control which clients play at which volume level and clients can even be switched between different streams.
This works really well and I didn&rsquo;t have any issues with snapcast so far.</p>]]></content></entry><entry><title>autosuspend: Automatically Suspending a Server on Inactivity</title><link rel="alternate" href="https://www.semipol.de/posts/2015/11/autosuspend-automatically-suspending-a-server-on-inactivity/"/><id>https://www.semipol.de/posts/2015/11/autosuspend-automatically-suspending-a-server-on-inactivity/</id><published>2015-11-14T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>A few months ago I sold my existing basic Synology NAS and built my own one based on a power-efficient Intel CPU inside a mini ITX system with a usual Linux as the operating system. This provided me with a lot more flexibility and e.g. possibilities to encrypt my data properly. One thing I needed for this custom solution was a daemon to suspend the system in case of inactivity to further reduce the power consumption. I found a few existing scripts online, started using one of them, but soon had to modify it deeply until it was general enough to suit my needs. Today, I finally took the time to clean up the last issues in the code base and the autosuspend project is now available on Github.</summary><content type="html"><![CDATA[<p>A few months ago I sold my existing basic Synology NAS and built my own one based on a power-efficient Intel CPU inside a mini ITX system with a usual Linux as the operating system.
This provided me with a lot more flexibility and e.g. possibilities to encrypt my data properly.
One thing I needed for this custom solution was a daemon to suspend the system in case of inactivity to further reduce the power consumption.
I found a few existing scripts online, started using one of them, but soon had to modify it deeply until it was general enough to suit my needs.
Today, I finally took the time to clean up the last issues in the code base and the <a href="https://github.com/languitar/autosuspend">autosuspend</a> project is now available on Github.</p>
<p><code>autosuspend</code> periodically checks a running Linux system for certain conditions which shall prevent the system from going to sleep.
Such conditions can be logged in users, external TCP connections, music playing on MPD, X11 activity etc.
In case the configured checks did not indicate activity for a certain amount of time, the system is automatically suspended.
You should configure Wake-on-LAN for being able to bring the system back up in case you need it again.</p>
<p><code>autosuspend</code> is implemented in Python 3, all checks are configurable via configuration file and custom checks can be added easily.
The repository includes a systemd unit which I use to run the daemon on my Archlinux setup.
For Archlinux, there is also a <a href="https://aur.archlinux.org/packages/autosuspend/">PKGBUILD on AUR</a>.</p>
<p>I&rsquo;d be glad if someone finds this script useful, too.
In case of issues, please use the <a href="https://github.com/languitar/autosuspend/issues">issue tracking in the Github project</a>.</p>]]></content></entry><entry><title>Plotting the Separating Hyperplane of an SVM in 3D with Matplotlib</title><link rel="alternate" href="https://www.semipol.de/posts/2015/10/plotting-the-separating-hyperplane-of-an-svm-in-3d-with-matplotlib/"/><id>https://www.semipol.de/posts/2015/10/plotting-the-separating-hyperplane-of-an-svm-in-3d-with-matplotlib/</id><published>2015-10-29T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I have been struggling how to plot the separating hyperplane of an SVM (a One-class SVM in my case) in a 3D space using matplotlib. There was no apparent way how to convert the decision function output into something that one of the 3D plotting functions could deal with. Fortunately I found a solution which I am going to share in case someone wants to do the same.</summary><content type="html"><![CDATA[<p>I have been struggling how to plot the separating hyperplane of an SVM (a One-class SVM in my case) in a 3D space using <a href="http://matplotlib.org">matplotlib</a>.
There was no apparent way how to convert the decision function output into something that one of the 3D plotting functions could deal with.
Fortunately I found a solution which I am going to share in case someone wants to do the same.</p>
<p>The solution is based on sampling the 3D space and computing a distance to the separating hyperplane for each sample.
Afterwards, I derived the isosurface at distance 0 using the <a href="http://scikit-image.org/docs/dev/auto_examples/plot_marching_cubes.html">marching cubes implementation in <code>scikit-image</code></a>.
The resulting mesh can be plotted using existing methods in matplotlib.
This is an example of this technique (based on the <a href="http://scikit-learn.org/stable/auto_examples/svm/plot_oneclass.html">2D example for the One-class SVM in scikit-learn</a>):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> matplotlib <span style="color:#f92672">import</span> cm
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> mpl_toolkits.mplot3d <span style="color:#f92672">import</span> axes3d
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> mpl_toolkits.mplot3d.art3d <span style="color:#f92672">import</span> Poly3DCollection
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> skimage <span style="color:#f92672">import</span> measure
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> sklearn <span style="color:#f92672">import</span> svm
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> matplotlib.font_manager
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> matplotlib.patches <span style="color:#66d9ef">as</span> mpatches
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> matplotlib.pyplot <span style="color:#66d9ef">as</span> plt
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> numpy <span style="color:#66d9ef">as</span> np
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SPACE_SAMPLING_POINTS <span style="color:#f92672">=</span> <span style="color:#ae81ff">100</span>
</span></span><span style="display:flex;"><span>TRAIN_POINTS <span style="color:#f92672">=</span> <span style="color:#ae81ff">100</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Define the size of the space which is interesting for the example</span>
</span></span><span style="display:flex;"><span>X_MIN <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>X_MAX <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>Y_MIN <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>Y_MAX <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>Z_MIN <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>Z_MAX <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generate a regular grid to sample the 3D space for various operations later</span>
</span></span><span style="display:flex;"><span>xx, yy, zz <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>meshgrid(np<span style="color:#f92672">.</span>linspace(X_MIN, X_MAX, SPACE_SAMPLING_POINTS),
</span></span><span style="display:flex;"><span>                         np<span style="color:#f92672">.</span>linspace(Y_MIN, Y_MAX, SPACE_SAMPLING_POINTS),
</span></span><span style="display:flex;"><span>                         np<span style="color:#f92672">.</span>linspace(Z_MIN, Z_MAX, SPACE_SAMPLING_POINTS))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generate training data by using a random cluster and copying it to various</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># places in the space</span>
</span></span><span style="display:flex;"><span>X <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.3</span> <span style="color:#f92672">*</span> np<span style="color:#f92672">.</span>random<span style="color:#f92672">.</span>randn(TRAIN_POINTS, <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>X_train <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>r_[X <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>, X <span style="color:#f92672">-</span> <span style="color:#ae81ff">2</span>, X <span style="color:#f92672">+</span> [<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">0</span>]]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generate some regular novel observations using the same method and</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># distribution properties</span>
</span></span><span style="display:flex;"><span>X <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.3</span> <span style="color:#f92672">*</span> np<span style="color:#f92672">.</span>random<span style="color:#f92672">.</span>randn(<span style="color:#ae81ff">20</span>, <span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>X_test <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>r_[X <span style="color:#f92672">+</span> <span style="color:#ae81ff">2</span>, X <span style="color:#f92672">-</span> <span style="color:#ae81ff">2</span>, X <span style="color:#f92672">+</span> [<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">0</span>]]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generate some abnormal novel observations using a different distribution</span>
</span></span><span style="display:flex;"><span>X_outliers <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>random<span style="color:#f92672">.</span>uniform(low<span style="color:#f92672">=-</span><span style="color:#ae81ff">4</span>, high<span style="color:#f92672">=</span><span style="color:#ae81ff">4</span>, size<span style="color:#f92672">=</span>(<span style="color:#ae81ff">20</span>, <span style="color:#ae81ff">3</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a OneClassSVM instance and fit it to the data</span>
</span></span><span style="display:flex;"><span>clf <span style="color:#f92672">=</span> svm<span style="color:#f92672">.</span>OneClassSVM(nu<span style="color:#f92672">=</span><span style="color:#ae81ff">0.1</span>, kernel<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;rbf&#34;</span>, gamma<span style="color:#f92672">=</span><span style="color:#ae81ff">0.1</span>)
</span></span><span style="display:flex;"><span>clf<span style="color:#f92672">.</span>fit(X_train)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Predict the class of the various input created before</span>
</span></span><span style="display:flex;"><span>y_pred_train <span style="color:#f92672">=</span> clf<span style="color:#f92672">.</span>predict(X_train)
</span></span><span style="display:flex;"><span>y_pred_test <span style="color:#f92672">=</span> clf<span style="color:#f92672">.</span>predict(X_test)
</span></span><span style="display:flex;"><span>y_pred_outliers <span style="color:#f92672">=</span> clf<span style="color:#f92672">.</span>predict(X_outliers)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># And compute classification error frequencies</span>
</span></span><span style="display:flex;"><span>n_error_train <span style="color:#f92672">=</span> y_pred_train[y_pred_train <span style="color:#f92672">==</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>size
</span></span><span style="display:flex;"><span>n_error_test <span style="color:#f92672">=</span> y_pred_test[y_pred_test <span style="color:#f92672">==</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>size
</span></span><span style="display:flex;"><span>n_error_outliers <span style="color:#f92672">=</span> y_pred_outliers[y_pred_outliers <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Calculate the distance from the separating hyperplane of the SVM for the</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># whole space using the grid defined in the beginning</span>
</span></span><span style="display:flex;"><span>Z <span style="color:#f92672">=</span> clf<span style="color:#f92672">.</span>decision_function(np<span style="color:#f92672">.</span>c_[xx<span style="color:#f92672">.</span>ravel(), yy<span style="color:#f92672">.</span>ravel(), zz<span style="color:#f92672">.</span>ravel()])
</span></span><span style="display:flex;"><span>Z <span style="color:#f92672">=</span> Z<span style="color:#f92672">.</span>reshape(xx<span style="color:#f92672">.</span>shape)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a figure with axes for 3D plotting</span>
</span></span><span style="display:flex;"><span>fig <span style="color:#f92672">=</span> plt<span style="color:#f92672">.</span>figure()
</span></span><span style="display:flex;"><span>ax <span style="color:#f92672">=</span> fig<span style="color:#f92672">.</span>gca(projection<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;3d&#39;</span>)
</span></span><span style="display:flex;"><span>fig<span style="color:#f92672">.</span>suptitle(<span style="color:#e6db74">&#34;Novelty Detection&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Plot the different input points using 3D scatter plotting</span>
</span></span><span style="display:flex;"><span>b1 <span style="color:#f92672">=</span> ax<span style="color:#f92672">.</span>scatter(X_train[:, <span style="color:#ae81ff">0</span>], X_train[:, <span style="color:#ae81ff">1</span>], X_train[:, <span style="color:#ae81ff">2</span>], c<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;white&#39;</span>)
</span></span><span style="display:flex;"><span>b2 <span style="color:#f92672">=</span> ax<span style="color:#f92672">.</span>scatter(X_test[:, <span style="color:#ae81ff">0</span>], X_test[:, <span style="color:#ae81ff">1</span>], X_test[:, <span style="color:#ae81ff">2</span>], c<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;green&#39;</span>)
</span></span><span style="display:flex;"><span>c <span style="color:#f92672">=</span> ax<span style="color:#f92672">.</span>scatter(X_outliers[:, <span style="color:#ae81ff">0</span>], X_outliers[:, <span style="color:#ae81ff">1</span>], X_outliers[:, <span style="color:#ae81ff">2</span>], c<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;red&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Plot the separating hyperplane by recreating the isosurface for the distance</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># == 0 level in the distance grid computed through the decision function of the</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># SVM. This is done using the marching cubes algorithm implementation from</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># scikit-image.</span>
</span></span><span style="display:flex;"><span>verts, faces <span style="color:#f92672">=</span> measure<span style="color:#f92672">.</span>marching_cubes(Z, <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Scale and transform to actual size of the interesting volume</span>
</span></span><span style="display:flex;"><span>verts <span style="color:#f92672">=</span> verts <span style="color:#f92672">*</span> \
</span></span><span style="display:flex;"><span>    [X_MAX <span style="color:#f92672">-</span> X_MIN, Y_MAX <span style="color:#f92672">-</span> Y_MIN, Z_MAX <span style="color:#f92672">-</span> Z_MIN] <span style="color:#f92672">/</span> SPACE_SAMPLING_POINTS
</span></span><span style="display:flex;"><span>verts <span style="color:#f92672">=</span> verts <span style="color:#f92672">+</span> [X_MIN, Y_MIN, Z_MIN]
</span></span><span style="display:flex;"><span><span style="color:#75715e"># and create a mesh to display</span>
</span></span><span style="display:flex;"><span>mesh <span style="color:#f92672">=</span> Poly3DCollection(verts[faces],
</span></span><span style="display:flex;"><span>                        facecolor<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;orange&#39;</span>, edgecolor<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;gray&#39;</span>, alpha<span style="color:#f92672">=</span><span style="color:#ae81ff">0.3</span>)
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>add_collection3d(mesh)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Some presentation tweaks</span>
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_xlim((<span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">5</span>))
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_ylim((<span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">5</span>))
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_zlim((<span style="color:#f92672">-</span><span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">5</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_xlabel(<span style="color:#e6db74">&#34;X&#34;</span>)
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_ylabel(<span style="color:#e6db74">&#34;Y&#34;</span>)
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_zlabel(<span style="color:#e6db74">&#34;Z&#34;</span>)
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>legend([mpatches<span style="color:#f92672">.</span>Patch(color<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;orange&#39;</span>, alpha<span style="color:#f92672">=</span><span style="color:#ae81ff">0.3</span>), b1, b2, c],
</span></span><span style="display:flex;"><span>          [<span style="color:#e6db74">&#34;learned frontier&#34;</span>, <span style="color:#e6db74">&#34;training observations&#34;</span>,
</span></span><span style="display:flex;"><span>           <span style="color:#e6db74">&#34;new regular observations&#34;</span>, <span style="color:#e6db74">&#34;new abnormal observations&#34;</span>],
</span></span><span style="display:flex;"><span>          loc<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;lower left&#34;</span>,
</span></span><span style="display:flex;"><span>          prop<span style="color:#f92672">=</span>matplotlib<span style="color:#f92672">.</span>font_manager<span style="color:#f92672">.</span>FontProperties(size<span style="color:#f92672">=</span><span style="color:#ae81ff">11</span>))
</span></span><span style="display:flex;"><span>ax<span style="color:#f92672">.</span>set_title(
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;error train: </span><span style="color:#e6db74">%d</span><span style="color:#e6db74">/200 ; errors novel regular: </span><span style="color:#e6db74">%d</span><span style="color:#e6db74">/40 ; &#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;errors novel abnormal: </span><span style="color:#e6db74">%d</span><span style="color:#e6db74">/40&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">%</span> (n_error_train, n_error_test, n_error_outliers))
</span></span><span style="display:flex;"><span>fig<span style="color:#f92672">.</span>show()
</span></span></code></pre></div><p>The resulting plot will look like this:</p>
<figure>
    <img loading="lazy" src="3Dsvm.png"
         alt="A plot showing the separating hyperplane for a One-class SVM on a generated data set"/> 
</figure>]]></content></entry><entry><title>Managing dotfiles with homeshick</title><link rel="alternate" href="https://www.semipol.de/posts/2015/09/managing-dotfiles-with-homeshick/"/><id>https://www.semipol.de/posts/2015/09/managing-dotfiles-with-homeshick/</id><published>2015-09-27T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I am constantly using several different computers (home, work, servers) and synchronizing the configurations of the shell and all other command line utilities I am using across these computers can be a bit challenging. Manually copying everything including all changes constantly appearing in the different configuration files is the worst solution. So I have been using a repository on my self-hosted Seafile server with all the required dotfiles and a custom setup script to create the required symlinks to these files. This worked quite well but also had several drawbacks. Therefore, I recently switched to homeshick to manage my dotfiles and, during this process, published most of my dotfiles on GitHub.</summary><content type="html"><![CDATA[<p>I am constantly using several different computers (home, work, servers) and synchronizing the configurations of the shell and all other command line utilities I am using across these computers can be a bit challenging.
Manually copying everything including all changes constantly appearing in the different configuration files is the worst solution.
So I have been using a repository on my self-hosted <a href="https://www.seafile.com/en/home/">Seafile server</a> with all the required dotfiles and a custom setup script to create the required symlinks to these files.
This worked quite well but also had several drawbacks.
Therefore, I recently switched to homeshick to manage my dotfiles and, during this process, published most of my dotfiles on <a href="https://github.com/">GitHub</a>.</p>
<p>Concerning the Seafile solution, the most prevalent issues why I wanted to switch away from this solution were:</p>
<ul>
<li>Lack of explicitness in the versioning system compared to e.g. Git:
There are no comments for changes and therefore it is sometimes hard to figure out what changed.</li>
<li>Setup effort: I do not want to run Seafile on every client I am working on.
However, Git is usually available on every client and doesn&rsquo;t require a daemon.</li>
<li>I do not want to provide credentials to my Seafile server just to use some dotfiles on a semi-trusted host.</li>
</ul>
<p>For these reasons I was looking for a different solution, but this was never really an urgent issue.</p>
<p>Several months ago I stumbled across <a href="https://github.com/technicalpickles/homesick">homesick</a>, which synchronizes dotfiles using Git.
I talked to a colleague about this, we both liked the idea, and then more or less forgot about this issue until a few weeks ago.
At that time, the colleague told me that he had looked at homesick, decided against a Ruby dependency just for managing dotfiles and started using <a href="https://github.com/andsens/homeshick">homeshick</a> (mind the H), which is more or less a clone of homesick written in bash.
Therefore, I also gave this a go and finally moved all dotfiles to the new system.</p>
<p>The first issue when starting to use homeshick or homesick is to decide how many git repositories (called castles) to use.
Since several parts of my configuration differ between private computers, work hosts and servers, I decided to use a modular approach and created a castle for each program I use.
Configuring the castles worked like expected apart from the fact that I had to fix some symlinks manually, which already existed from my previous solution.
There is no way for homeshick to understand which symlinks to keep and which to replace in this situation, so I can&rsquo;t blame anyone about this.</p>
<p>Since I spent some time to configure my environment and people sometimes ask about my configuration files I decided to host them publicly on GitHub.
At least all configuration files where I could remove sensitive information are now on <a href="https://github.com/search?q=user%3Alanguitar+config-">my GitHub account as repositories starting with the &ldquo;config-&rdquo; prefix</a>.
Feel free to use these configurations and give feedback on them.</p>
<p>So far I am quite happy with the solution and everything works as expected.
I did not investigate in how to manage the different castles, e.g. using repo or <a href="https://github.com/andsens/homeshick/wiki/Myrepos">myrepos as proposed by the homeshick authors</a>, but maybe I will try this out in the futures.</p>]]></content></entry><entry><title>A Python logging broadcast handler</title><link rel="alternate" href="https://www.semipol.de/posts/2015/09/a-python-logging-broadcast-handler/"/><id>https://www.semipol.de/posts/2015/09/a-python-logging-broadcast-handler/</id><published>2015-09-12T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I have implemented a handler for the Python logging system called broadcast-logging which sends out the log messages via UDP broadcasts. This might be useful in case you want to sporadically listen to certain log messages, e.g. from a server, without setting up a special service for this purpose. Since broadcasts are sent via UDP and no explicit connections are set up, this might also be useful in case you want to debug TCP-connection-related issues while preventing artificial connections for the debugging session.</summary><content type="html"><![CDATA[<p>I have implemented a handler for the <a href="https://docs.python.org/3/library/logging.html">Python logging system</a> called <a href="https://github.com/languitar/broadcast-logging">broadcast-logging</a> which sends out the log messages via UDP broadcasts.
This might be useful in case you want to sporadically listen to certain log messages, e.g. from a server, without setting up a special service for this purpose.
Since broadcasts are sent via UDP and no explicit connections are set up, this might also be useful in case you want to debug TCP-connection-related issues while preventing artificial connections for the debugging session.</p>
<p>After installing the Python package, you can use the provided logging handler by configuring the logging system appropriately, e.g. via a config file like the following one:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#66d9ef">[loggers]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">keys</span><span style="color:#f92672">=</span><span style="color:#e6db74">root</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[handlers]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">keys</span><span style="color:#f92672">=</span><span style="color:#e6db74">broadcastHandler</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[formatters]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">keys</span><span style="color:#f92672">=</span><span style="color:#e6db74">simpleFormatter</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[logger_root]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">level</span><span style="color:#f92672">=</span><span style="color:#e6db74">DEBUG</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">handlers</span><span style="color:#f92672">=</span><span style="color:#e6db74">broadcastHandler</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[handler_broadcastHandler]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">broadcastlogging.BroadcastHandler</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">level</span><span style="color:#f92672">=</span><span style="color:#e6db74">DEBUG</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">args</span><span style="color:#f92672">=</span><span style="color:#e6db74">(&#39;192.168.0.255&#39;,55555)</span>
</span></span></code></pre></div><p>In order to receive the logging messages, the <code>broadcastlogging</code> module also provides an executable which replicates the log messages in a local program. It can be launched e.g. as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>python -m broadcastlogging -h -c -b <span style="color:#e6db74">&#39;192.168.0.255&#39;</span> <span style="color:#ae81ff">55555</span>
</span></span></code></pre></div><p>For further details, please refer to the online help of the module and the <a href="https://github.com/languitar/broadcast-logging/blob/master/README.md">README file</a>.</p>
<p>The <a href="https://github.com/languitar/broadcast-logging">broadcast-logging</a> package is available on <a href="https://github.com/languitar">my GitHub account</a> and <a href="https://pypi.python.org/pypi/broadcast-logging">on PyPI</a>.
Feel free to try this out and please give feedback via <a href="https://github.com/languitar/broadcast-logging/issues">GitHub issues</a> in case of problems or enhancement ideas.</p>]]></content></entry><entry><title>matplotlib: Interactively zooming to a subplot</title><link rel="alternate" href="https://www.semipol.de/posts/2015/09/matplotlib-interactively-zooming-to-a-subplot/"/><id>https://www.semipol.de/posts/2015/09/matplotlib-interactively-zooming-to-a-subplot/</id><published>2015-09-04T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I am using matplotlib a lot for my data analysis tasks and most things work as I expect them to do. One thing that I was missing so far for interactive use was the ability to focus an individual subplot and temporarily let it fill the whole screen for deeper inspection of this plot. In case of multiple subplots, with the standard GUI elements you can zoom and move around inside each subplot (without changing their geometry), but not focus one of them individually. Therefore I came up with the following solution:</summary><content type="html"><![CDATA[<p>I am using <a href="http://matplotlib.org/">matplotlib</a> a lot for my data analysis tasks and most things work as I expect them to do.
One thing that I was missing so far for interactive use was the ability to focus an individual subplot and temporarily let it fill the whole screen for deeper inspection of this plot.
In case of multiple subplots, with the standard GUI elements you can zoom and move around inside each subplot (without changing their geometry), but not focus one of them individually.
Therefore I came up with the following solution:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">add_subplot_zoom</span>(figure):
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># temporary store for the currently zoomed axes. Use a list to work around</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># python&#39;s scoping rules</span>
</span></span><span style="display:flex;"><span>    zoomed_axes <span style="color:#f92672">=</span> [<span style="color:#66d9ef">None</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">on_click</span>(event):
</span></span><span style="display:flex;"><span>        ax <span style="color:#f92672">=</span> event<span style="color:#f92672">.</span>inaxes
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> ax <span style="color:#f92672">is</span> <span style="color:#66d9ef">None</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># occurs when a region not in an axis is clicked...</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># we want to allow other navigation modes as well. Only act in case</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># shift was pressed and the correct mouse button was used</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> event<span style="color:#f92672">.</span>key <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#39;shift&#39;</span> <span style="color:#f92672">or</span> event<span style="color:#f92672">.</span>button <span style="color:#f92672">!=</span> <span style="color:#ae81ff">1</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> zoomed_axes[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">is</span> <span style="color:#66d9ef">None</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># not zoomed so far. Perform zoom</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># store the original position of the axes</span>
</span></span><span style="display:flex;"><span>            zoomed_axes[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">=</span> (ax, ax<span style="color:#f92672">.</span>get_position())
</span></span><span style="display:flex;"><span>            ax<span style="color:#f92672">.</span>set_position([<span style="color:#ae81ff">0.1</span>, <span style="color:#ae81ff">0.1</span>, <span style="color:#ae81ff">0.85</span>, <span style="color:#ae81ff">0.85</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># hide all the other axes...</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> axis <span style="color:#f92672">in</span> event<span style="color:#f92672">.</span>canvas<span style="color:#f92672">.</span>figure<span style="color:#f92672">.</span>axes:
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span> axis <span style="color:#f92672">is</span> <span style="color:#f92672">not</span> ax:
</span></span><span style="display:flex;"><span>                    axis<span style="color:#f92672">.</span>set_visible(<span style="color:#66d9ef">False</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># restore the original state</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            zoomed_axes[<span style="color:#ae81ff">0</span>][<span style="color:#ae81ff">0</span>]<span style="color:#f92672">.</span>set_position(zoomed_axes[<span style="color:#ae81ff">0</span>][<span style="color:#ae81ff">1</span>])
</span></span><span style="display:flex;"><span>            zoomed_axes[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">=</span> <span style="color:#66d9ef">None</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># make other axes visible again</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> axis <span style="color:#f92672">in</span> event<span style="color:#f92672">.</span>canvas<span style="color:#f92672">.</span>figure<span style="color:#f92672">.</span>axes:
</span></span><span style="display:flex;"><span>                axis<span style="color:#f92672">.</span>set_visible(<span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># redraw to make changes visible.</span>
</span></span><span style="display:flex;"><span>        event<span style="color:#f92672">.</span>canvas<span style="color:#f92672">.</span>draw()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    figure<span style="color:#f92672">.</span>canvas<span style="color:#f92672">.</span>mpl_connect(<span style="color:#e6db74">&#39;button_press_event&#39;</span>, on_click)
</span></span></code></pre></div><p>Applying this method to a figure will allow you to use <code>Shift+Click</code> to let a single subplot fill the whole canvas and a second click of this kind will restore the original state.
This solution is partially based on the Stackoverflow question <a href="https://stackoverflow.com/questions/9012081/matplotlib-grab-single-subplot-from-multiple-subplots">Matplotlib: Grab Single Subplot from Multiple Subplots</a> but improves it for several corner cases.
Still some issues remain.
I couldn&rsquo;t find out how to get the state of the usual navigation buttons in the event handler.
Therefore the code might interfere with the other navigation operations and also the home button might not work as expected.
In case someone find out, please let me know.</p>]]></content></entry><entry><title>pass-git-helper: Integrating the pass password manager with git</title><link rel="alternate" href="https://www.semipol.de/posts/2015/09/pass-git-helper-integrating-the-pass-password-manager-with-git/"/><id>https://www.semipol.de/posts/2015/09/pass-git-helper-integrating-the-pass-password-manager-with-git/</id><published>2015-09-03T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I am using password managers since a long time to maintain secure and individual password for different online services. One thing that always bothered me was the missing integration of these password managers with different applications. I started my journey with password managers using KeePassX but recently switched to pass (the standard unix password manager) due to the inherent command line nature and therefore much better integration and remote usage possibilities. Still, there was no easy way to integrate pass with Git (for those repositories where SSH key authentication is not possible) and until recently I still used kwallet as the backend for Git, with all the hassles of duplicated data. To improve on this situation I finally took some time and implemented an adapter between Git and pass: pass-git-helper.</summary><content type="html"><![CDATA[<p>I am using password managers since a long time to maintain secure and individual password for different online services.
One thing that always bothered me was the missing integration of these password managers with different applications.
I started my journey with password managers using <a href="https://www.keepassx.org">KeePassX</a> but recently switched to <a href="http://www.passwordstore.org/">pass (the standard unix password manager)</a> due to the inherent command line nature and therefore much better integration and remote usage possibilities.
Still, there was no easy way to integrate pass with <a href="https://git-scm.com/">Git</a> (for those repositories where SSH key authentication is not possible) and until recently I still used kwallet as the backend for Git, with all the hassles of duplicated data.
To improve on this situation I finally took some time and implemented an adapter between Git and pass: <a href="https://github.com/languitar/pass-git-helper">pass-git-helper</a>.</p>
<p>pass-git-helper is a Python script which implements the <a href="https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html">Git credential API</a> to act as a credential helper.
Since Git requests credentials using the host name and the pass database is usually not organized this way, some kind of adjustment of these concepts is required.
My basic design decision with respect to this issue was that I did not want to artificially structure my password database just to match the Git host concept.
Therefore I opted for a mapping-based solution.
In order to use pass-git-helper you need to specify how hosts are mapped to entries in your password store using a file, usually called <code>~/.git-pass-mapping</code>, which might look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#66d9ef">[github.com]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">target</span><span style="color:#f92672">=</span><span style="color:#e6db74">dev/github</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[*.fooo-bar.*]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">target</span><span style="color:#f92672">=</span><span style="color:#e6db74">dev/fooo-bar</span>
</span></span></code></pre></div><p>Additionally, the helper needs to be configured inside Git, e.g. using:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>git config credential.helper <span style="color:#e6db74">&#39;!pass-git-helper $@&#39;</span>
</span></span></code></pre></div><p>As usual for pass, the first line of a password store entry is assumed to contain the password and the second line is interpreted as the user name, if present.</p>
<p>Git credential helper can also offer abilities to update saved credentials or store completely new ones.
This is currently not supported, but I&rsquo;d be happy to integrate such a feature if desired.</p>
<p><a href="https://github.com/languitar/pass-git-helper">pass-git-helper is available on GitHub</a> and licensed as LGPLv3+.
I&rsquo;d be glad to receive some feedback and hope this little helper is useful for someone.</p>]]></content></entry><entry><title>New Site and Static Site Generators</title><link rel="alternate" href="https://www.semipol.de/posts/2015/07/new-site-and-static-site-generators/"/><id>https://www.semipol.de/posts/2015/07/new-site-and-static-site-generators/</id><published>2015-07-19T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>For several years I have been using Wordpress as a platform for my blog. However, I never really needed anything dynamic. The amount of comments was very low and apart from that, I did nothing fancy which required dynamic content. Additionally, I was kind of tired to install Wordpress updates over and over again. So I moved this blog to a static site generator to completely get rid of Wordpress, comparable to what I did a few weeks ago with my photography portfolio.</summary><content type="html"><![CDATA[<p>For several years I have been using Wordpress as a platform for my blog.
However, I never really needed anything dynamic.
The amount of comments was very low and apart from that, I did nothing fancy which required dynamic content.
Additionally, I was kind of tired to install Wordpress updates over and over again.
So I moved this blog to a static site generator to completely get rid of Wordpress, comparable to <a href="https://www.johanneswienke.de/blog/2015/06/19/new-site.html" title="New Site with New Technology">what I did a few weeks ago</a> with my <a href="https://www.johanneswienke.de">photography portfolio</a>.</p>
<p>For my portfolio I have used <a href="http://jekyllrb.com">Jekyll</a> as a well known and easily maintainable static site generator.
I am quite happy with how things worked out for that site but there were a few things which led me to try out something different for the blog:</p>
<ul>
<li>While everything works very easily with Jekyll, from a modelling perspective, some aspects feel a bit ad hoc and a bit more structure and a clearer data model could be interesting.</li>
<li>Jekyll is written in Ruby and I am actually much more fluent in Python, so I wanted to give a Python-based generator a go.</li>
<li>I also just wanted to try something different to get an impression of what other static site generators do and are capable of.</li>
</ul>
<p>With that in mind I explored pythonic static site generators.
First stop here was the quite popular <a href="http://blog.getpelican.com">Pelican</a>.
I didn&rsquo;t notice any considerable technological improvement compared to Jekyll apart from being implemented in Python.
Also, most existing templates looked worse then for Jekyll, so I dropped Pelican.</p>
<p>Having experience with writing technical documentation using the <a href="http://sphinx-doc.org/">Sphinx documentation generator</a> I had the idea that it might be nice to have a blogging platform based on Sphinx.
Sphinx offers a lot of semantic additions to the usual reStructured Text repertoire, which makes it quite appealing on first sight.
Indeed, there are blogging platforms based on Sphinx and I started to explore <a href="http://tinkerer.me/index.html">Tinkerer</a>.
The problem I had with Tinkerer is that things which are easily possible with e.g. Jekyll were actually a nightmare to realize using Tinkerer because of the much more rigid structure of the processing backend.
One example is adding a teaser image per post.
This is not directly supported by Tinkerer and I would have had to implement an extension just for this purpose.
In Jekyll I can just use an item in the front matter and access it in the post list template.
Therefore, I also dropped Tinkerer.</p>
<p>In the end, I decided to use <a href="https://middlemanapp.com/">Middleman</a> for this site, a Ruby-based solution again. ;)
Middleman provides a lot of flexibility while still being easily usable and maintainable.
It is not only intended for blogging and e.g. adding post images was a matter of a few lines of template code.
So this works quite well.
Sometimes I had to dig a bit deeper into the documentation or the forum to understand some aspects, but generally, the documentation quality is good and the system is quite understandable.
I have decided to use <a href="http://kramdown.gettalong.org/">kramdown</a> as the markdown engine because of the richer feature set like definition lists.</p>
<p>For theming I decided to start a new theme more or less from scratch instead of using an existing once to avoid a lot of the overhead available in the existing themes.
The HTML code uses modern semantic HTML 5 elements like <code>article</code>, <code>section</code> or <code>nav</code> and CSS uses level 3 features.
The layout scales to portable devices using CSS media queries.
I tried to focus on the article contents and removed a lot of the previously existing sidebars etc.</p>
]]></content></entry><entry><title>Letting Enigmail use gpg-agent for passphrase caching on OSX</title><link rel="alternate" href="https://www.semipol.de/posts/2015/05/letting-enigmail-use-gpg-agent-for-passphrase-caching-on-osx/"/><id>https://www.semipol.de/posts/2015/05/letting-enigmail-use-gpg-agent-for-passphrase-caching-on-osx/</id><published>2015-05-03T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since one of the recent upgrades of Enigmail (the GPG extension for Thunderbird) and completely switching to GPG version 2 on my Macbook I ended up with the situation that Enigmail did not cache the key passphrases anymore and I had to enter them over and over again. This is caused by the fact that GPG2 requires to use gpg-agent and Enigmail&rsquo;s internal passphrase management cannot be used anymore. Therefore, a setup is required that enabled the gpg processes spawned by Enigmail to talk to a running gpg-agent instance.</summary><content type="html"><![CDATA[<p>Since one of the recent upgrades of <a href="https://www.enigmail.net/home/index.php">Enigmail</a> (the <a href="https://www.gnupg.org/">GPG</a> extension for <a href="https://www.mozilla.org/en-US/thunderbird/">Thunderbird</a>) and completely switching to GPG version 2 on my Macbook I ended up with the situation that Enigmail did not cache the key passphrases anymore and I had to enter them over and over again. This is caused by the fact that GPG2 requires to use <code>gpg-agent</code> and Enigmail&rsquo;s internal passphrase management cannot be used anymore. Therefore, a setup is required that enabled the <code>gpg</code> processes spawned by Enigmail to talk to a running <code>gpg-agent</code> instance.</p>
<p><code>gpg-agent</code> is a small utility daemon that handles passphrase caching. A <code>gpg</code> process can talk to a running <code>gpg-agent</code> once it knows where the agent can be reached. This information is obtained from the environment variable <code>GPG_AGENT_INFO</code>. The content of this variable looks something like this: <code>/Users/youruser/.gnupg/S.gpg-agent:38959:1</code>. In case of programs started in a shell, starting <code>gpg-agent</code> on demand and exporting the correct environment variable is easily possible with a few lines of shell configuration code. However, Thunderbird and therefore also Enigmail are usually started via the OSX GUI and not from within a shell. Therefore, the <code>GPG_AGENT_INFO</code> variable needs to be exported by the process which manages launching graphical programs (via Spotlight). This is <code>launchd</code> on OSX. Fortunately, <code>launchd</code> has command line options to control the environment it uses to start new processes, which we can take advantage of.</p>
<p>For the setup I am using now, I start a <code>gpg-agent</code> process with my graphical login. To do so, I have adapted <a href="http://www.weinschenker.name/2013-10-08/use-gpgtools-for-ssh-logins-on-mac-os-x/">this solution</a>, which starts <code>gpg-agent</code> at login, but does not export the environment variables inside <code>launchd</code>.</p>
<p>The first step is to create a plist-file, which is a configuration for <code>launchd</code> instructing it to start <code>gpg-agent</code> at login. Create <code>~/Library/LaunchAgents/org.gnupg.gpg-agent.plist</code> with the following contents (shamelessly stolen from the aforementioned blog post):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;xml</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.0&#34;</span> <span style="color:#a6e22e">encoding=</span><span style="color:#e6db74">&#34;UTF-8&#34;</span><span style="color:#960050;background-color:#1e0010">?</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;DOCTYPE</span> <span style="color:#960050;background-color:#1e0010">plist</span> <span style="color:#960050;background-color:#1e0010">PUBLIC</span> <span style="color:#960050;background-color:#1e0010">&#34;-//Apple//DTD</span> <span style="color:#960050;background-color:#1e0010">PLIST</span> <span style="color:#960050;background-color:#1e0010">1.0//EN&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050;background-color:#1e0010">&#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;plist</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.0&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;dict&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;key&gt;</span>Label<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;string&gt;</span>org.gnupg.gpg-agent<span style="color:#f92672">&lt;/string&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;key&gt;</span>ProgramArguments<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;array&gt;</span>
</span></span><span style="display:flex;"><span>       <span style="color:#f92672">&lt;string&gt;</span>/Users/youruser/bin/start-gpg-agent.sh<span style="color:#f92672">&lt;/string&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;/array&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;key&gt;</span>RunAtLoad<span style="color:#f92672">&lt;/key&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;true/&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;/dict&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/plist&gt;</span>
</span></span></code></pre></div><p>Replace <code>youruser</code> with your actual OSX username. <code>launchd</code> automatically processes plist files from the <code>~/Library/LaunchAgents</code> directory.</p>
<p>As the plist only dispatches to a shell script called <code>/Users/youruser/bin/start-gpg-agent.sh</code>, we need to create this script, which does the real magic of starting <code>gpg-agent</code> and exporting the variables. Create it with the following contents (adapt the <code>gpg-agent</code> path to your installation):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">if</span> test -f <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.gpg-agent-info&#34;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>   kill -0 <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>cut -d: -f <span style="color:#ae81ff">2</span> <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.gpg-agent-info&#34;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> 2&gt;/dev/null
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;already running&#34;</span> &gt; /dev/null
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    /usr/local/bin/gpg-agent -c --daemon --write-env-file &gt; /dev/null
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>HOME<span style="color:#e6db74">}</span><span style="color:#e6db74">/.gpg-agent-info&#34;</span> <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    socket<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>cut -d<span style="color:#f92672">=</span> -f2 <span style="color:#e6db74">&#34;</span>$HOME<span style="color:#e6db74">/.gpg-agent-info&#34;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    launchctl setenv GPG_AGENT_INFO <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>socket<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;gpg-agent did not write info file&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span></code></pre></div><p>The first part of the script starts <code>gpg-agent</code> in case no other <code>gpg-agent</code> instance is already running. A running instance of <code>gpg-agent</code> puts its connection information in a file called <code>~/.gpg-agent-info</code> in case it was started with the <code>--write-env-file</code> option. The second half of the shell script parses this file and exports the <code>GPG_AGENT_INFO</code> variable inside <code>launchd</code> with the <code>launchctl setenv</code> command. Afterwards, every graphically launched program has knowledge about the running <code>gpg-agent</code> instance and can connect to it.</p>
<p>In case a <code>gpg</code> process (e.g. spawned by Enigmail) now wants to interact with one of your keys, it will dispatch the passphrase work to <code>gpg-agent</code>. If a passphrase has not been provided to <code>gpg-agent</code> yet, or the last entry is longer ago than the configure TTL (time to live), <code>gpg-agent</code> needs a way to prompt for a new passphrase. Therefore it is important that a graphical pinentry program is configured for <code>gpg-agent</code>. This is done inside the file <code>~/.gnupg/gpg-agent.conf</code>. Ensure that in this file at least the following line is present (adapt the path as required):</p>
<pre tabindex="0"><code class="language-none" data-lang="none">pinentry-program /usr/local/bin/pinentry-mac
</code></pre><p>This instructs <code>gpg-agent</code> to use the <a href="https://github.com/GPGTools/pinentry-mac">pinentry-mac</a> program (from the GPGTools project, can e.g. be installed via homebrew) for requesting a passphrase.</p>
<p>After performing all these steps, you can logout and back in again. In a terminal you should now see that <code>gpg-agent</code> is running, e.g. via <code>ps -ef | grep gpg-agent</code> and also the <code>GPG_AGENT_INFO</code> variable should be present (<code>echo $GPG_AGENT_INFO</code>). Enigmail should be able to interact with <code>gpg-agent</code> and passphrases will only be requested once per TTL.</p>
<h3 id="update">Update:</h3>
<p>Starting with GPG 2.2 this is probably not necessary anymore, since it seems that GPG itself now implemented a system to start the agent if it is not running.</p>]]></content></entry><entry><title>Revamped FlickrExifTagger moved to Github</title><link rel="alternate" href="https://www.semipol.de/posts/2014/11/revamped-flickrexiftagger-moved-to-github/"/><id>https://www.semipol.de/posts/2014/11/revamped-flickrexiftagger-moved-to-github/</id><published>2014-11-20T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I revived the FlickrExifTagger script and updated my own Flickr stream with it to add machine tags specifying the lenses I have been using to all photos I took during the last years. For this purpose I improved the code to better support custom rules and moved the project to Github.
During this process I also updated the software section in this blog and used some Wordpress plugin magic to auto-generate an always up-to-date overview page, which I always forgot to update.</summary><content type="html"><![CDATA[<p>I revived the <a href="https://github.com/languitar/FlickrExifTagger" title="FlickrExifTagger">FlickrExifTagger</a> script and updated <a href="https://secure.flickr.com/photos/languitar/" title="languitar's Flickr stream">my own Flickr stream</a> with it to add <a href="https://secure.flickr.com/help/tags/#613430" title="Explanation of Flickr machine tags">machine tags</a> specifying the lenses I have been using to all photos I took during the last years. For this purpose I improved the code to better support custom rules and moved the project to Github.</p>
<p>During this process I also updated the <a href="/software" title="Semipol Software">software section</a> in this blog and used some Wordpress plugin magic to auto-generate an always up-to-date <a href="/software" title="Software Overview">overview page</a>, which I always forgot to update.</p>
]]></content></entry><entry><title>Applying the Changes of a Single File from a Git Stash</title><link rel="alternate" href="https://www.semipol.de/posts/2014/06/applying-the-changes-of-a-single-file-from-a-git-stash/"/><id>https://www.semipol.de/posts/2014/06/applying-the-changes-of-a-single-file-from-a-git-stash/</id><published>2014-06-18T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In order to apply only changes for a selected file from the git stash you can use the following command line (bash):
git diff stash@\{0\}^1 stash@\{0\} -- path/to/your/file | git apply Based on the Stackoverflow question: How would I extract a single file (or changes to a file) from a git stash?</summary><content type="html"><![CDATA[<p>In order to apply only changes for a selected file from the git stash you can use the following command line (bash):</p>
<pre><code>git diff stash@\{0\}^1 stash@\{0\} -- path/to/your/file | git apply
</code></pre>
<p>Based on the Stackoverflow question: <a href="https://stackoverflow.com/questions/1105253/how-would-i-extract-a-single-file-or-changes-to-a-file-from-a-git-stash" title="How would I extract a single file (or changes to a file) from a git stash?">How would I extract a single file (or changes to a file) from a git stash?</a></p>
]]></content></entry><entry><title>Python Highlights</title><link rel="alternate" href="https://www.semipol.de/posts/2014/05/python-highlights/"/><id>https://www.semipol.de/posts/2014/05/python-highlights/</id><published>2014-05-20T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Nice parsing differences between python versions:
languitar@cinnabar:~$ python2 -c 'print("test", "42")' ('test', '42') languitar@cinnabar:~$ python3 -c 'print("test", "42")' test 42</summary><content type="html"><![CDATA[<p>Nice parsing differences between python versions:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>languitar<span style="color:#a6e22e">@cinnabar</span>:<span style="color:#f92672">~</span><span style="color:#960050;background-color:#1e0010">$</span> python2 <span style="color:#f92672">-</span>c <span style="color:#e6db74">&#39;print(&#34;test&#34;, &#34;42&#34;)&#39;</span>
</span></span><span style="display:flex;"><span>(<span style="color:#e6db74">&#39;test&#39;</span>, <span style="color:#e6db74">&#39;42&#39;</span>)
</span></span><span style="display:flex;"><span>languitar<span style="color:#a6e22e">@cinnabar</span>:<span style="color:#f92672">~</span><span style="color:#960050;background-color:#1e0010">$</span> python3 <span style="color:#f92672">-</span>c <span style="color:#e6db74">&#39;print(&#34;test&#34;, &#34;42&#34;)&#39;</span>
</span></span><span style="display:flex;"><span>test <span style="color:#ae81ff">42</span>
</span></span></code></pre></div>]]></content></entry><entry><title>My own cloud: Seafile</title><link rel="alternate" href="https://www.semipol.de/posts/2014/03/my-own-cloud-seafile/"/><id>https://www.semipol.de/posts/2014/03/my-own-cloud-seafile/</id><published>2014-03-23T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Continuing with my journey to replace publicly hosted cloud services with self-hosted solutions. One of the nice developments of the recent years are services like Dropbox or Google Drive, which really simplify some use cases. For example, in my own workflow I mainly use these services to a) synchronize unix configuration files, b) synchronize some random temp files I need on several computers or which I need from my phone (I am usually too lazy to get a cable), c) for easy sharing of photos or other files, and d) for synchronizing my Lightroom catalogue across devices, a quite heavy task because of the monolithic sqlite file with > 1 GB. There have only been a few cases where I actually used a shared folder for collaborative work. Computer scientists have better tools for such jobs. ;) So my need for something that is really accepted by many users is again questionable. Hence, I could easily search for a self-hosted solution without many drawbacks.</summary><content type="html"><![CDATA[<p>Continuing with my journey to replace publicly hosted cloud services with self-hosted solutions. One of the nice developments of the recent years are services like Dropbox or Google Drive, which really simplify some use cases. For example, in my own workflow I mainly use these services to a) synchronize unix configuration files, b) synchronize some random temp files I need on several computers or which I need from my phone (I am usually too lazy to get a cable), c) for easy sharing of photos or other files, and d) for synchronizing my Lightroom catalogue across devices, a quite heavy task because of the monolithic sqlite file with &gt; 1 GB. There have only been a few cases where I actually used a shared folder for collaborative work. Computer scientists have better tools for such jobs. ;) So my need for something that is really accepted by many users is again questionable. Hence, I could easily search for a self-hosted solution without many drawbacks.</p>
<p>The first solution I tested was <a href="http://owncloud.org/" title="ownCloud">ownCloud</a>. My experiences weren&rsquo;t too good. Especially, because I was completely unable to manually compile the client on my work computer. After endless tries I finally ended up with a launchable version which, however, didn&rsquo;t synchronize at all. Some more web-browsing later with endless remarks about the bad support and many open issues I decided against ownCloud.</p>
<p>The solution I ended with is <a href="http://seafile.com/en/home/" title="Seafile">Seafile</a>, a not so well known open source solution with some Chinese developers and good support and issue response times. People might be suspicious because of the origins, but so far I couldn&rsquo;t find any obvious security issues and things work quite well.</p>
<p>For my setup I followed the <a href="https://github.com/haiwen/seafile/wiki" title="Seafile wiki">installation instructions on the Github wiki</a> using the pre-compiled packages. I am operating Seafile on a subfolder of an SSL-enabled subdomain by using apache as a proxy. Actually, all required information how to set up this configuration can be found on the wiki with some browsing. Things could be better described, but I can also imagine much more horrifying installation instructions.</p>
<p>After installing the Seafile server and adding a user account clients can connect to the server and synchronize multiple <em>libraries</em>. This is a nice concept not directly available in Dropbox etc. Each library is a folder structure with separate settings for the kind of history that is maintained and the ability to enable client-side encryption. Moreover, libraries are the atomic unit that can be shared between users on the same server. E.g. in my setup I created a library for sharing files with others where I completely disabled the history feature and another one for the config files where I preserve a few revisions of history. Across the different collections,  Seafile implements a de-duplication strategy to save server-side storage space. Clients exist for all major operating systems (including a console-based daemon for linux) and also for Android.</p>
<figure>
    <img loading="lazy" src="Screen-Shot-2014-03-23-at-19.04.38-300x123.png"
         alt="Seafile webinterface screenshot"/> <figcaption>
            <p>The different libraries I use as displayed in the web interface.</p>
        </figcaption>
</figure>

<p>My experiences with Seafile are quite good so far and most things work well. The following issues are the once I noticed and that could be improved.</p>
<ul>
<li>The Android client sometimes silently refuses to upload a file. I could not find out in which cases this happens.</li>
<li>There is no option to permanently synchronize single files to an Android device and keep them updated.</li>
<li>Desktop clients work flawlessly. The only thing I noticed is that the de-duplication could be used better also to determine what to upload  and what not to. In the case of my 1.x GB Lightroom catalog file, uploads take much longer than with Dropbox and afterwards the size on the server didn&rsquo;t increase as much as data was uploaded. My impression is that this behavior has been improved with one of the recent client updates, but still the performance of Dropbox is not reached here.</li>
<li>Server administrators have to perform a manual garbage collection task from time to time. Otherwise the storage requirements on the server will grow indefinitely. This is kind of annoying despite the <a href="https://github.com/haiwen/seafile/wiki/Garbage-Collecting-Unused-Blocks-on-Seafile-Server" title="Seafile Garbage Collection">explanation why this is required</a>.</li>
<li>Clients are still hard to compile. The situation is a bit better than for ownCloud but still many uncommon libraries with differing build systems are required.</li>
<li>I didn&rsquo;t do a server-side update, but I suspect it will be some reading and manual work.</li>
</ul>
]]></content></entry><entry><title>My own cloud: Tiny Tiny RSS</title><link rel="alternate" href="https://www.semipol.de/posts/2013/12/my-own-cloud-tiny-tiny-rss/"/><id>https://www.semipol.de/posts/2013/12/my-own-cloud-tiny-tiny-rss/</id><published>2013-12-08T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In the light of the recent NSA issues I have been reconsidering whether I really need to use public cloud services or not. The main benefit that I see in publicly provided services (despite the technical setup) is large amount of users that potentially enhance the service. There needs to be a tradeoff between these benefits and the data that one gives away to the service providers etc.
One kind of service I have been using for some time now is a news feed reader / aggregator. First Google Reader and after the shutdown Feedly. I never used any collaborative feature for a news feed reader, so there is really no benefit in using a public service despite the setup overhead. So I started to search for a privately hosted alternative. Basically I had only a few requirements:</summary><content type="html"><![CDATA[<p>In the light of the recent NSA issues I have been reconsidering whether I really need to use public cloud services or not. The main benefit that I see in publicly provided services (despite the technical setup) is large amount of users that potentially enhance the service. There needs to be a tradeoff between these benefits and the data that one gives away to the service providers etc.</p>
<p>One kind of service I have been using for some time now is a news feed reader / aggregator. First Google Reader and after the shutdown Feedly. I never used any collaborative feature for a news feed reader, so there is really no benefit in using a public service despite the setup overhead. So I started to search for a privately hosted alternative. Basically I had only a few requirements:</p>
<ul>
<li>Synchronization between different clients</li>
<li>Web front-end</li>
<li>Android front-end</li>
<li>Flagging articles as important or read later</li>
</ul>
<p>With these requirements I ended up with <a href="http://tt-rss.org/redmine/projects/tt-rss/wiki" title="Tiny Tiny RSS">Tiny Tiny RSS</a>. Tiny Tiny RSS is a PHP-based web-service providing a comparable service like Google Reader and Feedly did. Moreover, several front-ends exist, e.g. for Android.</p>
<p>I am using Tiny Tiny RSS now for several weeks and I am quite satisfied. The service works very reliable so far without any issues. The setup itself was simple following the installation guide. The default theme for the web-interface looks a bit oldish, so one modification I did was installing <a href="https://github.com/levito/tt-rss-feedly-theme" title="tt-rss-feedly-theme">tt-rss-feedly-theme</a>, which provides a Feeldy-like style:</p>
<figure>
    <img loading="lazy" src="Screen-Shot-2013-12-08-at-23.08.58-1-1024x397.png"
         alt="tt-rss with feedly theme"/> 
</figure>

<p>For mobile reading on my Andoird devices I am using <a href="https://play.google.com/store/apps/details?id=org.ttrssreader" title="TTRSS-Reader">TTRSS-Reader</a>. Instead of the &ldquo;official&rdquo; open source Android client , which for strange reasons requires a payed unlock for full functionality, this one is completely free and works well. Swiping between articles could be a bit smoothers and there is sometimes a rendering bug when going back to the article list. But apart from that, everything works well.</p>
<figure>
    <img loading="lazy" src="TTRSS-Reader-168x300.png"
         alt="TTRSS-Reader on Android"/> 
</figure>

<p>So, Tiny Tiny RSS works very well for me and I do not miss anything I previously had with Google Reader or feedly. There are also a lot of other front-ends available other than the ones I have shown, which allows for a lot more customization.</p>
]]></content></entry><entry><title>Bash alias: Build on all CPU cores</title><link rel="alternate" href="https://www.semipol.de/posts/2013/09/bash-alias-build-on-all-cpu-cores/"/><id>https://www.semipol.de/posts/2013/09/bash-alias-build-on-all-cpu-cores/</id><published>2013-09-05T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Linux:
alias makej="make -j $(cat /proc/cpuinfo | grep processor | wc | sed -r 's/^ +([0-9])+.*//')" Mac:
alias makej="make -j $(sysctl hw.ncpu | awk '{print $2}')"</summary><content type="html"><![CDATA[<p>Linux:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>alias makej<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;make -j </span><span style="color:#66d9ef">$(</span>cat /proc/cpuinfo | grep processor | wc | sed -r <span style="color:#e6db74">&#39;s/^ +([0-9])+.*//&#39;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div><p>Mac:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>alias makej<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;make -j </span><span style="color:#66d9ef">$(</span>sysctl hw.ncpu | awk <span style="color:#e6db74">&#39;{print $2}&#39;</span><span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div>]]></content></entry><entry><title>Sharing the git config across different computers with individual modifications</title><link rel="alternate" href="https://www.semipol.de/posts/2013/08/sharing-the-git-config-across-different-computers-with-individual-modifications/"/><id>https://www.semipol.de/posts/2013/08/sharing-the-git-config-across-different-computers-with-individual-modifications/</id><published>2013-08-26T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>As I am working on a lot of different computer I wanted to share some of my configuration files across these computers to have similar working environments on all of the machines. An easy solution to do this is e.g. for git to put the .gitconfig file (along with other configuration files) into a folder inside the Dropbox (or other syncing tool), create a symlink to that file in the original location in your home directory and let Dropbox do the syncing.</summary><content type="html"><![CDATA[<p>As I am working on a lot of different computer I wanted to share some of my configuration files across these computers to have similar working environments on all of the machines. An easy solution to do this is e.g. for git to put the <code>.gitconfig</code> file (along with other configuration files) into a folder inside the Dropbox (or other syncing tool), create a symlink to that file in the original location in your home directory and let Dropbox do the syncing.</p>
<p>However, what if some parts of the git config are device specific? E.g. the visual difftool on my Mac is different from the one on Linux workstation, also the keychain helper. The solution I came up with is to let the shared <code>.gitconfig</code> include a device-specific file for the specific settings using the include feature available since 1.7.10:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#66d9ef">[include]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">path</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">.gitlocal</span>
</span></span></code></pre></div><p>Now I can configure device specific settings in the <code>~/.gitlocal</code> file which is not synced by Dropbox.</p>
<p>Unfortunately, some of the computers I am working with have older git version running not supporting the include feature. For these machines I can at least include all settings shared between them in the usual <code>.gitconfig</code> file and override them for other computers in their <code>.gitlocal</code> files. Not perfect, but it works for my setup.</p>
]]></content></entry><entry><title>How to set up a build system in C++, Python and Java</title><link rel="alternate" href="https://www.semipol.de/posts/2013/05/how-to-set-up-a-build-system-in-c-python-and-java/"/><id>https://www.semipol.de/posts/2013/05/how-to-set-up-a-build-system-in-c-python-and-java/</id><published>2013-05-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I don&rsquo;t know why, but setting up the build system for a new software project and maintaining it seems to be something people are always afraid of. I&rsquo;ve often heard people say &ldquo;Eclipse does the job. It&rsquo;s just additional work.&rdquo; This usually leads to confusion and a lot of bulk and weird solutions several days later when the project starts to evolve, ultimately with much more &ldquo;additional work&rdquo;. Also in existing software project I have seen so many weird constructs effectively breaking the intended usage patterns and solutions of tools like CMake or setuptools, ending up with good software that is a nightmare to build and port to different platforms without insider knowledge.</summary><content type="html"><![CDATA[<p>I don&rsquo;t know why, but setting up the build system for a new software project and maintaining it seems to be something people are always afraid of. I&rsquo;ve often heard people say &ldquo;Eclipse does the job. It&rsquo;s just additional work.&rdquo; This usually leads to confusion and a lot of bulk and weird solutions several days later when the project starts to evolve, ultimately with much more &ldquo;additional work&rdquo;. Also in existing software project I have seen so many weird constructs effectively breaking the intended usage patterns and solutions of tools like CMake or setuptools, ending up with good software that is a nightmare to build and port to different platforms without insider knowledge.</p>
<p>To overcome at least the problem of setting up a usable build system at all I have created a tutorial with example projects for C++, Python and Java some time ago at work. This is probably also usable outside my university, so feel free to use that tutorial for you own needs: <a href="http://docs.cor-lab.de/build%20system%20essentials-tutorial/trunk/html/index.html" title="Build System Essentials">Build System Essentials</a>.</p>
]]></content></entry><entry><title>Python logging configuration</title><link rel="alternate" href="https://www.semipol.de/posts/2013/04/python-logging-configuration/"/><id>https://www.semipol.de/posts/2013/04/python-logging-configuration/</id><published>2013-04-29T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In case you ever wondered how to correctly configure the python logging system, e.g. from files and configuration server, this might be a useful link, which I hadn&rsquo;t see before: Logging Cookbook.</summary><content type="html"><![CDATA[<p>In case you ever wondered how to correctly configure the python logging system, e.g. from files and configuration server, this might be a useful link, which I hadn&rsquo;t see before: <a href="http://docs.python.org/2/howto/logging-cookbook.html" title="Python Logging Cookbook">Logging Cookbook</a>.</p>
]]></content></entry><entry><title>Difference between comparisons with == and is in Python</title><link rel="alternate" href="https://www.semipol.de/posts/2013/04/difference-between-comparisons-with-and-is-in-python/"/><id>https://www.semipol.de/posts/2013/04/difference-between-comparisons-with-and-is-in-python/</id><published>2013-04-08T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In Python, two operators exist to perform equality comparisons: == and is. Often you can read instructions like &ldquo;When comparing to None, always use is instead of ==&rdquo;, but the real reason is not explained. However, looking at the language expression specification section of the Python manual you can find the difference: &ldquo;The operators is and is not test for object identity: x is y is true if and only if x and y are the same object. x is not y yields the inverse truth value.&rdquo; This means the expressions &ldquo;a is b&rdquo; only returns True if both a and b point to the exact same object instance. Hence, you should always use is when you want to compare against specific instances. For the advice about using is to compare with None this means that there is only a single instance of None. The same is true also for Ellipsis.</summary><content type="html"><![CDATA[<p>In <a href="http://www.python.org/" title="Python Programming Language">Python</a>, two operators exist to perform equality comparisons: == and is. Often you can read instructions like &ldquo;When comparing to None, always use is instead of ==&rdquo;, but the real reason is not explained. However, looking at the <a href="http://docs.python.org/3/reference/expressions.html#not-in" title="Python manual - Comparisons">language expression specification section</a> of the Python manual you can find the difference: &ldquo;The operators <a href="http://docs.python.org/3/reference/expressions.html#is"><code>is</code></a> and <a href="http://docs.python.org/3/reference/expressions.html#is-not"><code>is not</code></a> test for object identity: <code>x is y</code> is true if and only if <em>x</em> and <em>y</em> are the same object. <code>x is not y</code> yields the inverse truth value.&rdquo; This means the expressions &ldquo;a is b&rdquo; only returns True if both a and b point to the exact same object instance. Hence, you should always use is when you want to compare against specific instances. For the advice about using is to compare with None this means that there is only a single instance of  None. The same is true also for <a href="http://docs.python.org/3/library/constants.html?highlight=ellipsis#Ellipsis" title="Ellipsis in Python 3">Ellipsis</a>.</p>
<p>Not knowing the difference in comparison operators can actually lead to quite confusing results because of Python&rsquo;s operator overloading abilities. Imagine you need to check in some code whether an arbitrary variable you receive is Ellipsis or anything else. If you use == instead of &ldquo;is&rdquo; for that check, this might work in many cases but it might also be destroyed completely if that variable points to an object with a custom implementation of the **eq** function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;a test string&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">==</span> Ellipsis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">False</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> <span style="color:#f92672">import</span> numpy <span style="color:#66d9ef">as</span> np
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>array(range(<span style="color:#ae81ff">5</span>))
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">==</span> Ellipsis
</span></span><span style="display:flex;"><span>array([<span style="color:#66d9ef">False</span>, <span style="color:#66d9ef">False</span>, <span style="color:#66d9ef">False</span>, <span style="color:#66d9ef">False</span>, <span style="color:#66d9ef">False</span>], dtype<span style="color:#f92672">=</span>bool)
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">is</span> Ellipsis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">False</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> a <span style="color:#f92672">==</span> <span style="color:#66d9ef">None</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">False</span>
</span></span></code></pre></div><p>In the example, string behaves correctly for the test against Ellipsis, but comparing against a <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html" title="numpy ndarray">numpy ndarray</a> (highlighted lines) doesn&rsquo;t yield a boolean value as expect, but instead another array containing booleans, because ndarray implements **eq** and maps the comparison operator to an element-wise comparison. This probably results in an exception in production use. Lines 10 and 11 show that &ldquo;is&rdquo; ignores the custom comparison method and correctly resutls the expected boolean value.</p>
<p>Finally it is noteworthy that **eq** implementation of ndarray seems to be aware of the fact that people constantly compare against None with ==. This is the reasons why the last two lines of the source code listing return only a single boolean value and not a list. However, you should normally not rely on this fact as it is not given for all comparison implementations.</p>
<p>Other languages actually have a similar concept but they expose it in a more obvious way. In Java the == operator always checks for object identity and you explicitly need to implement and call the equals method if you want to have a custom comparison.</p>
]]></content></entry><entry><title>Android Update to CyanogenMod 10</title><link rel="alternate" href="https://www.semipol.de/posts/2013/04/android-update-to-cyanogenmod-10/"/><id>https://www.semipol.de/posts/2013/04/android-update-to-cyanogenmod-10/</id><published>2013-04-02T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I finally took the time and updated my &ldquo;old&rdquo; Samsung Galaxy S+ (GT i9001) from the Stock 2.3.6 version of Android to CyanogenMod 10, beta 4. I really should have done this earlier. The stock version was getting slower and slower over time without any apparent reason and no update to a newer version was expected from Samsung. It seemed that especially changing cells was wasting CPU like crazy. I always resisted from installing CM because the device is not officially supported and most ROMs I found so far had serious bugs like missing tethering or Bluetooth. The ROM I finally found really works flawlessly and much faster than the stock installation. Everything I tested so far works as expected including Bluetooth and tethering using WiFi and USB.</summary><content type="html"><![CDATA[<p>I finally took the time and updated my &ldquo;old&rdquo; Samsung Galaxy S+ (GT i9001) from the Stock 2.3.6 version of Android to <a href="http://www.cyanogenmod.org/" title="CyanogenMod">CyanogenMod</a> 10, beta 4. I really should have done this earlier. The stock version was getting slower and slower over time without any apparent reason and no update to a newer version was expected from Samsung. It seemed that especially changing cells was wasting CPU like crazy. I always resisted from installing CM because the device is not officially supported and most ROMs I found so far had serious bugs like missing tethering or Bluetooth. The <a href="http://forum.xda-developers.com/showthread.php?t=2000828" title="SGS+ CM 10 ROM">ROM I finally found</a> really works flawlessly and much faster than the stock installation. Everything I tested so far works as expected including Bluetooth and tethering using WiFi and USB.</p>
<p>Of course, as usual with Samsung devices I had to go over several bricks before I finally got a running installation. Also, I ended up being stuck with an endless recovery mode loop caused by Clockwork Mod Recovery, which was fortunately cured by <a href="http://www.android-hilfe.de/root-hacking-modding-fuer-samsung-galaxy-s-plus/272328-reboot-recovery-problem-loesung.html" title="Recovery Mode Loop (German)">this solution</a> (German) after the second attempt. The only thing left I have to find out now is the battery consumption&hellip;</p>
<p>Btw, why are all these people on the android hacker forums so unbelievably brief and pseudo-geeky with their language. Really a pain to read posts and descriptions there&hellip;</p>
]]></content></entry><entry><title>Website Updates</title><link rel="alternate" href="https://www.semipol.de/posts/2013/03/website-updates/"/><id>https://www.semipol.de/posts/2013/03/website-updates/</id><published>2013-03-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>After serveral years I finally managed to restructure my websites. The blog here was kind of infrequently used and the photography section pointed to my flickr account using a flash viewer. Especially with this photography portfoilio there were several things that I did not like:
First of all this wasn&rsquo;t a portfolio at all with the lack of any selection and reasonable presentation. Essentially I am using flickr now for any kind of photo and not only for selected ones. Also, in line with the ongoing shift to other platforms, I have started putting fine art-like photos to other sites like 500px. Hence, flickr wasn&rsquo;t the right basis anymore. Second, flash is a dying web technology and has several drawbacks for photography. Most important it doesn&rsquo;t support color management well. So dropping this viewer was also an important step.</summary><content type="html"><![CDATA[<p>After serveral years I finally managed to restructure my websites. The blog here was kind of infrequently used and the photography section pointed to my flickr account using a flash viewer. Especially with this photography portfoilio there were several things that I did not like:</p>
<p>First of all this wasn&rsquo;t a portfolio at all with the lack of any selection and reasonable presentation. Essentially I am using flickr now for any kind of photo and not only for selected ones. Also, in line with the ongoing shift to other platforms, I have started putting fine art-like photos to other sites like 500px. Hence, flickr wasn&rsquo;t the right basis anymore.
Second, flash is a dying web technology and has several drawbacks for photography. Most important it doesn&rsquo;t support color management well. So dropping this viewer was also an important step.</p>
<p>As a consequence I have created a dedicated website for my photography work: <a href="https://www.johanneswienke.de">https://www.johanneswienke.de</a>. This website will also contain a blog for the photography-related things I am doing.</p>
<p>The blog here will still continue to exist and I will try to update it from time to time, especially with more tech-related stuff. As such things are mainly discussed in English, I have also switched the language to English now by replacing the underlying Wordpress installation. To make the maintenance of this blog and the portfolio easier I have also switched to the network features of Wordpress, which allows to run multiple sites using the same Wordpress installation.</p>
]]></content></entry><entry><title>copyiptcandxmp updated</title><link rel="alternate" href="https://www.semipol.de/posts/2012/06/copyiptcandxmp-updated/"/><id>https://www.semipol.de/posts/2012/06/copyiptcandxmp-updated/</id><published>2012-06-03T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I have updated the script formerly called &ldquo;fixgpsandtags&rdquo; so that it can now be used to more generally copy IPTC and XMP data to processed images. Therefore it is now called &ldquo;copyiptcandxmp&rdquo;. Such a step is often necessary because raw processing tools ignore XMP or IPTC completely. This script simplifies the process because several patterns can be specified how the original raw file name can be deduced from the processed file name.</summary><content type="html"><![CDATA[<p>I have updated the script formerly called &ldquo;fixgpsandtags&rdquo; so that it can now be used to more generally copy IPTC and XMP data to processed images. Therefore it is now called &ldquo;copyiptcandxmp&rdquo;. Such a step is often necessary because raw processing tools ignore XMP or IPTC completely. This script simplifies the process because several patterns can be specified how the original raw file name can be deduced from the processed file name.</p>
<p>The script can be found <a href="software/copyiptcandxmp" title="copyiptcandxmp">here</a>.</p>
]]></content></entry><entry><title>Relative RPath Settings with CMake</title><link rel="alternate" href="https://www.semipol.de/posts/2012/02/relative-rpath-settings-with-cmake/"/><id>https://www.semipol.de/posts/2012/02/relative-rpath-settings-with-cmake/</id><published>2012-02-16T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>The run-time search path (rpath) defines paths to search for dynamic libraries when executing a program. It is a mechanism on Linux parallel to the LD_LIBRARY_PATH environment variable, which is another hint to find dynamic libraries.
Usually, it is a good idea to make software which you built relocatable. This means that created binaries can be moved around and they still work after the location change. This includes the ability to still find the correct versions of dynamic libraries. One simple way to achieve this is by setting the rpath relative to the current location of the binary. In CMake this can be achieved like this:</summary><content type="html"><![CDATA[<p>The run-time search path (rpath) defines paths to search for dynamic libraries when executing a program. It is a mechanism on Linux parallel to the LD_LIBRARY_PATH environment variable, which is another hint to find dynamic libraries.</p>
<p>Usually, it is a good idea to make software which you built relocatable. This means that created binaries can be moved around and they still work after the location change. This includes the ability to still find the correct versions of dynamic libraries. One simple way to achieve this is by setting the rpath relative to the current location of the binary. In CMake this can be achieved like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span><span style="color:#75715e"># for all binaries created in a CMake project:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>SET(<span style="color:#e6db74">CMAKE_INSTALL_RPATH</span> <span style="color:#e6db74">&#34;$ORIGIN/../lib:$ORIGIN/&#34;</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># for certain targets
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>SET_TARGET_PROPERTIES(<span style="color:#e6db74">target</span> <span style="color:#e6db74">1</span> <span style="color:#e6db74">target2</span> <span style="color:#e6db74">...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">PROPERTIES</span> <span style="color:#e6db74">INSTALL_RPATH</span> <span style="color:#e6db74">&#34;$ORIGIN/../lib:$ORIGIN/&#34;</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Please note that the backslash is required.</p>
]]></content></entry><entry><title>Using Dependency Tracking in Jenkins with CMake-based C++ Projects</title><link rel="alternate" href="https://www.semipol.de/posts/2011/07/using-dependency-tracking-in-jenkins-with-cmake-based-c-projects/"/><id>https://www.semipol.de/posts/2011/07/using-dependency-tracking-in-jenkins-with-cmake-based-c-projects/</id><published>2011-07-31T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>If you are building multiple related software projects with a continuous integration server one important aspect is to be notified when changes in an upstream job break the build or tests for a downstream job. This involves knowing which exact build numbers of the upstream and the downstream job are involved.
The Jenkins continuous integration server uses the notion of file fingerprints for this purpose. The upstream job is built by Jenkins and produces one or several so called artifacts, the results of the build process. The artifacts are archived by Jenkins and fingerprints (hash sums) for each artifact are created and stored along with the build number of the job. When the downstream job starts to build it downloads the (most recent) artifacts from the upstream job and uses them for its purposes, i.e. building and running the own source code. By comparing the fingerprints of the downloaded artifacts with the stored fingerprints Jenkins knows which version of each upstream job was involved in a build and can track which upstream build number broke the downstream job. Jenkins will only issue notifications if this fingerprinting mechanism is properly configured, triggering a build after another is not sufficient to receive these notifications. Moreover, the Blame Upstream Commiters plugin needs to be used and enabled for each downstream job or the global property hudson.upstreamCulprits (will this ever be renamed?) needs to be set.</summary><content type="html"><![CDATA[<p>If you are building multiple related software projects with a continuous integration server one important aspect is to be notified when changes in an upstream job break the build or tests for a downstream job. This involves knowing which exact build numbers of the upstream and the downstream job are involved.</p>
<p>The <a href="http://jenkins-ci.org/" title="Jenkins CI">Jenkins</a> continuous integration server uses the notion of <a href="https://wiki.jenkins-ci.org/display/JENKINS/Fingerprint" title="Jeknins File Fingerprints">file fingerprints</a> for this purpose. The upstream job is built by Jenkins and produces one or several so called artifacts, the results of the build process. The artifacts are archived by Jenkins and fingerprints (hash sums) for each artifact are created and stored along with the build number of the job. When the downstream job starts to build it downloads the (most recent) artifacts from the upstream job and uses them for its purposes, i.e. building and running the own source code. By comparing the fingerprints of the downloaded artifacts with the stored fingerprints Jenkins knows which version of each upstream job was involved in a build and can track which upstream build number broke the downstream job. Jenkins will <strong>only</strong> issue notifications if this fingerprinting mechanism is properly configured, triggering a build after another is not sufficient to receive these notifications. Moreover, the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Blame+Upstream+Committers+Plugin" title="Jenkins Blame Upstream Committers plugin">Blame Upstream Commiters plugin</a> needs to be used and enabled for each downstream job or the global property <a href="https://wiki.jenkins-ci.org/display/JENKINS/Features+controlled+by+system+properties" title="Jenkins Properties">hudson.upstreamCulprits</a> (will this ever be renamed?) needs to be set.</p>
<p>The rational behind this rather complex mechanism is that it enables a high amount of parallelism for building jobs. While the downstream job builds, the upstream job can already operate again without affecting the downstream job. This would be the case if e.g. a central installation location would be shared between both jobs. If the upstream job installs new files while the downstream job is still building, this will certainly result in hard to debug errors. Moreover, this also allows to run the downstream job on a different build salve (assuming similar systems), which also would not be the case with a central installation location in a file system.</p>
<p>For Java projects (where Jenkins comes from) the explained mechanism usually works well. The upstream job produces one or several jar files containing all resources for the project like images, fingerprints them, no preprocessor is involved which configures the Java code according to the installation setup, and no source code was generated based on this setup. For C++ projects this is usually different, because the language already includes a preprocessor and it is common practice to set certain code lines according to the installation location, e.g. to find additional files like images, because they cannot be packaged in the jar file. Also, C++ projects usually consists of much more files considering all headers compared to Java. This provides more chances to mix something up.</p>
<p>So assuming an upstream C++ job A (using CMake, other build solutions are not covered in this post but the techniques can be applied there, too) which is built in Jenkins, it usually will be configured with an installation location, e.g. inside the job&rsquo;s workspace like <code>/jenkins/workspace/A/install</code>.</p>
<ol>
<li>
<p>Often, CMake will use this location, e.g. to generate a <code>config.h</code> which tells that images are found at <code>/jenkins/workspace/A/install/share/A/images</code> etc.</p>
</li>
<li>
<p>To use the CMake dependency mechanism, it will generate a <code>AConfig.cmake</code> file and install it also to the share folder (cf. the <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:find_package" title="CMake find_package documentation">CMake documentation for find_package</a>). The file might look like:</p>
<pre><code>SET(A_LIBRARIES &quot;/jenkins/workspace/A/install/lib/libA.so&quot;)
SET(A_INCLUDE_DIRS &quot;/jenkins/workspace/A/install/include/A&quot;)
</code></pre>
</li>
</ol>
<p>After building the project the job will e.g. use a compression tool to create a single archive and compress all contents of <code>/jenkins/workspace/A/install/</code>, archive this artifact and generate the fingerprints for it.</p>
<p>Both issues mentions above will prevent the dependency tracking of Jenkins to function properly, because the downstream job will download the artifacts to its own workspace, e.g. to <code>/jenkins/workspace/B/upstream/A</code> and unpack them. Cf. the issues:</p>
<ol>
<li>The upstream project A will not find external files at all or will use wrong versions, because in the meantime a new build of job A might have started and hence the workspace of this job is currently changing.</li>
<li>The downstream job B will not build at all or might use a wrong version of A because the contents of <code>AConfig.cmake</code> point to A&rsquo;s workspace and not the downloaded artifacts.</li>
</ol>
<p>To enable reliable dependency tracking in Jenkins, the solutions are:</p>
<ol>
<li>
<p>Do not use this technique at all. The software is generally more flexible if not hard locations are assumed and more situations are covered without recompiling.</p>
</li>
<li>
<p>The idea here is to make all paths given in the config file (<code>AConfig.cmake</code>) relative to its current location on the disc. This will look like this:</p>
<pre><code>GET_FILENAME_COMPONENT(CONFIG_DIR &quot;${CMAKE_CURRENT_LIST_FILE}&quot; PATH)
SET(A_LIBRARIES &quot;${CONFIG_DIR}/../../lib/libA.so&quot;)
SET(A_INCLUDE_DIRS &quot;${CONFIG_DIR}/../../include/A&quot;)
</code></pre>
<p>Now the CMake script of B will use the correct downloaded headers, libraries etc. for A from the own workspace</p>
</li>
</ol>
<p>The two aspects make it possible to use fingerprinting in Jenkins for dependency tracking with notifications for upstream committers. Especially the first aspect includes taking care while designing the project but there is no other solution I can think of.</p>
<p>Please note that for executing any tests in downsteam job B you have to set the <code>LD_LIBRARY_PATH</code> to find the right upstream libraries as well.</p>
<h3 id="random-comments">Random Comments</h3>
<p>Some more care needs to be taken to not mix up the dependency tracking again:</p>
<ul>
<li>
<p>The downstream job needs to make sure that the latest downloaded artifact is really used to build its own source code. So it is a good idea to simply remove the upstream directory as the first step of the build.</p>
</li>
<li>
<p>The downloaded artifacts (as explained above the generated archive files) need to be kept after extracting them, because the downstream job also has to generate fingerprints for them (and not for the extracted files) to create a match with the fingerprints stored for the upstream job.</p>
</li>
<li>
<p>In order to enable the downstream CMake project to find the upstream project use the <code>_DIR</code> variable for the CMake call as defined in the CMake documentation, e.g. <code>-DA_DIR=&quot;${WORKSPACE}/upstream/A/share/A&quot;</code></p>
</li>
<li>
<p>If your upstream project contains a version or revision number in the extracted folder (e.g. <code>${WORKSPACE}/upstream/A-0.35/</code>) and you want your downstream job to be resilient against version changes in the upstream project you can use some find-magic on UNIX for automatically finding the folder:</p>
<pre tabindex="0"><code>A=`find &#34;${WORKSPACE}/upstream&#34; -maxdepth 1 -type d -name &#34;A-\*&#34;;\`
</code></pre></li>
<li>
<p>If you are using <a href="http://www.freedesktop.org/wiki/Software/pkg-config" title="pkg-config">pkg-config</a> instead of or in addition to the CMake config file mechanism, you can use the <code>--define-variable</code> command line argument to achieve similar flexibility, assuming that all your absolute paths depend on a single prefix-variable in the pc file.</p>
</li>
</ul>
]]></content></entry><entry><title>Gcov Coverage Reports in Jenkins</title><link rel="alternate" href="https://www.semipol.de/posts/2011/04/gcov-coverage-reports-in-jenkins/"/><id>https://www.semipol.de/posts/2011/04/gcov-coverage-reports-in-jenkins/</id><published>2011-04-09T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I am currently evaluating the applicability and limitations of the Jenkins continuous integration server for C++ development. Besides several limitations which are mainly caused by the complexity of C++, Jenkins provides a solid basis for continuous integration of C++ projects.
One thing which I was not happy with so far was the missing integration of open-source coverage tools for Linux. Here, Gcov can be used to generate more or less precise coverage reports for projects compiled with GCC. Unfortunately, Gcov itself does not provide tools to export the results in any common or even nicely readable format. Until now, the only working solution I found was to use the Gcov front-end LCOV to generate a HTML report. This report is nice to read but it cannot be tracked by Jenkins with the drawback that no trend report for the code coverage can be generated. Nevertheless, I&rsquo;ve wrapped the creation of such a HTML report in a CMake function and worked with it so far.</summary><content type="html"><![CDATA[<p>I am currently evaluating the applicability and limitations of the <a href="http://jenkins-ci.org/" title="Jenkins">Jenkins</a> continuous integration server for C++ development. Besides several limitations which are mainly caused by the complexity of C++, Jenkins provides a solid basis for continuous integration of C++ projects.</p>
<p>One thing which I was not happy with so far was the missing integration of open-source coverage tools for Linux. Here, <a href="http://gcc.gnu.org/onlinedocs/gcc/Gcov.html" title="gcov">Gcov</a> can be used to generate more or less precise coverage reports for projects compiled with GCC. Unfortunately, Gcov itself does not provide tools to export the results in any common or even nicely readable format. Until now, the only working solution I found was to use the Gcov front-end <a href="http://ltp.sourceforge.net/coverage/lcov.php" title="LCOV">LCOV</a> to generate a HTML report. This report is nice to read but it cannot be tracked by Jenkins with the drawback that no trend report for the code coverage can be generated. Nevertheless, I&rsquo;ve wrapped the creation of such a HTML report in a CMake function and worked with it so far.</p>
<p>Today, I searched again for cheap solutions to overcome this drawback (this means without writing a custom Jenkins plugin for Gcov coverage files). While searching the net, I found the <a href="https://software.sandia.gov/trac/fast/wiki/gcovr" title="gcovr">gcovr</a> script, which parses Gcov result files and is able to convert them into XML files that satisfy the format generated by <a href="http://cobertura.sourceforge.net/" title="Cobertura">Cobertura</a>, which is a coverage tool for Java with an existing plugin for Jenkins.</p>
<p>As far as I tested it, this script works well with the Jenkins plugin, so I integrated the execution of this script in my existing coverage function for CMake, which is available in the <a href="https://code.cor-lab.de/projects/rsc" title="Robotics Systems Commons">RSC library</a>. This library also contains additional CMake wrappers for tools that can be used to generate trend reports in Jenkins, like <a href="http://sourceforge.net/apps/mediawiki/cppcheck/index.php?title=Main_Page" title="cppcheck">cppcheck</a>. Now our Jenkins can also generate coverage trend reports for C++ projects.</p>
<figure>
    <img loading="lazy" src="graph.png"
         alt="Coverage Report Graph in Jenkins"/> <figcaption>
            <p>A generated coverage report graph from our Jenkins server.</p>
        </figcaption>
</figure>

]]></content></entry><entry><title>Evaluation of Default Arguments in Python</title><link rel="alternate" href="https://www.semipol.de/posts/2011/01/evaluation-of-default-arguments-in-python/"/><id>https://www.semipol.de/posts/2011/01/evaluation-of-default-arguments-in-python/</id><published>2011-01-19T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Today I stumbled upon a very subtle problem with default arguments in python. I noticed that loading a python module already instantiated one of my classes even though I could not find an installation of this class. In the end it turned out to be a default argument for a function:
def foo(arg=MyClass()): pass As I am currently programming a lot in C++ this did not look suspicious to me. But from python&rsquo;s point of view it absolutely makes sense that the default value for arg is already constructed at module load time and not only on a call to that functions. Moreover it is important to remember that this default argument is constructed only once for all calls to a function as stated here.</summary><content type="html"><![CDATA[<p>Today I stumbled upon a very subtle problem with default arguments in python. I noticed that loading a python module already instantiated one of my classes even though I could not find an installation of this class. In the end it turned out to be a default argument for a function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">foo</span>(arg<span style="color:#f92672">=</span>MyClass()):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pass</span>
</span></span></code></pre></div><p>As I am currently programming a lot in C++ this did not look suspicious to me. But from python&rsquo;s point of view it absolutely makes sense that the default value for arg is already constructed at module load time and <strong>not</strong> only on a call to that functions. Moreover it is important to remember that this default argument is <strong>constructed only once</strong> for all calls to a function as stated <a href="http://www.network-theory.co.uk/docs/pytut/DefaultArgumentValues.html" title="An Introduction to Python - Default Argument Values">here</a>.</p>
]]></content></entry><entry><title>Boost bind and smart pointers</title><link rel="alternate" href="https://www.semipol.de/posts/2011/01/boost-bind-and-smart-pointers/"/><id>https://www.semipol.de/posts/2011/01/boost-bind-and-smart-pointers/</id><published>2011-01-09T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I&rsquo;ve seen this several times causing troubles:
boost::shared_ptr&lt;Foo> p(new Foo); boost::thread t(boost::bind(&amp;Foo::method, p.get())) This prevents the livecycle management of shared_ptr or any other smart pointer to be effective in the thread. Hence, p may get destructed even though the thread is still active.
Boost bind can handle smart pointers, so instead use the smart pointer itself as the instance argument for bind:
boost::thread t(boost::bind(&amp;Foo::method, p))</summary><content type="html"><![CDATA[<p>I&rsquo;ve seen this several times causing troubles:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>boost<span style="color:#f92672">::</span>shared_ptr<span style="color:#f92672">&lt;</span>Foo<span style="color:#f92672">&gt;</span> p(<span style="color:#66d9ef">new</span> Foo);
</span></span><span style="display:flex;"><span>boost<span style="color:#f92672">::</span><span style="color:#66d9ef">thread</span> t(boost<span style="color:#f92672">::</span>bind(<span style="color:#f92672">&amp;</span>Foo<span style="color:#f92672">::</span>method, p.get()))
</span></span></code></pre></div><p>This prevents the livecycle management of <code>shared_ptr</code> or any other smart pointer to be effective in the thread. Hence, <code>p</code> may get destructed even though the thread is still active.</p>
<p>Boost bind can handle smart pointers, so instead use the smart pointer itself as the instance argument for bind:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>boost<span style="color:#f92672">::</span><span style="color:#66d9ef">thread</span> t(boost<span style="color:#f92672">::</span>bind(<span style="color:#f92672">&amp;</span>Foo<span style="color:#f92672">::</span>method, p))
</span></span></code></pre></div>]]></content></entry><entry><title>bash: Home Directory Not Replaced With Tilde (~)</title><link rel="alternate" href="https://www.semipol.de/posts/2010/12/bash-home-directory-not-replaced-with-tilde-~/"/><id>https://www.semipol.de/posts/2010/12/bash-home-directory-not-replaced-with-tilde-~/</id><published>2010-12-30T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>After switching my computers to Arch Linux, reusing the existing home directories, I had the problem that the bash did not replace the user&rsquo;s home directory with the tilde character (~) in the prompt. The solutions for this problem is easy: somewhere in the bash-internals a check tests whether the output of pwd matches the contents of $HOME. $HOME, in turn, is filled from the user definition in /etc/passwd. pwd always returns the current working directory without a trailing slash, but the entry for my user in /etc/passwd contained a trailing slash. Removing this slash from the file solves the problem and the prompt uses ~ again for the home directory.</summary><content type="html"><![CDATA[<p>After switching my computers to Arch Linux, reusing the existing home directories, I had the problem that the bash did not replace the user&rsquo;s home directory with the tilde character (~) in the prompt. The solutions for this problem is easy: somewhere in the bash-internals a check tests whether the output of pwd matches the contents of <code>$HOME</code>. <code>$HOME</code>, in turn, is filled from the user definition in <code>/etc/passwd</code>. <code>pwd</code> always returns the current working directory without a trailing slash, but the entry for my user in <code>/etc/passwd</code> contained a trailing slash. Removing this slash from the file solves the problem and the prompt uses ~ again for the home directory.</p>
]]></content></entry><entry><title>Ubuntu Default Browser in Thunderbird</title><link rel="alternate" href="https://www.semipol.de/posts/2010/11/ubuntu-default-browser-in-thunderbird/"/><id>https://www.semipol.de/posts/2010/11/ubuntu-default-browser-in-thunderbird/</id><published>2010-11-13T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since the update to Ubuntu/Kubuntu Maverick Meerkat I was a bit puzzled why Thunderbird refused to open links in mails with my default browser Firefox even though it was set in the KDE settings and registered as a protocol-handler for http and https in the Thunderbird settings. It seems that there must be another setting in Thunderbird to use the default browser selected for the freedesktop environment which is now used. So updating the alternatives helped in Ubuntu:</summary><content type="html"><![CDATA[<p>Since the update to Ubuntu/Kubuntu Maverick Meerkat I was a bit puzzled why Thunderbird refused to open links in mails with my default browser Firefox even though it was set in the KDE settings and registered as a protocol-handler for http and https in the Thunderbird settings. It seems that there must be another setting in Thunderbird to use the default browser selected for the freedesktop environment which is now used. So updating the alternatives helped in Ubuntu:</p>
<pre tabindex="0"><code>sudo update-alternatives --config x-www-browser
</code></pre>]]></content></entry><entry><title>Menü Titanic</title><link rel="alternate" href="https://www.semipol.de/posts/2010/08/men%C3%BC-titanic/"/><id>https://www.semipol.de/posts/2010/08/men%C3%BC-titanic/</id><published>2010-08-27T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Speiseplan gestern in der Mensa:
Frühlingsröllchen, Chili-Pfeffer-Dip, Reis, Eisberg mit Möhren, Kokosquark</summary><content type="html"><![CDATA[<p>Speiseplan gestern in der Mensa:</p>
<p>Frühlingsröllchen, Chili-Pfeffer-Dip, Reis, <em>Eisberg</em> mit Möhren, Kokosquark</p>
]]></content></entry><entry><title>Ignoring Warnings from System Headers</title><link rel="alternate" href="https://www.semipol.de/posts/2010/08/ignoring-warnings-from-system-headers/"/><id>https://www.semipol.de/posts/2010/08/ignoring-warnings-from-system-headers/</id><published>2010-08-20T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Compiling C and C++ code with the highest warning levels is a good practice and helps spotting potential errors. For GCC the flags
-Wall -Wextra will generate a lot of useful warning messages about unused parameters etc.
Unfortunately, this is not the common practice and often the own compiler settings concerning the warning level results in dozens of warnings from system headers on which the own code relies, making it impossible to spot warnings from your own code in the endless mass of console output.</summary><content type="html"><![CDATA[<p>Compiling C and C++ code with the highest warning levels is a good practice and helps spotting potential errors. For GCC the flags</p>
<pre tabindex="0"><code>-Wall -Wextra
</code></pre><p>will generate a lot of useful warning messages about unused parameters etc.</p>
<p>Unfortunately, this is not the common practice and often the own compiler settings concerning the warning level results in dozens of warnings from system headers on which the own code relies, making it impossible to spot warnings from your own code in the endless mass of console output.</p>
<p>Fortunately, GCC has a way to ignore warnings from foreign headers. Instead of using <code>-I</code> to specify an include path, <code>-isystem</code> tells the compiler to treat the includes from the given path as system headers where no warnings should be reported.</p>
<p>If CMake is used to create the Makefile, a special argument to the <code>INCLUDE_DIRECTORIES</code> function generates these compiler flags:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span>INCLUDE_DIRECTORIES(<span style="color:#e6db74">SYSTEM</span> <span style="color:#e6db74">/usr/include</span> <span style="color:#e6db74">/and/other</span> <span style="color:#e6db74">/system/paths</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div>]]></content></entry><entry><title>Unused Parameters in C++</title><link rel="alternate" href="https://www.semipol.de/posts/2010/08/unused-parameters-in-c-/"/><id>https://www.semipol.de/posts/2010/08/unused-parameters-in-c-/</id><published>2010-08-09T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Just some quick thought on how to handle compiler warnings about unused parameters in C++ code. While these warnings are helpful most of the time, sometimes you simply have to ignore a parameter that is required by an interface definition. Then you got three solutions to remove the warning:
Change the compiler flags. The worst solution. In other cases these warnings are really helpful. Generally I really like to compile with the highest warning level. Most of the warnings (at least for GCC) really have something to tell.</summary><content type="html"><![CDATA[<p>Just some quick thought on how to handle compiler warnings about unused parameters in C++ code. While these warnings are helpful most of the time, sometimes you simply have to ignore a parameter that is required by an interface definition. Then you got three solutions to remove the warning:</p>
<ol>
<li>
<p>Change the compiler flags. The worst solution. In other cases these warnings are really helpful. Generally I really like to compile with the highest warning level. Most of the warnings (at least for GCC) really have something to tell.</p>
</li>
<li>
<p>Use a macro to flag a variable as being unused, e.g. from Qt:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>foo(<span style="color:#66d9ef">int</span> aParameter) {
</span></span><span style="display:flex;"><span>    Q_UNUSED(aParameter)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Even though this looks like a reasonable solution it has the drawback of having a potential for confusion.  Maybe sometime later you need the parameter but forget to remove the Q_UNUSED macro, hence generating something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>foo(<span style="color:#66d9ef">int</span> aParameter) {
</span></span><span style="display:flex;"><span>    Q_UNUSED(aParameter)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// 30 lines of other method code
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">int</span> anotherVariable <span style="color:#f92672">=</span> <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> aParameter;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Suddenly your code documents that a variable isn&rsquo;t used but actually it is and the compiler can&rsquo;t detect this error.</p>
</li>
<li>
<p>Simply comment the variable name:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>foo(<span style="color:#66d9ef">int</span> <span style="color:#75715e">/*aParameter*/</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// 30 lines of other method code
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">int</span> anotherVariable <span style="color:#f92672">=</span> <span style="color:#ae81ff">30</span> <span style="color:#f92672">*</span> aParameter;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Now the warning is gone, too and the compiler can detect either the illegal use of the variable in line three or the illegal statement that this variable is unused by purpose.</p>
</li>
</ol>
]]></content></entry><entry><title>CMake: installing headers and preserving the directory structure</title><link rel="alternate" href="https://www.semipol.de/posts/2010/05/cmake-installing-headers-and-preserving-the-directory-structure/"/><id>https://www.semipol.de/posts/2010/05/cmake-installing-headers-and-preserving-the-directory-structure/</id><published>2010-05-31T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>CMake doesn&rsquo;t provide a dedicated way to install header files (except for mac). What I wanted to do was to install all headers of my project using the same directory structure as in the source tree. This isn&rsquo;t as easy as it sounds. Assume you have a list of header files:
SET(HS folder/test.h folder/other/test2.h) A simple call to INSTALL doesn&rsquo;t preserve the folder structure:
INSTALL(FILES ${HS} DESTINATION include) This results in all files being directly under $prefix/include.</summary><content type="html"><![CDATA[<p>CMake doesn&rsquo;t provide a dedicated way to install header files (except for mac). What I wanted to do was to install all headers of my project using the same directory structure as in the source tree. This isn&rsquo;t as easy as it sounds. Assume you have a list of header files:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span>SET(<span style="color:#e6db74">HS</span> <span style="color:#e6db74">folder/test.h</span> <span style="color:#e6db74">folder/other/test2.h</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>A simple call to <code>INSTALL</code> doesn&rsquo;t preserve the folder structure:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span>INSTALL(<span style="color:#e6db74">FILES</span> <span style="color:#f92672">${</span>HS<span style="color:#f92672">}</span> <span style="color:#e6db74">DESTINATION</span> <span style="color:#e6db74">include</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>This results in all files being directly under <code>$prefix/include</code>.</p>
<p>To preserve the structure you can use this simple macro:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmake" data-lang="cmake"><span style="display:flex;"><span>MACRO(<span style="color:#e6db74">INSTALL_HEADERS_WITH_DIRECTORY</span> <span style="color:#e6db74">HEADER_LIST</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>    FOREACH(<span style="color:#e6db74">HEADER</span> <span style="color:#f92672">${</span>${HEADER_LIST<span style="color:#f92672">}</span><span style="color:#e6db74">}</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>        STRING(<span style="color:#e6db74">REGEX</span> <span style="color:#e6db74">MATCH</span> <span style="color:#e6db74">&#34;(.\\\*)\\\[/\\\]&#34;</span> <span style="color:#e6db74">DIR</span> <span style="color:#f92672">${</span>HEADER<span style="color:#f92672">}</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>        INSTALL(<span style="color:#e6db74">FILES</span> <span style="color:#f92672">${</span>HEADER<span style="color:#f92672">}</span> <span style="color:#e6db74">DESTINATION</span> <span style="color:#e6db74">include/</span><span style="color:#f92672">${</span>DIR<span style="color:#f92672">}</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>    ENDFOREACH(<span style="color:#e6db74">HEADER</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>ENDMACRO(<span style="color:#e6db74">INSTALL_HEADERS_WITH_DIRECTORY</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>INSTALL_HEADERS_WITH_DIRECTORY(<span style="color:#e6db74">HS</span>)<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div>]]></content></entry><entry><title>Using googlemock with the Boost Test Library</title><link rel="alternate" href="https://www.semipol.de/posts/2010/04/using-googlemock-with-the-boost-test-library/"/><id>https://www.semipol.de/posts/2010/04/using-googlemock-with-the-boost-test-library/</id><published>2010-04-13T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>googlemock is a framework that allows generating mock objects for unit tests. I&rsquo;ve decided to use this framework as it looks wells designed and maintained. The default is to use googlemock with Google&rsquo;s unit testing framework googletest, but as I was already using the Boost Testing Library, I was searching for a solution to use googlemock in Boost Test. Fortunately this isn&rsquo;t to hard to accomplish. You only have to create a TestEventListener that forwards all results supplied by googletest to the Boost Testing Framework:</summary><content type="html"><![CDATA[<p><a href="http://code.google.com/p/googlemock/" title="googlemock">googlemock</a> is a framework that allows generating mock objects for unit tests. I&rsquo;ve decided to use this framework as it looks wells designed and maintained. The default is to use googlemock with Google&rsquo;s unit testing framework <a href="http://code.google.com/p/googletest/">googletest</a>, but as I was already using the <a href="http://www.boost.org/doc/libs/1_42_0/libs/test/doc/html/index.html" title="Boost Testing Library">Boost Testing Library</a>, I was searching for a solution to use googlemock in Boost Test. Fortunately this isn&rsquo;t to hard to accomplish. You only have to create a TestEventListener that forwards all results supplied by googletest to the Boost Testing Framework:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;sstream&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;boost/test/included/unit_test.hpp&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;gtest/gtest.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;gmock/gmock.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">using</span> <span style="color:#66d9ef">namespace</span> std;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">using</span> <span style="color:#66d9ef">namespace</span> testing;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">BoostTestAdapter</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">public</span> EmptyTestEventListener {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">virtual</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">OnTestStart</span>(<span style="color:#66d9ef">const</span> TestInfo<span style="color:#f92672">&amp;</span> <span style="color:#75715e">/*testInfo*/</span>) {
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">virtual</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">OnTestPartResult</span>(<span style="color:#66d9ef">const</span> TestPartResult<span style="color:#f92672">&amp;</span> testPartResult) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (testPartResult.failed()) {
</span></span><span style="display:flex;"><span>        stringstream s;
</span></span><span style="display:flex;"><span>        s <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Mock test failed (file = &#39;&#34;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">&lt;&lt;</span> testPartResult.file_name()
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;&#39;, line = &#34;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">&lt;&lt;</span> testPartResult.line_number()
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;): &#34;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">&lt;&lt;</span> testPartResult.summary();
</span></span><span style="display:flex;"><span>        BOOST_FAIL(s.str());
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">virtual</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">OnTestEnd</span>(<span style="color:#66d9ef">const</span> <span style="color:#f92672">::</span>testing<span style="color:#f92672">::</span>TestInfo<span style="color:#f92672">&amp;</span> <span style="color:#75715e">/*testInfo*/</span>) {
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>Every time a partial test result of googletest is reported that fails, <code>BOOST_FAIL</code> is called.</p>
<p>The only thing that is left now is to install the newly created adapter in the googletest framework and initialize it properly. This can be done using a fixture class in Boost Test:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TestFixture</span> {
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span><span style="color:#f92672">:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    TestFixture() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        InitGoogleMock(
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&amp;</span>boost<span style="color:#f92672">::</span>unit_test<span style="color:#f92672">::</span>framework<span style="color:#f92672">::</span>master_test_suite().argc,
</span></span><span style="display:flex;"><span>            boost<span style="color:#f92672">::</span>unit_test<span style="color:#f92672">::</span>framework<span style="color:#f92672">::</span>master_test_suite().argv);
</span></span><span style="display:flex;"><span>        TestEventListeners <span style="color:#f92672">&amp;</span>listeners <span style="color:#f92672">=</span> UnitTest<span style="color:#f92672">::</span>GetInstance()<span style="color:#f92672">-&gt;</span>listeners();
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// this removes the default error printer
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">delete</span> listeners.Release(listeners.default_result_printer());
</span></span><span style="display:flex;"><span>        listeners.Append(<span style="color:#66d9ef">new</span> BoostTestAdapter);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">~</span>TestFixture() {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// nothing to tear down
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>BOOST_GLOBAL_FIXTURE(TestFixture)
</span></span></code></pre></div>]]></content></entry><entry><title>Doxygen Support in Eclipse CDT</title><link rel="alternate" href="https://www.semipol.de/posts/2010/04/doxygen-support-in-eclipse-cdt/"/><id>https://www.semipol.de/posts/2010/04/doxygen-support-in-eclipse-cdt/</id><published>2010-04-12T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Since a long time I was wondering why CDT, the C++ support for the Eclipse IDE, doesn&rsquo;t have a decent support for highlighting and creating comments in the Doxygen format. Today, while searching for customizable code templates per project, I found the setting to enable Doxygen support. It is located in the project properties at &ldquo;C/C++ General&rdquo;. Not that intuitive&hellip;
With this, Doxygen tags in comments are highlighted and comments with parameters etc. are generated automatically like in Java. What&rsquo;s still missing is the auto-formatter support for these comments and tag-completion.</summary><content type="html"><![CDATA[<p>Since a long time I was wondering why <a href="http://www.eclipse.org/cdt/" title="CDT">CDT</a>, the C++ support for the <a href="http://eclipse.org/" title="Eclipse IDE">Eclipse IDE</a>, doesn&rsquo;t have a decent support for highlighting and creating comments in the <a href="http://www.stack.nl/~dimitri/doxygen/" title="Doxygen">Doxygen</a> format. Today, while searching for customizable code templates per project, I found the setting to enable Doxygen support. It is located in the project properties at &ldquo;C/C++ General&rdquo;. Not that intuitive&hellip;</p>
<figure>
    <img loading="lazy" src="eclipse-cdt-doxygen-300x202.png"
         alt="Doxygen settings in Eclipse"/> 
</figure>

<p>With this, Doxygen tags in comments are highlighted and comments with parameters etc. are generated automatically like in Java. What&rsquo;s still missing is the auto-formatter support for these comments and tag-completion.</p>
]]></content></entry><entry><title>Flickr machine tags for lenses</title><link rel="alternate" href="https://www.semipol.de/posts/2010/04/flickr-machine-tags-for-lenses/"/><id>https://www.semipol.de/posts/2010/04/flickr-machine-tags-for-lenses/</id><published>2010-04-03T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>I&rsquo;ve added a simple script to the software section that allows adding machine tags to photos on your Flickr photo stream based on exif information found in the image. I use this script to tag photos with lens information but in general it can be used for every type of tag to add that can be deduced from the exif information.</summary><content type="html"><![CDATA[<p>I&rsquo;ve added a simple script to the <a href="/software.html">software section</a> that allows adding machine tags to photos on your Flickr photo stream based on exif information found in the image. I use this script to tag photos with lens information but in general it can be used for every type of tag to add that can be deduced from the exif information.</p>
]]></content></entry><entry><title>C64 Revival - Pong Evolutions</title><link rel="alternate" href="https://www.semipol.de/posts/2009/11/c64-revival-pong-evolutions/"/><id>https://www.semipol.de/posts/2009/11/c64-revival-pong-evolutions/</id><published>2009-11-08T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Last year at university I was participating at course for game development on a C64 machine. Let&rsquo;s get back to the 80s&hellip; Most of the time it was fun. But it was also challenging for us to develop thousands of lines of code in Assembler. Something completely different to the object oriented programming I do normally.
The game we developed is based on the well known Pong but extends it with some interesting tweaks like two paddles per player etc.</summary><content type="html"><![CDATA[<p>Last year at university I was participating at course for game development on a C64 machine. Let&rsquo;s get back to the 80s&hellip; Most of the time it was fun. But it was also challenging for us to develop thousands of lines of code in Assembler. Something completely different to the object oriented programming I do normally.</p>
<p>The game we developed is based on the well known Pong but extends it with some interesting tweaks like two paddles per player etc.</p>
<p>Here are the downloads:</p>
<ul>
<li><a href="PongEvolutions.d64">PongEvolutions d64 Image</a></li>
<li><a href="PongEvolutionsBooklet.pdf">PongEvolutions Booklet / Manual</a></li>
</ul>
<p>The game should be playable on every modern C64 emulator or the real one. It was developed on <a href="http://www.viceteam.org/" title="vice">vice</a>.</p>
]]></content></entry><entry><title>Google Earth: Probleme beim Verarbeiten von Tracks</title><link rel="alternate" href="https://www.semipol.de/posts/2009/09/google-earth-probleme-beim-verarbeiten-von-tracks/"/><id>https://www.semipol.de/posts/2009/09/google-earth-probleme-beim-verarbeiten-von-tracks/</id><published>2009-09-27T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In die aktuelle Linux-Version von Google Earth (5.1.3506.3999) scheint sich ein recht übler Bug, was das Verarbeiten von Tracks angeht, eingeschlichen zu haben. Bisher hatte ich nie Probleme, GPX-Dateien von meine GPS zu Laden, doch als ich es heute zum ersten Mal mit dieser Version versucht hab, war mein Track nur eine senkrechte Linie auf der Karte. Auch eine mit GPS-Babel nach *.kml konvertierte Variante hatte dieses Problem. Was hingegen funktioniert hat, war das Erstellen, Speichern und erneute Laden eines Tracks in Google Earth. Ein Vergleich meiner KML-Datei mit der von Google Earth selbst generierten hat einen netten Fehler aufgedeckt: Google hat wohl etwas zu viel i18n oder l10n gemacht, so dass beim Erstellen und Laden von Dateien das landestypische Dezimalzeichen (also mit deutscher Locale ein Komma) benutzt wird. Laut GPX- und KML-Spezifikation ist es natürlich totaler Müll, Koordinaten in der Form 52,xxx zu benutzen. Folgender Trick hat Google Earth dann davon überzeugt doch einen Punkt als Dezimaltrenner zu benutzen:</summary><content type="html"><![CDATA[<p>In die aktuelle Linux-Version von Google Earth (5.1.3506.3999) scheint sich ein recht übler Bug, was das Verarbeiten von Tracks angeht, eingeschlichen zu haben.  Bisher hatte ich nie Probleme, GPX-Dateien von meine GPS zu Laden, doch als ich es heute zum ersten Mal mit dieser Version versucht hab, war mein Track nur eine senkrechte Linie auf der Karte. Auch eine mit GPS-Babel nach <code>*.kml</code> konvertierte Variante hatte dieses Problem. Was hingegen funktioniert hat, war das Erstellen, Speichern und erneute Laden eines Tracks in Google Earth. Ein Vergleich meiner KML-Datei mit der von Google Earth selbst generierten hat einen netten Fehler aufgedeckt: Google hat wohl etwas zu viel i18n oder l10n gemacht, so dass beim Erstellen und Laden von Dateien das landestypische Dezimalzeichen (also mit deutscher Locale ein Komma) benutzt wird. Laut GPX- und KML-Spezifikation ist es natürlich totaler Müll, Koordinaten in der Form 52,xxx zu benutzen. Folgender Trick hat Google Earth dann davon überzeugt doch einen Punkt als Dezimaltrenner zu benutzen:</p>
<pre tabindex="0"><code>LANG=&#34;&#34; googleearth
</code></pre><p>So startet Google Earth auf Englisch.</p>
]]></content></entry><entry><title>Highlights aus der Boost Graph Library</title><link rel="alternate" href="https://www.semipol.de/posts/2009/07/highlights-aus-der-boost-graph-library/"/><id>https://www.semipol.de/posts/2009/07/highlights-aus-der-boost-graph-library/</id><published>2009-07-30T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Template Programming to the Extreme&hellip; Manchmal macht es echt eine Freude den Quellcode der BGL (Boost Graph Library) zu lesen. Hier ein paar Highlights:
typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&amp;); // The graph is passed by *const* reference so that graph adaptors // (temporaries) can be passed into this function. However, the // graph is not really const since we may write to property maps // of the graph. Spaßig sind aber auch die Compiler-Fehlermeldungen:</summary><content type="html"><![CDATA[<p>Template Programming to the Extreme&hellip; Manchmal macht es echt eine Freude den Quellcode der BGL (Boost Graph Library) zu lesen. Hier ein paar Highlights:</p>
<pre><code>typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&amp;);

// The graph is passed by *const* reference so that graph adaptors
// (temporaries) can be passed into this function. However, the
// graph is not really const since we may write to property maps
// of the graph.
</code></pre>
<p>Spaßig sind aber auch die Compiler-Fehlermeldungen:</p>
<pre tabindex="0"><code>make all Scanning dependencies of target imnbase [ 7%] Building CXX object src/CMakeFiles/imnbase.dir/algorithms/DefaultAlgorithmFactory.cpp.o [ 14%] Building CXX object src/CMakeFiles/imnbase.dir/algorithms/parallelScan/ParallelScan.cpp.o /usr/local/include/boost/mpi/datatype.hpp: In function »ompi_datatype_t\* boost::mpi::get_mpi_datatype(const T&amp;) [with T = std::basic_string, std::allocator &gt;]«: /usr/local/include/boost/mpi/detail/mpi_datatype_primitive.hpp:96: instantiated from »void boost::mpi::detail::mpi_datatype_primitive::save(const T&amp;) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:95: instantiated from »static void boost::archive::save_access::save_primitive(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:212: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_primitive::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/nvp.hpp:78: instantiated from »void boost::serialization::nvp::save(Archivex&amp;, unsigned int) const [with Archivex = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:93: instantiated from »static void boost::serialization::access::member_save(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:43: instantiated from »static void boost::serialization::detail::member_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:69: instantiated from »void boost::serialization::split_member(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/nvp.hpp:88: instantiated from »void boost::serialization::nvp::serialize(Archive&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:109: instantiated from »static void boost::serialization::access::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:74: instantiated from »void boost::serialization::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:220: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_only::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/collections_save_imp.hpp:60: instantiated from »void boost::serialization::stl::save_collection(Archive&amp;, const Container&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, Container = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:53: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int, mpl_::false_) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:123: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:45: instantiated from »static void boost::serialization::free_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:74: instantiated from »void boost::serialization::split_free(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:147: instantiated from »void boost::serialization::serialize(Archive&amp;, std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:144: instantiated from »void boost::archive::detail::oserializer::save_object_data(boost::archive::detail::basic_oarchive&amp;, const void*) const [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /home/languitar/workspace/iMN/src/algorithms/parallelScan/ParallelScan.cpp:128: instantiated from here /usr/local/include/boost/mpi/datatype.hpp:184: Fehler: keine passende Funktion für Aufruf von »assertion_failed(mpl_::failed*\*\*\*\*\*\*\*\*\*\*\* boost::mpi::is_mpi_datatype, std::allocator &gt; &gt;::\*\*\*\*\*\*\*\*\*\*\*\*)« /usr/local/include/boost/mpi/detail/mpi_datatype_cache.hpp: In member function »ompi_datatype_t\* boost::mpi::detail::mpi_datatype_map::datatype(const T&amp;, typename boost::disable_if, void&gt;::type*) [with T = std::basic_string, std::allocator &gt;]«: /usr/local/include/boost/mpi/datatype.hpp:185: instantiated from »ompi_datatype_t* boost::mpi::get_mpi_datatype(const T&amp;) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/detail/mpi_datatype_primitive.hpp:96: instantiated from »void boost::mpi::detail::mpi_datatype_primitive::save(const T&amp;) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:95: instantiated from »static void boost::archive::save_access::save_primitive(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:212: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_primitive::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/nvp.hpp:78: instantiated from »void boost::serialization::nvp::save(Archivex&amp;, unsigned int) const [with Archivex = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:93: instantiated from »static void boost::serialization::access::member_save(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:43: instantiated from »static void boost::serialization::detail::member_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:69: instantiated from »void boost::serialization::split_member(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/nvp.hpp:88: instantiated from »void boost::serialization::nvp::serialize(Archive&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:109: instantiated from »static void boost::serialization::access::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:74: instantiated from »void boost::serialization::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:220: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_only::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/collections_save_imp.hpp:60: instantiated from »void boost::serialization::stl::save_collection(Archive&amp;, const Container&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, Container = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:53: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int, mpl_::false_) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:123: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:45: instantiated from »static void boost::serialization::free_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:74: instantiated from »void boost::serialization::split_free(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:147: instantiated from »void boost::serialization::serialize(Archive&amp;, std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:144: instantiated from »void boost::archive::detail::oserializer::save_object_data(boost::archive::detail::basic_oarchive&amp;, const void*) const [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /home/languitar/workspace/iMN/src/algorithms/parallelScan/ParallelScan.cpp:128: instantiated from here /usr/local/include/boost/mpi/detail/mpi_datatype_cache.hpp:68: Fehler: keine passende Funktion für Aufruf von »assertion_failed(mpl_::failed*\*\*\*\*\*\*\*\*\*\*\* boost::mpi::is_mpi_datatype, std::allocator &gt; &gt;::\*\*\*\*\*\*\*\*\*\*\*\*)« /usr/local/include/boost/mpi/detail/mpi_datatype_oarchive.hpp: In constructor »boost::mpi::detail::mpi_datatype_oarchive::mpi_datatype_oarchive(const T&amp;) [with T = std::basic_string, std::allocator &gt;]«: /usr/local/include/boost/mpi/detail/mpi_datatype_cache.hpp:75: instantiated from »ompi_datatype_t\* boost::mpi::detail::mpi_datatype_map::datatype(const T&amp;, typename boost::disable_if, void&gt;::type*) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/datatype.hpp:185: instantiated from »ompi_datatype_t* boost::mpi::get_mpi_datatype(const T&amp;) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/detail/mpi_datatype_primitive.hpp:96: instantiated from »void boost::mpi::detail::mpi_datatype_primitive::save(const T&amp;) [with T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:95: instantiated from »static void boost::archive::save_access::save_primitive(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:212: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_primitive::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::basic_string, std::allocator &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const std::basic_string, std::allocator &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/nvp.hpp:78: instantiated from »void boost::serialization::nvp::save(Archivex&amp;, unsigned int) const [with Archivex = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:93: instantiated from »static void boost::serialization::access::member_save(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:43: instantiated from »static void boost::serialization::detail::member_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_member.hpp:69: instantiated from »void boost::serialization::split_member(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/nvp.hpp:88: instantiated from »void boost::serialization::nvp::serialize(Archive&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = const std::basic_string, std::allocator &gt;]« /usr/local/include/boost/serialization/access.hpp:109: instantiated from »static void boost::serialization::access::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:74: instantiated from »void boost::serialization::serialize(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:220: instantiated from »static void boost::archive::detail::save_non_pointer_type::save_only::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:294: instantiated from »static void boost::archive::detail::save_non_pointer_type::invoke(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:506: instantiated from »void boost::archive::save(Archive&amp;, const T&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = boost::serialization::nvp, std::allocator &gt; &gt;]« /usr/local/include/boost/mpi/detail/ignore_skeleton_oarchive.hpp:46: instantiated from »void boost::mpi::detail::ignore_skeleton_oarchive::save_override(const T&amp;, int) [with T = boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/archive/detail/interface_oarchive.hpp:64: instantiated from »Archive&amp; boost::archive::detail::interface_oarchive::operator&lt;&lt;(T&amp;) [with T = const boost::serialization::nvp, std::allocator &gt; &gt;, Archive = boost::mpi::detail::mpi_datatype_oarchive]« /usr/local/include/boost/serialization/collections_save_imp.hpp:60: instantiated from »void boost::serialization::stl::save_collection(Archive&amp;, const Container&amp;) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, Container = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:53: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int, mpl_::false_) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:123: instantiated from »void boost::serialization::save(Archive&amp;, const std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:45: instantiated from »static void boost::serialization::free_saver::invoke(Archive&amp;, const T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/split_free.hpp:74: instantiated from »void boost::serialization::split_free(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/serialization/vector.hpp:147: instantiated from »void boost::serialization::serialize(Archive&amp;, std::vector&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, U = std::basic_string, std::allocator &gt;, Allocator = std::allocator, std::allocator &gt; &gt;]« /usr/local/include/boost/serialization/serialization.hpp:133: instantiated from »void boost::serialization::serialize_adl(Archive&amp;, T&amp;, unsigned int) [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /usr/local/include/boost/archive/detail/oserializer.hpp:144: instantiated from »void boost::archive::detail::oserializer::save_object_data(boost::archive::detail::basic_oarchive&amp;, const void*) const [with Archive = boost::mpi::detail::mpi_datatype_oarchive, T = std::vector, std::allocator &gt;, std::allocator, std::allocator &gt; &gt; &gt;]« /home/languitar/workspace/iMN/src/algorithms/parallelScan/ParallelScan.cpp:128: instantiated from here /usr/local/include/boost/mpi/detail/mpi_datatype_oarchive.hpp:36: Fehler: keine passende Funktion für Aufruf von »assertion_failed(mpl_::failed*\*\*\*\*\*\*\*\*\*\*\* boost::mpi::is_mpi_datatype, std::allocator &gt; &gt;::\*\*\*\*\*\*\*\*\*\*\*\*)« make[2]: \*\*\* [src/CMakeFiles/imnbase.dir/algorithms/parallelScan/ParallelScan.cpp.o] Fehler 1 make[1]: \*\*\* [src/CMakeFiles/imnbase.dir/all] Fehler 2 make: \*\*\* [all] Fehler 2
</code></pre><p>Übersichtlich&hellip;</p>
]]></content></entry><entry><title>Highlights aus Graz</title><link rel="alternate" href="https://www.semipol.de/posts/2009/07/highlights-aus-graz/"/><id>https://www.semipol.de/posts/2009/07/highlights-aus-graz/</id><published>2009-07-11T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary> Doppelhaltestelle
Buchstabenschwund
Zeitloch</summary><content type="html"><![CDATA[<figure>
    <img loading="lazy" src="x7053021-218x300.jpg"
         alt="Doppelhaltestelle"/> <figcaption>
            <p>Doppelhaltestelle</p>
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="x7052923-300x110.jpg"
         alt="Buchstabenschwund"/> <figcaption>
            <p>Buchstabenschwund</p>
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="3710021639_0533beb4e1_o-300x93.jpg"
         alt="Zeitloch"/> <figcaption>
            <p>Zeitloch</p>
        </figcaption>
</figure>

]]></content></entry><entry><title>Enigmail gpg-agent Kommunikation unter KDE4 (Jaunty)</title><link rel="alternate" href="https://www.semipol.de/posts/2009/05/enigmail-gpg-agent-kommunikation-unter-kde4-jaunty/"/><id>https://www.semipol.de/posts/2009/05/enigmail-gpg-agent-kommunikation-unter-kde4-jaunty/</id><published>2009-05-16T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Enigmail hat auf meinem neuen Laptop mit dem kopierten Home-Directory den Dienst verweigert. Bevor ich überhaupt eine Passphrase eingeben konnte erschien bereits die Meldung, dass ich eine falsche eingegeben hätte. Das Problem war auf der Konsole dann noch etwas konkreter sichtbar:
gpg: Schwierigkeiten mit dem Agenten - Agent-Ansteuerung wird abgeschaltet Lange Rede, kurzer Sinn: der gpg-agent lief, aber ihm fehlte das entsprechende Programm um den Eingabedialog für das Passwort anzuzeigen. Da der gpg-agent von meiner KDE-Sitzung gestartet wurde, hat pinentry-qt gefehlt. Seltsamerweise wird in Jaunty unter KDE4 nicht pinentry-qt4 benutzt, was bereits installiert war.</summary><content type="html"><![CDATA[<p>Enigmail hat auf meinem neuen Laptop mit dem kopierten Home-Directory den Dienst verweigert. Bevor ich überhaupt eine Passphrase eingeben konnte erschien bereits die Meldung, dass ich eine falsche eingegeben hätte. Das Problem war auf der Konsole dann noch etwas konkreter sichtbar:</p>
<pre tabindex="0"><code>gpg: Schwierigkeiten mit dem Agenten - Agent-Ansteuerung wird abgeschaltet
</code></pre><p>Lange Rede, kurzer Sinn: der gpg-agent lief, aber ihm fehlte das entsprechende Programm um den Eingabedialog für das Passwort anzuzeigen. Da der gpg-agent von meiner KDE-Sitzung gestartet wurde, hat pinentry-qt gefehlt. Seltsamerweise wird in Jaunty unter KDE4 nicht pinentry-qt4 benutzt, was bereits installiert war.</p>
]]></content></entry><entry><title>Out-of-Source Builds mit CMake</title><link rel="alternate" href="https://www.semipol.de/posts/2009/03/out-of-source-builds-mit-cmake/"/><id>https://www.semipol.de/posts/2009/03/out-of-source-builds-mit-cmake/</id><published>2009-03-25T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>In der Java-Welt gibt es schon lange die sinnvolle Konvention kompilierte class-Dateien in einer anderen Verzeichnisstruktur abzulegen als den Quellcode. So eine eine Konvention hat viele Vorteile:
Falls der Quellcode in ein Versionskontrollsystem eingecheckt wird (und das sollte er auf jeden Fall), müssen nicht umständliche Regeln zum Excluden der kompilierten Dateien geschrieben werden. Dateioperationen im Source-Tree (z. B. ein Aufruf von find oder grep) müssen nicht aufwendig um die kompilierten Dateien herumgelenkt werden Leider ist dies in der C++-Welt teilweise noch nicht ganz angekommen, deshalb hier ein kurzer Reminder, wie solche &ldquo;Out-of-Source Builds&rdquo; mit CMake gemacht werden können.</summary><content type="html"><![CDATA[<p>In der Java-Welt gibt es schon lange die sinnvolle Konvention kompilierte class-Dateien in einer anderen Verzeichnisstruktur abzulegen als den Quellcode. So eine eine Konvention hat viele Vorteile:</p>
<ul>
<li>Falls der Quellcode in ein Versionskontrollsystem eingecheckt wird (und das sollte er auf jeden Fall), müssen nicht umständliche Regeln zum Excluden der kompilierten Dateien geschrieben werden.</li>
<li>Dateioperationen im Source-Tree (z. B. ein Aufruf von find oder grep) müssen nicht aufwendig um die kompilierten Dateien herumgelenkt werden</li>
</ul>
<p>Leider ist dies in der C++-Welt teilweise noch nicht ganz angekommen, deshalb hier ein kurzer Reminder, wie solche &ldquo;Out-of-Source Builds&rdquo; mit CMake gemacht werden können.</p>
<p>Das schöne an CMake ist, dass man eigentlich gar nichts tun muss, um ein Out-of-Source Build zu erstellen. Angenommen die Projektstruktur sie so aus:</p>
<pre tabindex="0"><code>languitar@bird /tmp/cmakeexample $ find .
./bin
./src
./src/yourCodeHere.cpp
./CMakeLists.txt
</code></pre><p>Um jetzt ein Out-of-Source Build zu erstellen, bei dem alle kompilierten Dateien in <code>bin</code> abgelegt werden, reicht es in das <code>bin</code>-Verzeichnis zu navigieren und dort <code>cmake ..</code> aufzurufen. Alle Dateien, die CMake intern benötigt, inklusive des generierten Makefiles,  und alle Ergebnisse des Compilers / Linkers werden so in <code>bin</code> angelegt und sowohl <code>src</code> als auch der Projektordner bleiben unangetastet. Diese Vorgehen hat bei CMake auch noch einen besonderen Vorteil: Eigentlich sollte CMake Änderungen an der <code>CMakeLists.txt</code> eigenständig feststellen und das Makefile neu generieren beim Bauen. Das klappt des Öfteren jedoch nicht richtig. Hätte man CMake im Projektverzeichnis aufgerufen müsste man dort jetzt mühselig alle von ihm generierten Dateien wie den <code>CMakeCache.txt</code> löschen um von vorne anzufangen. Im Falle eines Out-of-Source Builds kann man hingegen bedenkenlos und einfach den Build-Ordner leeren.</p>
<p>Ein paar Kleinigkeiten muss man für saubere Out-of-Source Builds mit CMake allerdings doch noch beachten. Auch wenn CMake das eigentliche Bauen und das Verwalten der internen Dateien sauber im Build-Ordner durchführt, verhindert es keine Fehler durch den Anwender. Falls man CMake z. B. noch selbst benutzt um Dateien zu generieren (z. B. pkg-config Files) sollten diese auch im Build-Ordner erstellt werden. Dieses Verzeichnis kann man in CMake mit den Variablen <code>CMAKE_BINARY_DIR</code> bzw. <code>CMAKE_CURRENT_BINARY_DIR</code> abfragen. Dateien sollten also immer über diese Variablen gespeichert werden und nicht über <code>CMAKE_SOURCE_DIR</code> bzw. <code>CMAKE_CURRENT_SOURCE_DIR</code>. Im Falle eines &ldquo;In-Source&rdquo; Builds (also der Aufruf <code>cmake .</code> im Projektordner) zeigen <code>CMAKE_BINARY_DIR</code> und <code>CMAKE_SOURCE_DIR</code> etc. übrigens auf dieselben Verzeichnisse.</p>
]]></content></entry><entry><title>Tücken des Observer-Patterns in Java</title><link rel="alternate" href="https://www.semipol.de/posts/2009/03/t%C3%BCcken-des-observer-patterns-in-java/"/><id>https://www.semipol.de/posts/2009/03/t%C3%BCcken-des-observer-patterns-in-java/</id><published>2009-03-18T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Alle paar Monate stolper ich in irgendwelchem Code über das gleiche Problem bei der Implementierung des Observer-Patterns in Java. Deshalb hier noch mal ein kurzer Reminder, was man beachten sollte.
Häufig sieht man Implementierungen wie diese:
public class ObserverTest { private static interface Observer { void process(); } private static Set observers = new HashSet(); public static void addObserver(Observer observer) { observers.add(observer); } public static void removeObserver(Observer observer) { observers.remove(observer); } private static void notifyObservers() { for (Observer o : observers) { o.process(); } } // es fehlt noch eine main-Methode } Das funktioniert so auch in vielen Fällen problemlos, in folgendem Fall aber nicht:</summary><content type="html"><![CDATA[<p>Alle paar Monate stolper ich in irgendwelchem Code über das gleiche Problem bei der Implementierung des Observer-Patterns in  Java. Deshalb hier noch mal ein kurzer Reminder, was man beachten sollte.</p>
<p>Häufig sieht man Implementierungen wie diese:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ObserverTest</span> {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">Observer</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">process</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Set observers <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">addObserver</span>(Observer observer) {
</span></span><span style="display:flex;"><span>        observers.<span style="color:#a6e22e">add</span>(observer);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">removeObserver</span>(Observer observer) {
</span></span><span style="display:flex;"><span>        observers.<span style="color:#a6e22e">remove</span>(observer);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">notifyObservers</span>() {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> (Observer o : observers) {
</span></span><span style="display:flex;"><span>            o.<span style="color:#a6e22e">process</span>();
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// es fehlt noch eine main-Methode</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Das funktioniert so auch in vielen Fällen problemlos, in folgendem Fall aber nicht:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span>(String<span style="color:#f92672">[]</span> args) {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    addObserver(<span style="color:#66d9ef">new</span> Observer() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">process</span>() {
</span></span><span style="display:flex;"><span>            removeObserver(<span style="color:#66d9ef">this</span>);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    notifyObservers();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Führt man das Programm so aus, wirft Java eine ConcurrentModificationException:</p>
<pre tabindex="0"><code>Exception in thread &#34;main&#34; java.util.ConcurrentModificationException
    at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
    at java.util.LinkedList$ListItr.next(LinkedList.java:696)
    at ObserverTest.notifyObservers(ObserverTest.java:21)
    at ObserverTest.main(ObserverTest.java:37)
</code></pre><p>Das Problem hier ist, dass eigentlich alle Standardimplementationen von Collection keine Änderung beim iterieren zulassen. Diese Beschränkung sollte man normalerweise aber nicht an die Observer weiterreichen, da sie deren Handlungsfähigkeit stark einschränkt (ein üblicher Anwendungsfall ist, dass sich ein Observer abmeldet, wenn er die gewünschte Information erhalten hat). Zum Glück gibt es eine sehr einfache Lösung für dieses Problem: vor dem Iterieren holt man sich eine Kopie der Collection und iteriert über diese (hierbei muss beachtet werden, dass es eine &ldquo;shallow copy&rdquo; ist, also die Elemente selbst nicht Kopiert werden, nur der Container).</p>
<p>Mit folgender Modifikation läuft der Code also problemlos durch:</p>
<pre tabindex="0"><code>private static void notifyObservers() {
    Set observersCopy = new HashSet(observers);
    for (Observer o : observersCopy) {
        o.process();
    }
}
</code></pre>]]></content></entry><entry><title>Google - Diese Website kann Ihren Computer beschädigen.</title><link rel="alternate" href="https://www.semipol.de/posts/2009/01/google-diese-website-kann-ihren-computer-besch%C3%A4digen./"/><id>https://www.semipol.de/posts/2009/01/google-diese-website-kann-ihren-computer-besch%C3%A4digen./</id><published>2009-01-31T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Google meint es wohl gerade etwas zu gut damit arme Internetnutzer vor den Gefahren des WWW zu warnen und stuft das komplette Internet als Malware-gefährdet ein - inklusive sich selbst.
Google - Diese Website kann Ihren Computer beschädigen.
Vielleicht wird es doch Zeit, sich nach einer Alternative umzuschauen&hellip;</summary><content type="html"><![CDATA[<p>Google meint es wohl gerade etwas zu gut damit arme Internetnutzer vor den Gefahren  des WWW zu warnen und stuft das komplette Internet als Malware-gefährdet ein - inklusive sich selbst.</p>
<figure>
    <img loading="lazy" src="google-238x300.png"
         alt="Google - Diese Website kann Ihren Computer beschädigen"/> <figcaption>
            <p>Google - Diese Website kann Ihren Computer beschädigen.</p>
        </figcaption>
</figure>

<p>Vielleicht wird es doch Zeit, sich nach einer Alternative umzuschauen&hellip;</p>
]]></content></entry><entry><title>OpenCV Buch</title><link rel="alternate" href="https://www.semipol.de/posts/2008/12/opencv-buch/"/><id>https://www.semipol.de/posts/2008/12/opencv-buch/</id><published>2008-12-21T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Die Dokumentation von OpenCV ist ja nicht unbedingt immer gut und in letzter Zeit gab es häufiger mal Probleme mit dem ansonsten recht brauchbaren Wiki. Wer eine gute und ausfallsichere Referenz für OpenCV sucht, sollte sich &ldquo;OpenCV - Learning Computer Vision with the OpenCV Library&rdquo; von Gary Bradski und Adrian Kaehler anschauen. Neben einer guten Referenz für OpenCV bietet dieses Buch auch nützliches Hintergrundwissen und Erklärungen zu den verwendeten Algorithmen und Techniken.</summary><content type="html"><![CDATA[<p>Die Dokumentation von <a href="http://opencv.willowgarage.com/wiki/" title="OpenCV">OpenCV</a> ist ja nicht unbedingt immer gut und in letzter Zeit gab es häufiger mal Probleme mit dem ansonsten recht brauchbaren <a href="http://opencv.willowgarage.com/wiki/" title="OpenCV Wiki">Wiki</a>. Wer eine gute und ausfallsichere Referenz für OpenCV sucht, sollte sich &ldquo;OpenCV - Learning Computer Vision with the OpenCV Library&rdquo; von Gary Bradski und Adrian Kaehler anschauen. Neben einer guten Referenz für OpenCV bietet dieses Buch auch nützliches Hintergrundwissen und Erklärungen zu den verwendeten Algorithmen und Techniken.</p>
<figure>
    <img loading="lazy" src="9780596516130_cat.gif"
         alt="OpenCV - Learning Computer Vision with the OpenCV Library"/> <figcaption>
            <p>OpenCV - Learning Computer Vision with the OpenCV Library</p>
        </figcaption>
</figure>

<p>Das Buch ist unter der ISBN 978-0-596-51613-0 bei O&rsquo;Reilly erschienen.</p>
]]></content></entry><entry><title>Kurioses aus Manpages</title><link rel="alternate" href="https://www.semipol.de/posts/2008/11/kurioses-aus-manpages/"/><id>https://www.semipol.de/posts/2008/11/kurioses-aus-manpages/</id><published>2008-11-13T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Gerade in der Manpage zu dpkg gefunden:
-DOktal, --debug=Oktal [...] --debug=help zeigen diese Debugging-Werte an. Nummer Beschreibung 1 Allgemein hilfreiche Fortschrittsinformationen 2 Aufruf und Status der Betreuerskripte 10 Ausgabe für jede verarbeitete Datei 100 Umfangreiche Ausgabe für jede verarbeitete Datei 20 Ausgabe für jede Konfigurationsdatei 200 Umfangreiche Ausgabe für jede Konfigurationsdatei 40 Abhängigkeiten und Konflikte 400 Umfangreiche Abhängigkeiten/Konflikte-Ausgabe 10000 Trigger-Aktivierung und -Verarbeitung 20000 Umfangreiche Ausgabe bezüglich Trigger 40000 Alberne Menge an Ausgabe bezüglich Trigger 1000 Umfangreiches Gelaber beispielsweise über das dpkg/info-Verzeichnis 2000 Verrückte Mengen an Gelaber Seltsamerweise findet sich das nicht in der Online-Version dieser Manpage auf der Ubuntu-Seite&hellip;</summary><content type="html"><![CDATA[<p>Gerade in der <a href="http://de.wikipedia.org/wiki/Manpage" title="Manpage">Manpage</a> zu <a href="http://de.wikipedia.org/wiki/Dpkg" title="dpkg">dpkg</a> gefunden:</p>
<pre><code>       -DOktal, --debug=Oktal
              [...]
              --debug=help zeigen diese Debugging-Werte an.

                Nummer  Beschreibung
                    1   Allgemein hilfreiche Fortschrittsinformationen
                    2   Aufruf und Status der Betreuerskripte
                   10   Ausgabe für jede verarbeitete Datei
                  100   Umfangreiche Ausgabe für jede verarbeitete Datei
                   20   Ausgabe für jede Konfigurationsdatei
                  200   Umfangreiche Ausgabe für jede Konfigurationsdatei
                   40   Abhängigkeiten und Konflikte
                  400   Umfangreiche Abhängigkeiten/Konflikte-Ausgabe
                10000   Trigger-Aktivierung und -Verarbeitung
                20000   Umfangreiche Ausgabe bezüglich Trigger
                40000   Alberne Menge an Ausgabe bezüglich Trigger
                 1000   Umfangreiches Gelaber beispielsweise über das dpkg/info-Verzeichnis
                 2000   Verrückte Mengen an Gelaber
</code></pre>
<p>Seltsamerweise findet sich das nicht in der Online-Version dieser Manpage auf der Ubuntu-Seite&hellip;</p>
]]></content></entry><entry><title>Geocaching</title><link rel="alternate" href="https://www.semipol.de/posts/2008/11/geocaching/"/><id>https://www.semipol.de/posts/2008/11/geocaching/</id><published>2008-11-12T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Vor gut zwei Wochen habe ich mir ein Garmin eTrex H GPS-Gerät geleistet, vor allem um Fotos problemloser &ldquo;geotaggen&rdquo; zu können. Da ich in den letzten Wochen aber noch nicht wieder zum Fotografieren gekommen bin und das Wetter ja eh nicht zu gut war musste das eTrex anders beschäftigt werden. Also hab ich mich heute mal wieder aufs Rad gesetzt und etwas &ldquo;geogecached&rdquo;. Die gefahrene Route gibts im Google Earth-Screenshot. Habe natürlich gleich beim ersten Multicache erfahren, dass es keine gute Idee ist alte Cache-Beschreibungen zu benutzen. Die Beschreibung hatte ich am 1.11. ausgedruckt, weil ich mir den Cache eigentlich da schon anschauen wollte, bin dann aber doch nicht dazu gekommen. Am 2.11. wurde er dann komplett überarbeitet. So stand ich dann heute vor einem verlassenen Baumstumpf&hellip;</summary><content type="html"><![CDATA[<p>Vor gut zwei Wochen habe ich mir ein <a href="https://buy.garmin.com/shop/shop.do?cID=144&amp;pID=8705" title="Garmin eTrex H">Garmin eTrex H</a> GPS-Gerät geleistet, vor allem um Fotos problemloser &ldquo;geotaggen&rdquo; zu können. Da ich in den letzten Wochen aber noch nicht wieder zum Fotografieren gekommen bin und das Wetter ja eh nicht zu gut war musste das eTrex anders beschäftigt werden. Also hab ich mich heute mal wieder aufs Rad gesetzt und etwas &ldquo;geogecached&rdquo;. Die gefahrene Route gibts im <a href="http://earth.google.de/" title="Google Earth">Google Earth</a>-Screenshot. Habe natürlich gleich beim ersten Multicache erfahren, dass es keine gute Idee ist alte Cache-Beschreibungen zu benutzen. Die Beschreibung hatte ich am 1.11. ausgedruckt, weil ich mir den Cache eigentlich da schon anschauen wollte, bin dann aber doch nicht dazu gekommen. Am 2.11. wurde er dann komplett überarbeitet. So stand ich dann heute vor einem verlassenen Baumstumpf&hellip;</p>
<figure>
    <img loading="lazy" src="geocaching-300x148.png"
         alt="Geocaching in Halle und Umgebung"/> <figcaption>
            <p>Geocaching in Halle und Umgebung, unterwegs mit dem Rad.</p>
        </figcaption>
</figure>

]]></content></entry><entry><title>Sichtbarkeiten beachten mit Hibernate Search / Lucene</title><link rel="alternate" href="https://www.semipol.de/posts/2008/10/sichtbarkeiten-beachten-mit-hibernate-search-/-lucene/"/><id>https://www.semipol.de/posts/2008/10/sichtbarkeiten-beachten-mit-hibernate-search-/-lucene/</id><published>2008-10-06T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Für ein Projekt musste ich einen Suchmechanismus implementieren. Die Wahl von Hibernate Search war dabei auf Grund vieler Vorteile für das Projekt klar. Allerdings gab es eine Besonderheit in diesem Projekt, die ich bei der Suche beachten musste und für die ich keine existierende Lösung gefunden habe: Bestimmte Einträge der zu indizierenden Entitäten sind nur dann sichtbar, wenn der Nutzer, der die Suche ausführt, eingelogged ist. Diese Einträge sollten aber auf jeden Fall durchsucht werden können. Nach längerer Recherche habe ich keine existierende Lösung gefunden, die diesem Problem begegnet, daher habe ich einen eigenen Ansatz verfolgt.</summary><content type="html"><![CDATA[<p>Für ein Projekt musste ich einen Suchmechanismus implementieren. Die Wahl von <a href="http://www.hibernate.org/410.html" title="Hibernate Search">Hibernate Search</a> war dabei auf Grund vieler Vorteile für das Projekt klar. Allerdings gab es eine Besonderheit in diesem Projekt, die ich bei der Suche beachten musste und für die ich keine existierende Lösung gefunden habe: Bestimmte Einträge der zu indizierenden Entitäten sind nur dann sichtbar, wenn der Nutzer, der die Suche ausführt, eingelogged ist. Diese Einträge sollten aber auf jeden Fall durchsucht werden können. Nach längerer Recherche habe ich keine existierende Lösung gefunden, die diesem Problem begegnet, daher habe ich einen eigenen Ansatz verfolgt.</p>
<p>Die Entität wird normal mittels der Hibernate Search Annotationen indiziert, für alle Einträge, deren Sichtbarkeit geregelt werden kann, wird jedoch eine eigene <a href="http://www.hibernate.org/hib_docs/search/api/org/hibernate/search/bridge/FieldBridge.html" title="FieldBridge">FieldBridge</a> benutzt, die als Feldnamen für das <a href="http://lucene.apache.org/java/docs/">Lucene</a>-Document eine Kombination aus Sichtbarkeit und gewünschtem Feldnamen benutzt, so dass die Einträge im Document am Ende so aussehen könnten:</p>
<pre><code>EXTERNAL_name: Mr. X
COMMUNITY_name: Mr. X
EXTERNAL_project: XYZ
COMMUNITY_age: 24
COMMUNITY_phone: 1234567890
</code></pre>
<p>Wichtig für meinen Ansatz ist, dass Einträge, die für alle sichtbar sind, zusätzlich auch mit der Sichtbarkeit für eingeloggte Nutzer gespeichert werden (oder falls es noch mehr Levels gibt entsprechend auch für alle alle weiteren &ldquo;kleineren&rdquo; Levels).</p>
<p>Die Frage ist nun, wie in einem so strukturierten Dokument gesucht wird. Ich habe dafür leider keine Lösung gefunden, die den existierenden Parser für Suchausdrücke von Lucene benutzten kann. Daher wird zunächst eine eigener Parser benötigt, der z. B. mit <a href="https://javacc.dev.java.net/" title="javacc">javacc</a> implementiert werden kann. Die grundsätzliche Idee ist nun, dass dieser Parser mittels der <a href="http://lucene.apache.org/java/2_3_2/api/core/index.html">Lucene API</a> Suchausdrücke auf den im Document gespeicherten Feldern (hier also &ldquo;name&rdquo;, &ldquo;project&rdquo;, &ldquo;age&rdquo; und &ldquo;phone&rdquo;) baut und dabei vor jeden Feldnamen das gerade notwendige Sichtbarkeitslevel (&ldquo;COMMUNITY&rdquo; oder &ldquo;EXTERNAL&rdquo;) schreibt, so dass nur auf den Feldern des entsprechenden Levels gesucht werden kann.</p>
]]></content></entry><entry><title>Oft genutzte Test-Fixtures zentral initialisieren mit JUnit 4</title><link rel="alternate" href="https://www.semipol.de/posts/2008/10/oft-genutzte-test-fixtures-zentral-initialisieren-mit-junit-4/"/><id>https://www.semipol.de/posts/2008/10/oft-genutzte-test-fixtures-zentral-initialisieren-mit-junit-4/</id><published>2008-10-05T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Häufig kommt es beim (Unit) Testing vor, dass viele der Test Cases zumindest teilweise eine gemeinsame Fixture brauchen. So z. B. wenn einige der getesteten Klassen gegen eine Testdatenbank laufen. Hierbei muss sichergestellt werden, dass die Datenbank richtig initialisiert und wieder heruntergefahren wird und sich vor jedem Test im gleichen Zustand befindet. JUnit 4 bietet eine interessante Möglichkeit diese Vorgänge zentral und ohne Code-Duplizierung auszulagern. Damit jede Test-Methode (Annotation @Test in Junit 4) die gleiche Fixture zur Verfügung hat, wird diese üblicherweise in setUp- und tearDown-Methoden hergestellt. Um nicht in jeder von der Datenbank abhängigen Test-Klassen den Datenbank-Code hierin zu duplizieren, ist es mit JUnit 4 möglich eine Basisklasse für alle von der Datenbank abhängigen Tests zu benutzen, die diese Aufgabe übernimmt:</summary><content type="html"><![CDATA[<p>Häufig kommt es beim (Unit) Testing vor, dass viele der Test Cases zumindest teilweise eine gemeinsame Fixture brauchen. So z. B. wenn einige der getesteten Klassen gegen eine Testdatenbank laufen. Hierbei muss sichergestellt werden, dass die Datenbank richtig initialisiert und wieder heruntergefahren wird und sich vor jedem Test im gleichen Zustand befindet. JUnit 4 bietet eine interessante Möglichkeit diese Vorgänge zentral und ohne Code-Duplizierung auszulagern. Damit jede Test-Methode (Annotation @Test in Junit 4) die gleiche Fixture zur Verfügung hat, wird diese üblicherweise in setUp- und tearDown-Methoden hergestellt. Um nicht in jeder von der Datenbank abhängigen Test-Klassen den Datenbank-Code hierin zu duplizieren, ist es mit JUnit 4 möglich eine Basisklasse für alle von der Datenbank abhängigen Tests zu benutzen, die diese Aufgabe übernimmt:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> org.junit.After;
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.junit.Before;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">DatabaseTestCase</span> {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Before</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initDatabase</span>() {
</span></span><span style="display:flex;"><span>        System.<span style="color:#a6e22e">out</span>.<span style="color:#a6e22e">println</span>(<span style="color:#e6db74">&#34;Initializing DB&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// init db stuff</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@After</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">clearDatabase</span>() {
</span></span><span style="display:flex;"><span>        System.<span style="color:#a6e22e">out</span>.<span style="color:#a6e22e">println</span>(<span style="color:#e6db74">&#34;Clearing DB&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// set db to old state</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Ein konkreter Test, der die Datenbank benutzt, könnte dann wie folgt aussehen:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> org.junit.After;
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.junit.Before;
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.junit.Test;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FooDBTest</span> <span style="color:#66d9ef">extends</span> DatabaseTestCase {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Before</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setUp</span>() {
</span></span><span style="display:flex;"><span>        System.<span style="color:#a6e22e">out</span>.<span style="color:#a6e22e">println</span>(<span style="color:#e6db74">&#34;Initializing test case&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Test</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">test</span>() {
</span></span><span style="display:flex;"><span>        System.<span style="color:#a6e22e">out</span>.<span style="color:#a6e22e">println</span>(<span style="color:#e6db74">&#34;I should test the DB&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@After</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">tearDown</span>() {
</span></span><span style="display:flex;"><span>        System.<span style="color:#a6e22e">out</span>.<span style="color:#a6e22e">println</span>(<span style="color:#e6db74">&#34;Tear down of test case&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Der entscheidende Punkt hier ist, dass JUnit 4 versichert, dass die mit @Before gekennzeichneten Methoden einer Oberklasse garantiert vor den mit @Before gekennzeichneten Methoden der Unterklasse und mit @After markierte Methoden der Oberklasse erst nach den mit @After markierten Methoden der Unterklasse aufgerufen werden. D. h. FooDBTest kann auch in seiner setUp-Methode schon davon ausgehen, dass die Datenbank initialisiert ist.</p>
<p>Dieses Verhalten lässt sich natürlich auch für jede beliebige andere Test-Fixture benutzen.</p>
]]></content></entry><entry><title>Eclipse-Fangfragen</title><link rel="alternate" href="https://www.semipol.de/posts/2008/09/eclipse-fangfragen/"/><id>https://www.semipol.de/posts/2008/09/eclipse-fangfragen/</id><published>2008-09-23T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Eclipse auf amd64 ist ja schon eine Herausforderung. Egal was man tut, es stürzt ständig ab. Heute war es mal so gnädig und hat statt eines Absturzes eine äußerst sinnvolle Frage gestellt:
Wer hat schon gerne Probleme?
Zumindest auf meinem Rechner reproduzierbar beim Kopieren einer HTML-Datei im Package-Explorer in die Zwischenablage.</summary><content type="html"><![CDATA[<p>Eclipse auf amd64 ist ja schon eine Herausforderung. Egal was man tut, es stürzt ständig ab. Heute war es mal so gnädig und hat statt eines Absturzes eine äußerst sinnvolle Frage gestellt:</p>
<figure>
    <img loading="lazy" src="eclipse-300x83.png"
         alt="Eclipse-Dialog"/> <figcaption>
            <p>Wer hat schon gerne Probleme?</p>
        </figcaption>
</figure>

<p>Zumindest auf meinem Rechner reproduzierbar beim Kopieren einer HTML-Datei im Package-Explorer in die Zwischenablage.</p>
]]></content></entry><entry><title>Gutes Hugin Tutorial</title><link rel="alternate" href="https://www.semipol.de/posts/2008/08/gutes-hugin-tutorial/"/><id>https://www.semipol.de/posts/2008/08/gutes-hugin-tutorial/</id><published>2008-08-29T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary> Tunnel auf der Radroute am Telemarkkanal (gestitched mit Hugin)
Für die Fotos aus Norwegen benutze ich gerade mal wieder den OpenSource Panorama Stitcher Hugin, der in aller Regeln schon hervorragende Ergebnisse liefert. Bei einigen schwierigeren Aufnahmen hat mir allerdings bisher der Background gefehlt, um die entsprechende Parameter zu optimieren. Auf der Suche nach einer guten Erklärung dazu bin ich über dieses Tutorial gestolpert, das viele Tipps mit wesentlich mehr fachlichem Hintergrund gibt, als andere Tutorials für Hugin.</summary><content type="html"><![CDATA[<figure>
    <img loading="lazy" src="tunnel_panorama_small-84x300.jpg"
         alt="Tunnel auf der Radroute am Telemarkkanal"/> <figcaption>
            <p>Tunnel auf der Radroute am Telemarkkanal (gestitched mit Hugin)</p>
        </figcaption>
</figure>

<p>Für die Fotos aus Norwegen benutze ich gerade mal wieder den OpenSource Panorama Stitcher <a href="http://hugin.sourceforge.net/" title="Hugin">Hugin</a>, der in aller Regeln schon hervorragende Ergebnisse liefert. Bei einigen schwierigeren Aufnahmen hat mir allerdings bisher der Background gefehlt, um die entsprechende Parameter zu optimieren. Auf der Suche nach einer guten Erklärung dazu bin ich über <a href="http://freenet-homepage.de/martin_wehner/Tutorial/panorama.html" title="Hugin-Tutorial: Panoramailder erstellen">dieses Tutorial</a> gestolpert, das viele Tipps mit wesentlich mehr fachlichem Hintergrund gibt, als andere Tutorials für Hugin.</p>
]]></content></entry><entry><title>Neulich im Westend</title><link rel="alternate" href="https://www.semipol.de/posts/2008/08/neulich-im-westend/"/><id>https://www.semipol.de/posts/2008/08/neulich-im-westend/</id><published>2008-08-27T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary> Westend Speiseplan</summary><content type="html"><![CDATA[<figure>
    <img loading="lazy" src="bild031-300x236.jpg"
         alt="Westend Speiseplan"/> <figcaption>
            <p>Westend Speiseplan</p>
        </figcaption>
</figure>

]]></content></entry><entry><title>Öffnungszeiten in Norwegen</title><link rel="alternate" href="https://www.semipol.de/posts/2008/08/%C3%B6ffnungszeiten-in-norwegen/"/><id>https://www.semipol.de/posts/2008/08/%C3%B6ffnungszeiten-in-norwegen/</id><published>2008-08-25T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Öffnungszeiten sind in Norwegen ein weit dehnbarer Begriff:
Öffnungszeiten in Norwegen
Gefunden an einem kombinierten Möbelladen, Künstleratelier und Bootsverleih.</summary><content type="html"><![CDATA[<p>Öffnungszeiten sind in Norwegen ein weit dehnbarer Begriff:</p>
<figure>
    <img loading="lazy" src="bild033b-300x240.jpg"
         alt="Öffnungszeiten in Norwegen"/> <figcaption>
            <p>Öffnungszeiten in Norwegen</p>
        </figcaption>
</figure>

<p>Gefunden an einem kombinierten Möbelladen, Künstleratelier und Bootsverleih.</p>
]]></content></entry><entry><title>Urlaub :)</title><link rel="alternate" href="https://www.semipol.de/posts/2008/08/urlaub/"/><id>https://www.semipol.de/posts/2008/08/urlaub/</id><published>2008-08-08T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Nach zwei Jahren ohne Urlaub ist es jetzt endlich wieder so weit. Gestern war die letzte Prüfung im Bachelor und ich muss jetzt nur noch auf die Note meiner Bachelorarbeit warten. Bis dahin habe ich zum ersten Mal wieder halbwegs freie Semesterferien (vorlesungsfreie Zeit). Die sind dann gestern auch spontan mit zwei Wochen Norwegen auf dem Rad und per Kanu verplant worden. Montag gehts los. So spontan war der Urlaub dann doch noch nie. Heute war großes Ausrüstungskaufen angesagt. Teurer Spaß&hellip; aber man sieht es dem Fahrrad jetzt an.</summary><content type="html"><![CDATA[<p>Nach zwei Jahren ohne Urlaub ist es jetzt endlich wieder so weit. Gestern war die letzte Prüfung im Bachelor und ich muss jetzt nur noch auf die Note meiner Bachelorarbeit warten. Bis dahin habe ich zum ersten Mal wieder halbwegs freie Semesterferien (vorlesungsfreie Zeit). Die sind dann gestern auch spontan mit zwei Wochen Norwegen auf dem Rad und per Kanu verplant worden. Montag gehts los. So spontan war der Urlaub dann doch noch nie. Heute war großes Ausrüstungskaufen angesagt. Teurer Spaß&hellip; aber man sieht es dem Fahrrad jetzt an.</p>
<figure>
    <img loading="lazy" src="bild035-300x240.jpg"
         alt="Fahrradausrüstung für Norwegen"/> <figcaption>
            <p>Fahrradausrüstung für Norwegen</p>
        </figcaption>
</figure>

<p>Soweit man überhaupt irgendwas an diesem Urlaub geplant nennen darf, ist es die <a href="http://www.bike-norway.com/Rute.asp?ID=2&amp;KID=34&amp;lang=ENG" title="Radroute am Telemarkkanal">Route entlang des Telemarkkanals</a>. Diese wollen wir die erste Woche mit dem Rad fahren und dann je nach Stimmung entweder mit Kanus zurück oder mit einem Boot an einem Tag und dann auf einem anderen Gewässer Kanu fahren.</p>
]]></content></entry><entry><title>Aktueller CD-Tipp: Pat Metheny - Secret Story</title><link rel="alternate" href="https://www.semipol.de/posts/2008/08/aktueller-cd-tipp-pat-metheny-secret-story/"/><id>https://www.semipol.de/posts/2008/08/aktueller-cd-tipp-pat-metheny-secret-story/</id><published>2008-08-02T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Eine meiner Lieblings-CDs zur Zeit ist das Album &ldquo;Secret Story&rdquo; von Pat Metheny. Zu Pat Metheny als Gitarristen muss man vermutlich nicht viel sagen, zu Secret Story jedoch schon. Ein wirklich interessantes Album, das musikalisch die gleiche Bandbreite abdeckt wie das Cover-Bild Kunstrichtungen. Dabei lädt die Musik vor allem zum Entspannen ein. Besonders gelungen finde ich den Titel &ldquo;Finding and Believing&rdquo;, der sich langsam von einem verschlungenen Anfangsteil zu einem sehr harmonischen Ende hin entwickelt.</summary><content type="html"><![CDATA[<p>Eine meiner Lieblings-CDs zur Zeit ist das Album &ldquo;Secret Story&rdquo; von Pat Metheny. Zu Pat Metheny als Gitarristen muss man vermutlich nicht viel sagen, zu Secret Story jedoch schon. Ein wirklich interessantes Album, das musikalisch die gleiche Bandbreite abdeckt wie das Cover-Bild Kunstrichtungen. Dabei lädt die Musik vor allem zum Entspannen ein. Besonders gelungen finde ich den Titel &ldquo;Finding and Believing&rdquo;, der sich langsam von einem verschlungenen Anfangsteil zu einem sehr harmonischen Ende hin entwickelt.</p>
<figure>
    <img loading="lazy" src="51eabak3zjl_ss400_-300x300.jpg"
         alt="Path Metheny - Secret Story"/> <figcaption>
            <p>Path Metheny - Secret Story</p>
        </figcaption>
</figure>

]]></content></entry><entry><title>OpenCV-Tutorial</title><link rel="alternate" href="https://www.semipol.de/posts/2008/07/opencv-tutorial/"/><id>https://www.semipol.de/posts/2008/07/opencv-tutorial/</id><published>2008-07-16T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Im Rahmen der Veranstaltung &ldquo;Computer Vision Toolkits - Vom Sensor zu System&rdquo; in diesem Semester, habe ich ein Tutorial über OpenCV, die &ldquo;Open Source Computer Vision Library&rdquo;, geschrieben, dass den grundsätzlichen Umgang mit ihr beschreibt. Da das für den ein oder anderen sicher interessant ist, gibt es das Tutorial jetzt auch hier online.
Tutorial: OpenCV Tutorial (PDF)</summary><content type="html"><![CDATA[<p>Im Rahmen der Veranstaltung &ldquo;Computer Vision Toolkits - Vom Sensor zu System&rdquo; in diesem Semester, habe ich ein Tutorial über <a href="http://www.intel.com/technology/computing/opencv/index.htm" title="OpenCV Website">OpenCV</a>, die &ldquo;Open Source Computer Vision Library&rdquo;, geschrieben, dass den grundsätzlichen Umgang mit ihr beschreibt. Da das für den ein oder anderen sicher interessant ist, gibt es das Tutorial jetzt auch hier online.</p>
<ul>
<li>Tutorial: <a href="opencv-tutorial.pdf">OpenCV Tutorial (PDF)</a></li>
</ul>
]]></content></entry><entry><title>Speiseplan mit Tücken</title><link rel="alternate" href="https://www.semipol.de/posts/2008/07/speiseplan-mit-t%C3%BCcken/"/><id>https://www.semipol.de/posts/2008/07/speiseplan-mit-t%C3%BCcken/</id><published>2008-07-16T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Ich hab gerade in einer Ecke des Desktops einen alten Screenshot von einem Mensaspeiseplan wiedergefunden. Der Schreiber dieses Plans hatte wohl schon etwas getrunken oder so&hellip;
Was für eine Soße?
Viel Bockwurst!
Wo wohl der Unterschied zwischen Bockwurst und Bockwurst(1,2,3) ist?</summary><content type="html"><![CDATA[<p>Ich hab gerade in einer Ecke des Desktops einen alten Screenshot von einem Mensaspeiseplan wiedergefunden. Der Schreiber dieses Plans hatte wohl schon etwas getrunken oder so&hellip;</p>
<figure>
    <img loading="lazy" src="speiseplan1.png"
         alt="Foto vom Mensaspeiseplan"/> <figcaption>
            <p>Was für eine Soße?</p>
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="speiseplan2.png"
         alt="Foto vom Mensaspeiseplan"/> <figcaption>
            <p>Viel Bockwurst!</p>
        </figcaption>
</figure>

<p>Wo wohl der Unterschied zwischen Bockwurst und Bockwurst(1,2,3) ist?</p>
]]></content></entry><entry><title>Grundregeln des API-Designs</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/grundregeln-des-api-designs/"/><id>https://www.semipol.de/posts/2008/06/grundregeln-des-api-designs/</id><published>2008-06-24T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>API-Design ist sicherlich keine einfache Sachen, aber es gibt schon ein paar Grundregeln, an die man sich relativ problemlos halten kann. Ein gute Auflistung dieser Regeln liefert z.B. der Blog Eintrag &ldquo;API Design Guidelines&rdquo;.
Einer der wichtigsten Punkte wird im genannten Text unter &ldquo;Be intuitive&rdquo; aufgeführt: &ldquo;Use consistent parameter ordering across methods&rdquo;. Dazu ein Beispiel aus der C API, über das ich heute dank Segfault gestolpert bin:
int puts(char *s); int fputs(const char *s, FILE *stream); vs.</summary><content type="html"><![CDATA[<p>API-Design ist sicherlich keine einfache Sachen, aber es gibt schon ein paar Grundregeln, an die man sich relativ problemlos halten kann. Ein gute Auflistung dieser Regeln liefert z.B. der Blog Eintrag &ldquo;<a href="http://blog.isnotworking.com/2007/05/api-design-guidelines.html">API Design Guidelines</a>&rdquo;.</p>
<p>Einer der wichtigsten Punkte wird im genannten Text unter &ldquo;Be intuitive&rdquo; aufgeführt: &ldquo;Use consistent parameter ordering across methods&rdquo;. Dazu ein Beispiel aus der C API, über das ich heute dank Segfault gestolpert bin:</p>
<pre><code>int puts(char *s);
int fputs(const char *s, FILE *stream);
</code></pre>
<p>vs.</p>
<pre><code>int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
</code></pre>
<p><code>fprintf</code> erwartet den Stream als erstes Argument, während <code>fputs</code> ihn als letztes Argument erwartet. Nicht gerade konsistent und intuitiv. Und das ganze geht noch weiter: <code>puts</code> ist ja vor allem so praktisch, weil es sich selbst um das Newline-Zeichen kümmert. Warum kann <code>fputs</code> das dann nicht auch? &ldquo;fputs() schreibt die Zeichenkette s ohne sein nachfolgendes ’’ in den Ausgabestrom stream.&rdquo; (aus der Manpage).</p>
]]></content></entry><entry><title>Panoramas und andere schöne Fotos</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/panoramas-und-andere-sch%C3%B6ne-fotos/"/><id>https://www.semipol.de/posts/2008/06/panoramas-und-andere-sch%C3%B6ne-fotos/</id><published>2008-06-21T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Wikipedia ist ja eigentlich nicht der erste Anlaufpunkt für gute Fotos, aber mit etwas Glück findet man auch dort Sehenswertes. Einen Blick wert ist dort auf jeden Fall die Liste der exzellenten Bilder. Besonders zu empfehlen sind auch die Fotos des Users Diliff, der eine Menge beeindruckender Panoramas geschossen hat.</summary><content type="html"><![CDATA[<p>Wikipedia ist ja eigentlich nicht der erste Anlaufpunkt für gute Fotos, aber mit etwas Glück findet man auch dort Sehenswertes. Einen Blick wert ist dort auf jeden Fall die <a href="http://de.wikipedia.org/wiki/Wikipedia:Exzellente_Bilder">Liste der exzellenten Bilder</a>. Besonders zu empfehlen sind auch die <a href="http://en.wikipedia.org/wiki/User:Diliff">Fotos des Users Diliff</a>, der eine Menge beeindruckender Panoramas geschossen hat.</p>
]]></content></entry><entry><title>PyGTK Segfault durch bereits geladenes GTK</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/pygtk-segfault-durch-bereits-geladenes-gtk/"/><id>https://www.semipol.de/posts/2008/06/pygtk-segfault-durch-bereits-geladenes-gtk/</id><published>2008-06-17T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Seit zwei Wochen bastel ich mich jetzt schon um einen mir unerklärlichen Segfault beim Importieren von PyGTK herum. Heute hab ich dann endlich mal etwas Zeit gehabt das ganze genauer unter die Lupe zu nehmen. Das Modul in meinem Projekt, das die GUI-Funktionalität bereitstellt, enthält folgende Imports:
import pygtk pygtk.require('2.0') import gtk Bis zur require-Zeile ist das alles kein Problem, doch import gtk hat in manchen Situationen den Segfault ausgelöst. Seit heute weiß ich, dass dieser Segfault auftritt, wenn vorher bereits ein Modul geladen wurde, das gegen GTK gelinkt wurde, in meinem Projekt z.B. der loader:</summary><content type="html"><![CDATA[<p>Seit zwei Wochen bastel ich mich jetzt schon um einen mir unerklärlichen Segfault beim Importieren von <a href="http://www.pygtk.org/" title="PyGTK">PyGTK</a> herum. Heute hab ich dann endlich mal etwas Zeit gehabt das ganze genauer unter die Lupe zu nehmen. Das Modul in meinem Projekt, das die GUI-Funktionalität bereitstellt, enthält folgende Imports:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> pygtk
</span></span><span style="display:flex;"><span>pygtk<span style="color:#f92672">.</span>require(<span style="color:#e6db74">&#39;2.0&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> gtk
</span></span></code></pre></div><p>Bis zur require-Zeile ist das alles kein Problem, doch <code>import gtk</code> hat in manchen Situationen den Segfault ausgelöst. Seit heute weiß ich, dass dieser Segfault auftritt, wenn vorher bereits ein Modul geladen wurde, das gegen GTK gelinkt wurde, in meinem Projekt z.B. der loader:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> ship.icewing <span style="color:#f92672">import</span> loader
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> pygtk
</span></span><span style="display:flex;"><span>pygtk<span style="color:#f92672">.</span>require(<span style="color:#e6db74">&#39;2.0&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> gtk
</span></span></code></pre></div><p>Diese Variante führt garantiert in den Segfault, während folgendes kein Problem ist:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> pygtk
</span></span><span style="display:flex;"><span>pygtk<span style="color:#f92672">.</span>require(<span style="color:#e6db74">&#39;2.0&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> gtk
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> ship.icewing <span style="color:#f92672">import</span> loader
</span></span></code></pre></div><p>So weiß ich jetzt zumindest, wie ich den Fehler systematisch umgehen kann, schön ist das aber immer noch nicht. Vor allem muss jetzt der Nutzer meiner API die Import-Reihenfolge beachten. Hat irgendwer einen besseren Lösungsweg oder eine Idee, wo das Problem herkommt?</p>
]]></content></entry><entry><title>Magische Konstanten</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/magische-konstanten/"/><id>https://www.semipol.de/posts/2008/06/magische-konstanten/</id><published>2008-06-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Gerade im Legacy-Code meiner Bachelorarbeit über ein lustiges C &ldquo;Feature&rdquo; gestolpert. Was man doch alles in Ermangelung von Exceptions machen kann:
/* Return value for opts_value_set() if error occurs */ #define OPTS_SET_ERROR (-9999) Leider kann -9999 auch ein valider Rückgabewert der Funktion sein, die diese Konstante benutzt.</summary><content type="html"><![CDATA[<p>Gerade im Legacy-Code meiner Bachelorarbeit über ein lustiges C &ldquo;Feature&rdquo; gestolpert. Was man doch alles in Ermangelung von Exceptions machen kann:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/* Return value for opts_value_set() if error occurs */</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#define OPTS_SET_ERROR  (-9999)
</span></span></span></code></pre></div><p>Leider kann -9999 auch ein valider Rückgabewert der Funktion sein, die diese Konstante benutzt.</p>
]]></content></entry><entry><title>printf und die Anzahl an Argumenten</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/printf-und-die-anzahl-an-argumenten/"/><id>https://www.semipol.de/posts/2008/06/printf-und-die-anzahl-an-argumenten/</id><published>2008-06-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Variable Argumente in C scheinen ja auch besonders schwierig zu sein, oder man weiß es nicht, wieso printf so seltsam auf eine fehlerhafte Anzahl Argumente reagiert:
#include &lt;stdio.h> int main(void) { int foo = 1; int bar = 0; printf("%d, %d\n", foo &amp;&amp; bar); return 0; } Mal schnell die Berechnung einer boolschen Variable in printf gejagt und vergessen die &amp;&amp; gegen Kommas zu ersetzen und schon sieht man die seltsamsten Ergebnisse:
0, -1079242984 In welchem Speicher printf da wohl nach dem zweiten Integer sucht? Wie schön sind doch Exceptions&hellip; Nach so einem Fehler kann man ewig suchen.</summary><content type="html"><![CDATA[<p>Variable Argumente in C scheinen ja auch besonders schwierig zu sein, oder man weiß es nicht, wieso printf so seltsam auf eine fehlerhafte Anzahl Argumente reagiert:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdio.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>(<span style="color:#66d9ef">void</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> foo <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> bar <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;%d, %d</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, foo <span style="color:#f92672">&amp;&amp;</span> bar);
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Mal schnell die Berechnung einer boolschen Variable in printf gejagt und vergessen die &amp;&amp; gegen Kommas zu ersetzen und schon sieht man die seltsamsten Ergebnisse:</p>
<pre tabindex="0"><code>0, -1079242984
</code></pre><p>In welchem Speicher printf da wohl nach dem zweiten Integer sucht? Wie schön sind doch Exceptions&hellip; Nach so einem Fehler kann man ewig suchen.</p>
]]></content></entry><entry><title>Style Guide für Python</title><link rel="alternate" href="https://www.semipol.de/posts/2008/06/style-guide-f%C3%BCr-python/"/><id>https://www.semipol.de/posts/2008/06/style-guide-f%C3%BCr-python/</id><published>2008-06-15T00:00:00+00:00</published><updated>2021-04-30T22:40:19+02:00</updated><summary>Style Guides für Java und C/C++ gibt es ja zu Hauf, für Python war mir aber bisher noch kein explizit aufgeschriebener aufgefallen - zumindest bis gestern: PEP 8 &ndash; Style Guide for Python</summary><content type="html"><![CDATA[<p>Style Guides für Java und C/C++ gibt es ja zu Hauf, für Python war mir aber bisher noch kein explizit aufgeschriebener aufgefallen - zumindest bis gestern: <a href="http://www.python.org/dev/peps/pep-0008/" title="PEP 8 -- Style Guide for Python">PEP 8 &ndash; Style Guide for Python</a></p>
]]></content></entry></feed>