<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>chrisport.ch</title>
    <description>Christoph Portmann — software engineer and tech lead. Posts and projects on Go, Java, and building software in teams.</description>
    <link>https://chrisport.ch/</link>
    <atom:link href="https://chrisport.ch/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 02 Oct 2026 19:45:28 +0000</pubDate>
    <lastBuildDate>Fri, 02 Oct 2026 19:45:28 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Amortizing Software Rewrites: An Evolutionary Approach</title>
        <description>&lt;p&gt;This post I have written and published with a colleague during my time at Thoughtworks.
Please find it here: &lt;a href=&quot;https://www.thoughtworks.com/en-de/insights/blog/amortizing-software-rewrites-evolutionary-approach&quot;&gt;thoughtworks.com/en-de/insights/blog/amortizing-software-rewrites-evolutionary-approach&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 16 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://chrisport.ch/software-engineering/2021/04/16/amortizing-software-rewrites.html</link>
        <guid isPermaLink="true">https://chrisport.ch/software-engineering/2021/04/16/amortizing-software-rewrites.html</guid>
        
        
        <category>software-engineering</category>
        
      </item>
    
      <item>
        <title>Bringing vision into a code base</title>
        <description>&lt;p&gt;This post is about how to inject and persist architectural vision in a code base, based on a recent experience.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;High-level approach&lt;/strong&gt; to restructure and refactor a messy code base&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Persist architectural vision&lt;/strong&gt; to outlive people and team changes and move the code in a single direction.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;preface-the-tale-of-my-own-legacy&quot;&gt;Preface: The tale of my own legacy&lt;/h2&gt;
&lt;p&gt;Some code comes with a long history and reflects the opinion and knowledge of all the people that have worked on it.   &lt;br /&gt;
Recently I had the honor to work on a rather small, but messy code base which has been passed around between teams multiple times over the course of three years. In fact, I had worked on it myself for a while a year before and I remember very well how we were sitting in a small meeting room with stifling air, talking over the code smells and trying to come up with ideas on how to make it shine. &lt;br /&gt;
Due to organisational reasons, it was soon to be transferred to another team on another continent. We shared our gained understanding as best we could and explained our half-baked ideas of the next steps.&lt;/p&gt;

&lt;p&gt;One year later this code had become a bottleneck to the project and the assumption is that no more than two pairs are able to work on it in parallel. As an experiment we put together a team of two pairs, one from our team and one from the other team, with the mission to make work on this code base more parallelizable - of course with on-going delivery on top. 
As part of this new team the code base came back to me after over a year. The good news: The other team has made vast improvements and did an excellent job in the time given. But big parts were untouched and moreover our half-baked solutions from one year ago are now just additional complexity and became part of the problem. &lt;br /&gt;
It’s great to work in a small and fresh team on a single problem. The scope is narrow, which leaves our brains the energy to understand the technical details in-depth and make the right decisions on what to tackle, and how and when.&lt;sup&gt;1&lt;/sup&gt; Let’s see how we deal with the actual task.&lt;/p&gt;

&lt;h2 id=&quot;approach-the-restructuring&quot;&gt;Approach the Restructuring&lt;/h2&gt;
&lt;p&gt;The initial milestone is to reach a clearly structured base, in which we can implement new changes and continue to clean up messy parts as we touch it.&lt;br /&gt;
We approach the refactoring in five steps:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Get a shared understanding of the business context&lt;/strong&gt; &lt;br /&gt;
It is essential to first get a common understanding of the business domain and capabilities that the code base provides. A simplified &lt;a href=&quot;https://eventstorming.com&quot;&gt;event storming&lt;/a&gt;&lt;sup&gt;2&lt;/sup&gt; session helps us to get to know what we are dealing with and have a common and well-defined language to talk about the business. &lt;br /&gt;
Later we often have to distinguish between essential complexity, which reflects the complexity of the business capability, and accidental complexity, which is added through the chosen implementation and can be eliminated.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Define a high-level target structure&lt;/strong&gt;
Based on this business understanding we create a very simple first high-level structure that looks something like this.
&lt;img src=&quot;/images/vision/structure.png&quot; alt=&quot;Basic structure in a hierarchical diagram&quot; /&gt;
This structure is by no means written in stone. In fact, as we proceed into the next phases, we refine it multiple times.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Name the mess&lt;/strong&gt; &lt;br /&gt;
It is time to collect the low-hanging fruits! This means reading the code, splitting and moving files to reach higher cohesion, and renaming things to reflect their semantics. The terms from the event storming session come in handy here, and the high-level target structure guides where files should live. At this point we don’t really touch any logic, but simply rename and move files, classes and (top-level) functions. 
Thanks to modern IDEs like IntelliJ, these are quite risk-free refactorings with immediate benefit.
One of our measures of success is that a new developer should be able to intuitively navigate to the code related to a feature they are working on. 
In our case, a new joiner gives her subjective impression and uncovers some more unintuitive names and structures. &lt;br /&gt;
&lt;strong&gt;Example&lt;/strong&gt;: 
we collect a bunch of tools, which are not directly related to business cases, like the swagger setup, in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; package. 
‘tools’ might not be the best name, but the important thing now is to split the mess into manageable and obvious parts that can be worked on further later.  &lt;br /&gt;
&lt;strong&gt;Example&lt;/strong&gt;:
The package &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api&lt;/code&gt; contains a class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataController&lt;/code&gt;. Neither “api” nor “data” says what the content of this file is about.
&lt;img src=&quot;/images/vision/renaming_initial.png&quot; alt=&quot;Wrong naming initially, there is a API package with a mysterious DataController&quot; /&gt;
We figure out that these are HTTP APIs for customer profile preview and editing, including image upload. We move them to corresponding feature packages. The result looks like this:
&lt;img src=&quot;/images/vision/renaming_result.png&quot; alt=&quot;Resulting hierarchy, renamed and moved into 2 files under parent-package &amp;quot;feature&amp;quot;.&quot; /&gt;
The entanglement in code is still there, maybe the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preview&lt;/code&gt; code uses functions from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edit&lt;/code&gt; code to get the uploaded image. 
Maybe it would make sense to split out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; functionalities and move them to the core.
But in this phase, demystifying and making them obvious brings more value. 
The names reflect the content and are close to the right place now, and we are much happier!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Identify and prioritise the hot spots&lt;/strong&gt; &lt;br /&gt;
While a lot of things are tightly coupled, we can identify hot spots that are central to the application logic and particularly complex. We identify these exploratively by using tools like &lt;a href=&quot;https://github.com/vanniktech/gradle-dependency-graph-generator-plugin&quot;&gt;dependency graphs&lt;/a&gt;. Some hot spots only become obvious during the feature work. Such discoveries are actually the most valuable ones, because solving them first will have an immediate impact on our feature delivery speed, which makes them cheap improvements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Restructure&lt;/strong&gt;
This is the most fun phase for the devs! We refactor the code to make it more understandable, maintainable and evolvable. It’s advisable to limit and coordinate the bigger tasks, as some might go deep into the fundamental structure of the application. In an ideal case we do this as part of the feature work, but since we want to significantly improve the code base in a limited time, we also run refactorings as tasks on their own, so that a pair can concentrate on finding the best way. While refactoring per definition excludes changing behaviour, don’t be afraid to question existing logic. Again the question is, if this complexity is accidental or essential. One of the greatest feelings is when you spend half a day understanding what a particularly complex part is doing, just to come to the conclusion that we don’t need it at all.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;persisting-vision&quot;&gt;Persisting Vision&lt;/h2&gt;
&lt;p&gt;By nature the entropy, or chaos, of a code base increases with the features and changes applied on it. Therefore, refactoring should be part of everyday development work. 
But changes and refactorings need to go in one direction towards a common vision of how the code base ought to look. 
A good analogy I’ve read is that “a code base should look like it’s written by a single person”&lt;sup&gt;3&lt;/sup&gt;.
The easiest way to achieve this in a team is through pair programming and regular open discussions, but in fact it is shaped by any interaction and casual conversation team members have. 
With larger teams this becomes increasingly difficult&lt;sup&gt;4&lt;/sup&gt; and when a code base is even passed around between teams, the communication of the vision barely happens. &lt;br /&gt;
So considering that this team has an expiry date, a big concern for us is how we can transfer our vision and knowledge to whoever will encounter this codebase. 
&lt;em&gt;The vision must be translated into the code base.&lt;/em&gt; 
Ideally it is readable and obvious, when a developer wants to do a change, they should feel “this is how I should do it”. 
But even if the code base still is a bit messy, we want to provide some guide rail and the following tools and techniques have been particularly useful.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/TNG/ArchUnit&quot;&gt;&lt;strong&gt;ArchUnit&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
ArchUnit is a testing framework for the architecture of a JVM based application. Our code base is in Kotlin and the framework does a wonderful job. It allows us to express our intentions in small tests that then assert that the rule is not violated. Here is a simple example of an ArchUnit test. ArchUnit is a really amazing tool and I have yet to discover such tools for other technologies.&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot; data-lang=&quot;kotlin&quot;&gt;  &lt;span class=&quot;nd&quot;&gt;@ArchTest&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;`classes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;core&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;noClasses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;that&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resideInAPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ch.chrisport.core..&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;should&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dependOnClassesThat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resideInAPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ch.chrisport.features..&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          
  &lt;span class=&quot;nd&quot;&gt;@ArchTest&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;`features&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;circular&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dependencies`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;matching&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ch.chrisport.features.(*)..&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;should&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;beFreeOfCycles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Manifesto / Code of Conduct&lt;/strong&gt; &lt;br /&gt;
We create a Code of Conduct in the root folder of the code base, requesting any external contributor to read it before writing code. 
The goal of the code of conduct is to raise awareness, not explain in detail. It describes in short the business scope, the architectural goal of the code base, current state, as well as Do’s and Dont’s.  &lt;br /&gt;
The document should be short enough for anybody to read it in just &lt;em&gt;five minutes&lt;/em&gt;, not an extensive documentation. The points are at least mid-term, so that they don’t need to be updated every week. Some parts might be a bit more short-lived, such as
    &lt;blockquote&gt;
      &lt;p&gt;Don’t write more Enzyme tests, we want to migrate to React Testing Library tests&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;or&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Do not add more properties to the Preview class, we want to move to more specialised interfaces.&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;Where possible, move such things to ArchUnit tests, where they are much more practical.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Continuous guided change with pre-commit hooks&lt;/strong&gt; &lt;br /&gt;
On a similar line as the ArchUnit tests, we’ve introduced a git pre-commit hook (using &lt;a href=&quot;https://github.com/typicode/husky&quot;&gt;husky&lt;/a&gt;), which runs through the touched files and verifies that certain things are not present anymore. This supports a continuous refactoring approach to things like renaming or changing tools, in the sense of a fitness function&lt;sup&gt;5&lt;/sup&gt;. &lt;br /&gt;
For example whenever you have touched a test, all junit4 tests should be junit5 now and the name ‘OutputView’ should not appear anymore in any variable name, but be replaced with ‘View’. &lt;br /&gt;
Scanning through the files of a commit, the script searches for appearances of unwanted content and prints the violation to the console. Each violation has an explanatory comment which is printed alongside.
    &lt;blockquote&gt;
      &lt;p&gt;Violation: File Application.test.kt contains org.junit.test. Please migrate Junit4 tests to Junit5.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;We looked at an approach to restructure a messy code base in five steps:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;Get a shared understanding of the business context&lt;/em&gt;: Bring everything on the table, share knowledge and agree on terms&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Define a high-level target structure&lt;/em&gt;: Define a first version of the target structure to guide further steps. Revisit it frequently.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Name the mess&lt;/em&gt;: Collect low hanging fruits by moving and renaming things according to their semantic.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Identify and prioritise the hot spots&lt;/em&gt;: Analyse the code base to identify where complexity lies, prioritise it according to impact on the upcoming work.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Restructure&lt;/em&gt;: Limit and coordinate the more complex refactorings to stay focused. Don’t be afraid to question.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We also looked at three tools that support the continuation of a unified vision, even if the people change:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;ArchUnit&lt;/em&gt;: For expressing intention and structure in form of tests.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Manifesto / Code of Conduct&lt;/em&gt;: For sharing the core ideas and direction with any person unfamiliar, explicitly and brief.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Continuous guided change with pre-commit hooks&lt;/em&gt;: For verifying that no unwanted content is present in any touched file, this pushes developers to apply the Boy Scout rule.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;
&lt;em&gt;Send me some feedback on this post via Social Media.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;references-&quot;&gt;References &lt;a name=&quot;references&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; In her book &lt;a href=&quot;https://www.amazon.com/Dynamic-Reteaming-Wisdom-Changing-Teams/dp/1733567216&quot;&gt;Dynamic Reteaming&lt;/a&gt;, Heidi Helfand calls this approach of building a new team around a specific problem &lt;a href=&quot;https://www.pluralsight.com/blog/teams/heidi-helfand-s-five-patterns-for-responsible-reteaming&quot;&gt;Isolation Pattern&lt;/a&gt;. &lt;br /&gt;
&lt;sup&gt;2&lt;/sup&gt; Eventstorming is an approach to discover the domain in form of a workshop. We used &lt;a href=&quot;http://www.mural.co&quot;&gt;Mural&lt;/a&gt; to do this remotely. &lt;br /&gt;
&lt;sup&gt;3&lt;/sup&gt; If you know the origin of this analogy, please let me know. &lt;br /&gt;
&lt;sup&gt;4&lt;/sup&gt; See also &lt;a href=&quot;https://www.solutionsiq.com/learning/blog-post/lines-of-communication&quot;&gt;https://www.solutionsiq.com/learning/blog-post/lines-of-communication&lt;/a&gt; &lt;br /&gt;
&lt;sup&gt;5&lt;/sup&gt; A fitness function, as described in the book &lt;a href=&quot;https://www.thoughtworks.com/books/building-evolutionary-architectures&quot;&gt;Building Evolutionary Architectures&lt;/a&gt; produces a statement, which tells us if we move forward in the direction of a desired architectural characteristic.&lt;/p&gt;

</description>
        <pubDate>Sat, 26 Dec 2020 00:00:00 +0000</pubDate>
        <link>https://chrisport.ch/software-engineering/2020/12/26/bringing-vision-into-a-code-base.html</link>
        <guid isPermaLink="true">https://chrisport.ch/software-engineering/2020/12/26/bringing-vision-into-a-code-base.html</guid>
        
        
        <category>software-engineering</category>
        
      </item>
    
      <item>
        <title>Bubble up errors in Golang</title>
        <description>&lt;p&gt;One problem I often encounter is errors without any context.
If an arbitrary method returns an error “invalid character ‘}’ after object key”, you will have to dive down the stack until you find
the exact place the error happened. Therefore whenever you receive an error and you decide to not handle it, but instead
return it to the caller of your method, you should provide context about the reason the error occurred.
The examples below use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;errors.Wrap&lt;/code&gt; from &lt;a href=&quot;https://github.com/pkg/errors&quot;&gt;github.com/pkg/errors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take the following method as example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;some_invalid_input&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serviceA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serviceB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If serviceA or serviceB returns an error, we don’t know which one failed and we don’t know whether it is our fault
or whether the service is unreachable or misconfigured.
The error could look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invalid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;character&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;}&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;looking&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beginning&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;goroutine&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;running&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;christophportmann&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;workspace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrisport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;playground&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errorhandling&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0x92&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By wrapping the error, we can provide the missing information about what part failed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;some_invalid_input&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serviceA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;call to service A failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serviceB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;call to service B failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The result would be unambiguous:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invalid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;character&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;}&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;looking&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beginning&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;goroutine&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;running&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;christophportmann&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;workspace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrisport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;playground&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errorhandling&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0x92&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this simple example the advantage is not crystal clear. But imagine serviceA is doing a complex task itself and doesn’t wrap its errors either. &lt;br /&gt;
You could end up getting generic errors (e.g. a timeout on an http call) and need to debug down the whole stack to find out which
call has failed. But if errors are always wrapped with necessary context, an error message could look as nice as this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backend&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wrote&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;more&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;than&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;declared&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Therefore &lt;b&gt;if you decide to bubble up an error, always provide context&lt;/b&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 20 Sep 2017 00:00:00 +0000</pubDate>
        <link>https://chrisport.ch/golang/2017/09/20/golang-error-wrapping.html</link>
        <guid isPermaLink="true">https://chrisport.ch/golang/2017/09/20/golang-error-wrapping.html</guid>
        
        
        <category>Golang</category>
        
      </item>
    
      <item>
        <title>Context Aware Java Executor and Spring&apos;s @Async</title>
        <description>&lt;p&gt;Recently I came across the problem of ThreadLocal context in multithreaded environment.
If the Thread that handled a request uses an &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html&quot;&gt;Executor&lt;/a&gt; 
to asynchronously execute tasks, the ThreadLocal context is lost and information such as requestId will be missing in the logs.  &lt;br /&gt;
We can solve this using the Decorator pattern:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Wrap Runnable to preserve caller Thread’s context&lt;/li&gt;
  &lt;li&gt;Implement ExecutorDecorator that wraps every execution&lt;/li&gt;
  &lt;li&gt;Additional: Configure Spring’s @Async to use Decorator&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.slf4j.org/api/org/slf4j/MDC.html&quot;&gt;&lt;em&gt;MDC&lt;/em&gt; (Mapped Diagnostic Context)&lt;/a&gt; used in the example as the ThreadLocal context&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;caller Thread&lt;/em&gt;, which wants to schedule some task&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;executor Thread&lt;/em&gt;, which can be any Thread (e.g. from a pool) that executes the task&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;1-make-the-runnable-context-aware&quot;&gt;1. Make the runnable context aware&lt;/h3&gt;

&lt;p&gt;To pass the MDC of the caller Thread to the executor Thread, we get a copy of the ContextMap.&lt;br /&gt;
Then we set this context map before execution of the task and reset it after the execution, even if the task fails.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt; 
&lt;span class=&quot;c1&quot;&gt;// get a copy of the values of calling Thread&apos;s MDC&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callerContextCopy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCopyOfContextMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctxAwareTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// get a copy of the values of executing-Thread&apos;s MDC&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executorContextCopy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCopyOfContextMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callerContextCopy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// set the desired context that was present at point of calling execute&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setContextMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callerContextCopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// execute the command&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// reset the context, even if the command throws&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorContextCopy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;MDC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setContextMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorContextCopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;2-implement-custom-executor-that-decorates-every-task&quot;&gt;2. Implement custom Executor that decorates every task&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;  
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ContextAwareExecutorDecorator&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TaskExecutor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContextAwareExecutorDecorator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// decorate the task&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctxAwareCommand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wrapContextAware&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// execute the decorated task&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctxAwareCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;wrapContextAware&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;see&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;above&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctxAwareTask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Please note that I also implement Spring’s TaskExecutor for usage below.&lt;/p&gt;

&lt;h3 id=&quot;3-addition-configure-springs-async-to-use-decorator&quot;&gt;3. Addition: Configure Spring’s @Async to use Decorator&lt;/h3&gt;

&lt;p&gt;We can configure the default executor easily with the following Configuration.
See also &lt;a href=&quot;https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableAsync.html&quot;&gt;Spring’s documentation: EnableAsync&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableAsync&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AsyncConfigurerSupport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getAsyncExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setCorePoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setMaxPoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setQueueCapacity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setThreadNamePrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ContextAwareExecutor-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContextAwareExecutorDecorator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;sample-application&quot;&gt;Sample Application&lt;/h3&gt;

&lt;p&gt;There is a small &lt;a href=&quot;https://github.com/chrisport/thread-context-demo&quot;&gt;sample application&lt;/a&gt; on Github. It has a service, which
has an @Async method. After startup, the service is called 10 times with a specific MDC context containing the loop-count and
the caller’s threadId. The asynchronous service method prints its MDC to the log, which should contain the originally mentioned properties.&lt;/p&gt;

&lt;p&gt;Without our ContextAwareExecutorDecorator, we will encounter the initially described problem: the ThreadLocal context gets lost. &lt;br /&gt;
In that case the log looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;13:14:20.643 executorThreadId: 17&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: null
13:14:20.748 executorThreadId: 18&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: null
13:14:20.852 executorThreadId: 19&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: null
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we now wrap the Executor into our ContextAwareExecutorDecorator, as described in Step 3, the problem will be solved. &lt;br /&gt;
The resulting log looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;13:07:50.634 executorThreadId: 17&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:50.737 executorThreadId: 18&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:50.839 executorThreadId: 19&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:50.943 executorThreadId: 20&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.045 executorThreadId: 21&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.149 executorThreadId: 23&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.254 executorThreadId: 24&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.359 executorThreadId: 17&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.462 executorThreadId: 18&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
13:07:51.565 executorThreadId: 19&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ContextMap on execution: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9, &lt;span class=&quot;nv&quot;&gt;callerThreadId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;16&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Wed, 12 Oct 2016 00:00:00 +0000</pubDate>
        <link>https://chrisport.ch/java/2016/10/12/java-spring-context-aware.html</link>
        <guid isPermaLink="true">https://chrisport.ch/java/2016/10/12/java-spring-context-aware.html</guid>
        
        
        <category>Java</category>
        
      </item>
    
      <item>
        <title>Visualize call trees in a microservice architecture</title>
        <description>&lt;p&gt;&lt;em&gt;Disclaimer 2020/2026: Distributed tracing is provided by various mature libraries, prominently by the standard OpenTelemetry. Please consider these before implementing anything yourself.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In a microservice architecture, one request can lead to multiple log entries 
distributed across services.
One client request can cause multiple internal requests, which in turn can cause further requests.
This can lead to unwanted depth of requests which leads to high latency.
I worked in a system with central logging using the ELK stack. It was easy to search for log entries and even
to search for all entries by unique ID per request. But the possibilities to analyse request trees were very limited.
In this article I will show a solution to analyse the logs and create useful results and graphs. The examples are
invented but reflect our experiences.&lt;/p&gt;

&lt;h3 id=&quot;request-trees&quot;&gt;Request Trees&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/DOT_(graph_description_language)&quot;&gt;DOT graph description language&lt;/a&gt; is used to create
graphs in plain text, which can be visualized using tools like &lt;a href=&quot;https://www.graphviz.org/&quot;&gt;Graphviz&lt;/a&gt;.
The language can be understood in few minutes which makes it easy to work with. Here is an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    digraph &quot;/pay&quot; {
      &quot;CLIENT&quot; -&amp;gt; &quot;proxy&quot;
      &quot;Proxy&quot; -&amp;gt; &quot;BillService&quot;
      &quot;BillService&quot; -&amp;gt; &quot;UserService&quot;
      &quot;BillService&quot; -&amp;gt; &quot;BankGateway&quot;
      &quot;BankGateway&quot; -&amp;gt; &quot;AuditService&quot;
    }&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can store this in a .dot or .gv file and open it with GraphViz.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/ex1.png&quot; alt=&quot;Visualization of graph&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;track-request-trees-through-chained-ids&quot;&gt;Track request trees through chained IDs&lt;/h3&gt;

&lt;p&gt;As mentioned it is not possible to track a chain if there is only a unique ID per request, since one service
can call multiple other services and do this even in parallel.
Therefore we need three parts, a Unique Request ID, a Caller ID and a Receiver ID.
For a fast implementation I just modified the unique ID to be in the format&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;lt;FixedRequestId&amp;gt;::&amp;lt;LastCallerID&amp;gt;::&amp;lt;ReceiverId&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A chain from the example above can now easily be parsed and printed in dot notation. The IDs from the example above
would be the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Proxy           UID
BillService     UID::BillServiceID
UserService     UID::BillServiceID::UserServiceID
BankGateway    UID::BillServiceID::BankGatewayID
AuditService    UID::BankGatewayID::AuditServiceID&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/images/ex2-5.png&quot; alt=&quot;Visualization of request with elapsed time &quot; /&gt;&lt;/p&gt;

&lt;p&gt;The Go function to create these IDs is as simple as&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformUniqueId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parentUID&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ids&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parentUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;::&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentUID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;::&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getNextInstanceId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;::&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ids&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;::&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getNextInstanceId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Since we use a &lt;a href=&quot;https://beego.me/docs/mvc/controller/filter.md&quot;&gt;beego filter&lt;/a&gt; to write the access logs, it is very easy
to apply this to every incoming request. Parallel benchmarking shows that the additional cost of this is in range
of 600-800 nanoseconds, including decomposition of the received ID, generation of the new ID and storing the result
in the request context. The resulting ID will be sent in the header of every consecutive request to other services.&lt;/p&gt;

&lt;h3 id=&quot;parser-implementation&quot;&gt;Parser implementation&lt;/h3&gt;

&lt;p&gt;After some logs have been produced, I wrote a parser for analysing these logs.
A simple Golang interface represents a log entry:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Log&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// RequestID returns the unique ID of the original request&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;RequestID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// String returns a string representation of the log&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// SenderID returns the ID of the sender&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SenderID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// ID returns the ID of this log. It is basically the ReceiverId&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Default implementation with functionality to parse chained IDs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DefaultLog&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;requestID&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;senderID&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;        &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The parser basically just takes one entry, decomposes the unique id and creates an instance of DefaultLog. All the parsed
logs are stored in a map or slice which can be iterated, sorted and filtered for analysis and graph creation.&lt;/p&gt;

&lt;h3 id=&quot;results-of-analysis&quot;&gt;Results of analysis&lt;/h3&gt;

&lt;p&gt;Here are three examples of results that can easily be produced with the parsed logs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Request tree and elapsed time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By changing the String() method, the desired information can easily be printed into dot notation.
In this example I executed a request and printed elapsed time per service. This is sort of profiling on system level.
The graphic shows which service takes how much time in a clean way.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/ex2.png&quot; alt=&quot;Visualization of request with elapsed time &quot; /&gt;
(numbers do not represent real environment times)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Request number between services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/ex3.png&quot; alt=&quot;Visualization of total requests between services&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This graphic shows system wide calls. It is created over a certain time period and shows absolute numbers of total requests.
Please note, one node is one service, not one running instance.
We can make the following interpretations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Service A, C and H call other services through proxy. This is unnecessary and should be corrected.&lt;/li&gt;
  &lt;li&gt;Service C calls itself, these calls should be refactored to method calls.&lt;/li&gt;
  &lt;li&gt;Service D is called most by far. These calls are very cheap and caused by a temporary solution. Therefore it can be ignored.&lt;/li&gt;
  &lt;li&gt;Service F is called directly, the system would be cleaner if we can redirect those calls through the proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Outgoing requests per incoming requests&lt;/strong&gt;
Example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;6.5322833   ServiceA
2.5714285   ServiceB
0.99878484  Proxy
0           mailer&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This ratio can reveal flaws in the services. Some may have a high number because they basically
aggregate data from other services, but they should be investigated. Also it can be seen that Proxy is almost but not
exactly 1. This 0.0013 difference consists of invalid requests which the proxy couldn’t resolve and responded with “service not found”.
A similar statistic can be made per endpoint.&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Jan 2015 10:00:00 +0000</pubDate>
        <link>https://chrisport.ch/golang/2015/01/12/golang-log-microservices.html</link>
        <guid isPermaLink="true">https://chrisport.ch/golang/2015/01/12/golang-log-microservices.html</guid>
        
        
        <category>Golang</category>
        
      </item>
    
      <item>
        <title>Simple JSON in Golang</title>
        <description>&lt;p&gt;Simplejson is an imitation of Java’s json-simple for the Go language. It allows you to access JSON data without the overhead of
predefining a model or casting elements manually. Therefore it is useful, whenever you want to get data from different schemas
in a quick and clean way. It additionally provides handy error handling, as well as segmented keys to directly access
nested Objects and Arrays. Current Version is 0.3 and its API will change slightly to allow a better error handling in the next version.&lt;/p&gt;

&lt;h3 id=&quot;context&quot;&gt;Context&lt;/h3&gt;

&lt;p&gt;While developing a configuration reader, I came across the problem: how to generically access data in nested JSON files in Go.
Golang’s native json-package provides methods to access data in json-format by unmarshaling into a predefined struct. 
Therefore to handle various config-files, every project had to define its own config model that is used
to unmarshal data and this was a pain.&lt;br /&gt;
If the type is not clear, you are always free to parse it into a map[string]interface{}, but it means you need to 
 cast the elements you access on this map (unless they are all of the same type, e.g. map[string]string).
But when you have nested data, it quickly becomes a pain, because in every step you need to cast the elements.&lt;br /&gt;
Let’s look at an example.
Json config file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;profile/id/:id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://api.eventmanager.com/events&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;events/id/:id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://api.eventmanager.com/events&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;adminMode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;built-in-possibilities-to-access&quot;&gt;Built-in possibilities to access&lt;/h3&gt;
&lt;p&gt;To access the “path”-attribute of the first route, there is the first solution including casting:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;c&quot;&gt;// define the base map&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootMap&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// unmarshal data into map&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rootMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// access and cast until desired data is retrieved&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;routes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;firstRoute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstRoute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s crazy, let’s try another solution by defining a local struct:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localStruct&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Routes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;path&quot;`&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;routes&quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pathOfFirstObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localStruct&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s a bit less crazy, but still quite crazy. And this doesn’t make sense at all, if we need to write this for 
multiple items, then we can just define the model on its own.&lt;/p&gt;

&lt;h3 id=&quot;imitation-of-simple-json&quot;&gt;Imitation of simple-json&lt;/h3&gt;
&lt;p&gt;From Java I am familiar with json-simple, which allows you to access json-data like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;c1&quot;&gt;//parse to json&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;JSONObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JSONObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//get object&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pathOfFirstObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJSONArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJSONObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The implementation of json-simple in Go allows to do exactly the same:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewJSONObjectFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jsonString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pathOfFirstObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JSONArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JSONObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;direct-access-through-segmented-keys&quot;&gt;Direct access through segmented keys&lt;/h3&gt;
&lt;p&gt;Besides chaining calls, you have also the possibility to directly access nested data by providing a segmented key-string.
To access the example data, you would call the key “routes::0::path”:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewJSONObjectFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jsonString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pathOfFirstObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rootObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;routes::0::path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;version-04-preview-error-handling-and-chained-calls&quot;&gt;Version 0.4 preview: Error handling and chained calls&lt;/h3&gt;
&lt;p&gt;This feature is planned to be included in Version 0.4.
For sure Error handling is an important topic. In Java we have the possibility to wrap the whole chain
into a Try-Catch block, which prevents the application from crashing, but may hide the source of the error.
For this implementation you can do something similar:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;n&quot;&gt;pathOfFirstObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewJSONObjectFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jsonString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;JSONArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;JSONObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Gotcha! Message: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The special thing about this is the customized error that is returned when any error happened. The error provides all 
methods that JSONObject and JSONArray provide, therefore the chained method-calls can be executed safely and without 
worrying about panic. All methods of this error return the error itself, so it can be analyzed at the end.
Additionally the error includes the key where the casting failed and can be used to track back the source of the error.&lt;/p&gt;
</description>
        <pubDate>Sun, 14 Sep 2014 22:25:00 +0000</pubDate>
        <link>https://chrisport.ch/golang/2014/09/14/golang-simplejson.html</link>
        <guid isPermaLink="true">https://chrisport.ch/golang/2014/09/14/golang-simplejson.html</guid>
        
        
        <category>Golang</category>
        
      </item>
    
      <item>
        <title>Model Binding for Android</title>
        <description>&lt;p&gt;There are tons of approaches to update the UI when data changes or the other way round, in short: model binding. In this
post we will investigate four possible implementations of a one-way binding and compare their performance in a series 
of tests. Different code snippets provide an overview of the complexity when applying the approaches to a real example.&lt;/p&gt;

&lt;h2 id=&quot;context&quot;&gt;Context&lt;/h2&gt;
&lt;p&gt;While developing the Android Client for a platform that provides near-realtime experience for interactions between users,
we had to implement a binding between the Model and the UI. During the development we created and evolved our own system,
but we ended up with something very similar to &lt;a href=&quot;https://developer.android.com/reference/java/beans/PropertyChangeListener.html&quot;&gt;Java Bean’s PropertyChangeListener&lt;/a&gt;.
To find a better approach, I created a small setup consisting of a model “Profile” and a UI reflecting a profile’s properties
(such as name, age, followers). Inside this setup I implemented the different solutions and trialed them in a predefined
set of tests.&lt;br /&gt;
Unfortunately I didn’t find time to finish a version with an Eventbus such as &lt;a href=&quot;https://square.github.io/otto/&quot;&gt;Square’s Otto&lt;/a&gt;;
I may add this in the future.&lt;/p&gt;

&lt;h2 id=&quot;approaches&quot;&gt;Approaches&lt;/h2&gt;

&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Original: Project’s implementation as-is&lt;/li&gt;
  &lt;li&gt;PropertyChangeListener: the java.beans solution + a modified version that notifies on UI-Thread&lt;/li&gt;
  &lt;li&gt;Property Class: Properties are replaced by a Wrapper-class with Observable-feature&lt;/li&gt;
  &lt;li&gt;Proxy solution: Java’s dynamic proxies are used for notification in an AOP-like manner&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;projects-solution&quot;&gt;Project’s solution&lt;/h3&gt;
&lt;p&gt;Our own solution is very similar to PropertyChangeListener, a FieldObserver can directly bind to a FieldObservable Model’s Field.
FieldObserver and Field are generic and provide type-safety.&lt;br /&gt;
Further it provides Thread-safety and updates the Observers directly on the UIThread which allows us to make updates from
any thread.&lt;br /&gt;
The disadvantages are the huge boilerplate when creating a new model, as well as
 the high complexity of the implementation. Therefore this implementation needs some serious refactoring, which will
 probably never happen, since the app is not under active development anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/chrisport/748ba6d5370f769e58b6&quot;&gt;Code example on Gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look how we implement the Profile:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractFieldsObservable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FIRST_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setFirstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;notifyFieldObservers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;FIRST_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getFirstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we were using an abstract class to inherit the common functions. Refactoring this to a component would make Profile implementation look like the next one, 
PropertyChangeListener.&lt;/p&gt;

&lt;h3 id=&quot;propertychangelistener&quot;&gt;PropertyChangeListener&lt;/h3&gt;

&lt;p&gt;This implementation is based on Java Bean’s PropertyChangeListener. There are basically two versions under test,
the original one and a slightly modified one.
In the modified version the Listeners are notified on the UI-Thread 
which allows us to call the model’s update-method from a background thread.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;firePropertyChange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyChangeEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;uiHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
                    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;finalP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;propertyChange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Profile implementation&lt;/strong&gt; looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProfilePropChangeListenerOwn&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyChangeSupport&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;changeSupport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyChangeSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
 
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oldName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;changeSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;firePropertyChange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oldName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addPropertyChangeListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;PropertyChangeListenerOwn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;changeSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addPropertyChangeListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;removePropertyChangeListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;PropertyChangeListenerOwn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;changeSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;removePropertyChangeListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;property-class&quot;&gt;Property Class&lt;/h3&gt;

&lt;p&gt;The property class is a generic class, that holds its own listener. The Observer pattern is therefore moved from the model
to its properties.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/chrisport/386cc4c82d7caceb02f0&quot;&gt;Code example on Gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Profile implementation&lt;/strong&gt; now gets really comfortable:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProfilePropsObserver&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Done. This is a very solid solution and lets you implement new models lightning fast. The disadvantage of this solution
may be the high number of small objects that are produced, which shouldn’t be a problem in most contexts. Further it is 
hard to acquire information about who is listening to a model, since the listeners are spread over the
model’s properties.&lt;/p&gt;

&lt;h3 id=&quot;dynamic-proxy-solution&quot;&gt;Dynamic Proxy solution&lt;/h3&gt;

&lt;p&gt;The most advanced and interesting solution includes the usage of Java’s dynamic proxy. A similar approach is also used by
 the widespread Spring framework.&lt;br /&gt;
 The dynamic proxy stores properties according to the called “set”-method in a Map. Therefore “setFirstName” will store
the provided value under the key “firstName”. Further it implements “get” and “is”, as well as addObserver. RemoveObserver
is not implemented, since it is not used by the tests. The full code of the Proxy can be found here:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/chrisport/c2780eff8fa234087751&quot;&gt;Code example on gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;interface of Profile&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Creation of a new Profile will in this case look as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;profile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PojoProxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Profile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To use Dynamic Proxy on Android, the ClassLoader must be obtained via a context: context.getClassLoader()&lt;/p&gt;

&lt;p&gt;For more information see also &lt;a href=&quot;https://tutorials.jenkov.com/java-reflection/dynamic-proxies.html&quot;&gt;“Java Reflection - Dynamic Proxies” by Jakob Jenkov&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;comparison&quot;&gt;Comparison&lt;/h2&gt;

&lt;p&gt;All tests are run on an LG Nexus 4. There are two profile models that are modified during the test.&lt;br /&gt;
The time measurement
ends when all changes have been applied (using Timelatch). 
The times below represent the average time per setter-call and are calculated by:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(Total time) / (number of setter-calls)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;UI-Thread: 24’000 setter-calls&lt;br /&gt;
Multithread: 3 Threads à 8’000 setter-calls&lt;br /&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Approach&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;UI-Thread&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Multithread&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;GC runs&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Project solution&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;28 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;40 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;PropertyChangeListener&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;38 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;–&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;23&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;PropertyChangeListener (mod)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;31 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;44 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;23&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Property Class&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;33 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;40 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dynamic Proxy&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;85 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;93 μs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;45&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Please note the &lt;strong&gt;performance penalty&lt;/strong&gt; of multithreaded runs, which is caused by the low priority of background threads.
The custom implementation seems to have a slight performance advantage. But the differences are small.
Only dynamic proxy takes significantly more time and causes more GC-runs than the other solutions.
I suspect the overhead of the reflective method lookup causes this performance cost.&lt;/p&gt;

&lt;p&gt;From implementation perspective the Property Class is the easiest to implement and use. But the fact that observers
are stored for every property can be a big disadvantage.&lt;br /&gt;
The Dynamic Proxy provides also an easy-to-use solution, but comes with an overhead at runtime. In our case this is the
solution I would go with today, because it gives us further possibilities to intercept interactions with the model.&lt;/p&gt;

</description>
        <pubDate>Mon, 08 Sep 2014 20:50:00 +0000</pubDate>
        <link>https://chrisport.ch/android/2014/09/08/property-change-listener.html</link>
        <guid isPermaLink="true">https://chrisport.ch/android/2014/09/08/property-change-listener.html</guid>
        
        
        <category>Android</category>
        
      </item>
    
  </channel>
</rss>
