<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sebastian Kurfürst</title>
    <description>The latest articles on DEV Community by Sebastian Kurfürst (@skurfuerst).</description>
    <link>https://dev.to/skurfuerst</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F125231%2F2bcdcc09-91de-41e5-9dd4-778b661aef59.jpeg</url>
      <title>DEV Community: Sebastian Kurfürst</title>
      <link>https://dev.to/skurfuerst</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/skurfuerst"/>
    <language>en</language>
    <item>
      <title>Using Nginx to Migrate Legacy Systems</title>
      <dc:creator>Sebastian Kurfürst</dc:creator>
      <pubDate>Sun, 27 Oct 2019 19:11:30 +0000</pubDate>
      <link>https://dev.to/skurfuerst/using-nginx-to-migrate-legacy-systems-2ilo</link>
      <guid>https://dev.to/skurfuerst/using-nginx-to-migrate-legacy-systems-2ilo</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Using Nginx to migrate legacy systems is very powerful. By clever combinations of rewrite rules and reverse proxies, one can implement seamless transitions!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We demonstrate the above by replacing a CMS with Neos CMS, but similar ideas can be applied to many kinds of systems.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem - Adopting a new CMS incrementally
&lt;/h1&gt;

&lt;p&gt;For a customer of us, it became evident that he could not implement his needs with his previous CMS – and after we have showed Neos CMS, it became quickly appearent that they would profit a lot by its functionalities, especially flexible content modelling, redirect management, and SEO functionalities.&lt;/p&gt;

&lt;p&gt;However, the customer had quite a lot of content in the old CMS; and also special functionalities like a shopping basket and different kinds of forms – so we figured out that replacing everything in a big bang would be too expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For us, the core question was: How can we unlock the potential of Neos CMS for the customer, in a very cost-effective way?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the plus side, the customer had recently adopted a new design which he was very happy with; so we wouldn't need to touch any of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Idea: Deliver Neos Content first, then fall back to the old CMS
&lt;/h2&gt;

&lt;p&gt;At [Neos Conference 2018](&lt;a href="http://neoscon.io"&gt;http://neoscon.io&lt;/a&gt;], I've attended a talk by Sebastian Heuer and Arne Blankerts about &lt;a href="https://www.youtube.com/watch?v=hnT_97Ik6po&amp;amp;list=PLmMUGpq3yu-idh6IyyFLhOCgchqHfMzDW&amp;amp;index=13"&gt;escaping legacy hell&lt;/a&gt; - where they introduced the pattern of using Nginx reverse proxies, configured in a clever way. Basically, the idea is to ask the new system first, and when the new system returns a 404 page, intercept that at the Nginx-layer; and instead ask the old system for the same URL.&lt;/p&gt;

&lt;p&gt;This way, we were able to re-build the template in Neos, and migrate incrementally: We took a page where the current structure was not as expected, and we re-built this page in the new system.&lt;/p&gt;

&lt;h1&gt;
  
  
  Nginx Configuration to migrate legacy systems
&lt;/h1&gt;

&lt;p&gt;Let's zoom in a bit on the required Nginx configuration - which, at the core, boils down to the following settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# default for Neos CMS; to redirect all pages which do not exist on disk to index.php&lt;/span&gt;
    &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="n"&gt;/index.php?&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# default config - passing PHP calls to PHP-FPM via FastCGI&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.php&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt;   &lt;span class="s"&gt;unix:/tmp/php7-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# ... quite some more fastcgi parameters here&lt;/span&gt;

    &lt;span class="c1"&gt;# when PHP delivers an HTTP error, do not send this to the end-user directly,&lt;/span&gt;
    &lt;span class="c1"&gt;# but instead evaluate the error_page directive.    fastcgi_intercept_errors on;     &lt;/span&gt;

    &lt;span class="c1"&gt;# redirect to the named @legacy location in case of a 404 from the new system.    &lt;/span&gt;
    &lt;span class="kn"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@legacy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     
    &lt;span class="c1"&gt;# also allow if that happens multiple levels.   &lt;/span&gt;
    &lt;span class="kn"&gt;recursive_error_pages&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# definition for the legacy backend&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;@legacy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# ... (see below)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, I had some trouble defining the legacy backend correctly, because with my first tries defining proxy_pass, the URL /index.php was always called on the legacy system. Then, a bit of debugging and docs reading revealed what was going on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The try_files directive works like some internal redirect; effectively rewriting the Nginx internal variables such as $uri to /index.php.&lt;/li&gt;
&lt;li&gt;then, the PHP location block is executed - and if PHP returned a 404 error, the current request (which was still a request to /index.php) was returned to the legacy system.&lt;/li&gt;
&lt;li&gt;the legacy system (of course) could not deal with requests to /index.php and returned an error.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;So, the question was: How can we use the original URL (before starting to rewrite) and pass that to the legacy upstream system?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The solution is quite easy, but it took a bit to figure this out. The core idea was to use variables inside proxy_pass, to build up the target URL dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;@legacy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# we use the ORIGINAL request URI (including all arguments) here.&lt;/span&gt;
    &lt;span class="c1"&gt;# To quote the docs at https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass:&lt;/span&gt;
    &lt;span class="c1"&gt;#     When variables are used in proxy_pass the URL&lt;/span&gt;
    &lt;span class="c1"&gt;#     is passed to the server as is, replacing the original request URI.&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;https://old.my-url.de&lt;/span&gt;&lt;span class="nv"&gt;$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# we need to define a resolver, as we use variables and a full domain name in proxy_pass&lt;/span&gt;
    &lt;span class="kn"&gt;resolver&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="s"&gt;.8.8.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# for the dynamic parts to work, we need to rewrite Location headers to be relative again, because we use a&lt;/span&gt;
    &lt;span class="c1"&gt;# dynamic $request_uri in proxy_pass - and thus the default rewriting of proxy_redirect does not happen anymore.&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_redirect&lt;/span&gt; &lt;span class="s"&gt;https://old.my-url.de/&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_redirect&lt;/span&gt; &lt;span class="s"&gt;http://old.my-url.de/&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Add a Fast-Path for static assets
&lt;/h1&gt;

&lt;p&gt;In our setup above, the dynamic pages are handled by php-fpm; and all static files (like images, css, ...) are delivered directly from the nginx system which also does the proxying. Thus, we want to avoid asking our new backend for every static asset; just to get the 404 returned, and then to ask the legacy system (which has the asset).&lt;/p&gt;

&lt;p&gt;To fix this, a rather simple additional rule is needed for handling static file types directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.(?:css|png|js|woff|woff2|svg|jpg|jpeg|ttf|pdf)&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# if these static files do not exist on disk, directly ask the legacy backend.&lt;/span&gt;
    &lt;span class="kn"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@legacy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Adding Caching
&lt;/h1&gt;

&lt;p&gt;Finally, to further improve response times, we added a simple cache which caches all legacy-upstream resources for 10 minutes, by using the rules below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_cache_path&lt;/span&gt; &lt;span class="n"&gt;/tmp/nginx-cache&lt;/span&gt; &lt;span class="s"&gt;levels=1:2&lt;/span&gt; &lt;span class="s"&gt;keys_zone=legacy:50m&lt;/span&gt; &lt;span class="s"&gt;inactive=24h&lt;/span&gt;  &lt;span class="s"&gt;max_size=1g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;@legacy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;#  ... the config from above, and additionally the following lines:&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_cache&lt;/span&gt; &lt;span class="s"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_cache_background_update&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_cache_use_stale&lt;/span&gt;  &lt;span class="s"&gt;error&lt;/span&gt; &lt;span class="s"&gt;timeout&lt;/span&gt; &lt;span class="s"&gt;invalid_header&lt;/span&gt; &lt;span class="s"&gt;updating&lt;/span&gt;
                           &lt;span class="s"&gt;http_500&lt;/span&gt; &lt;span class="s"&gt;http_502&lt;/span&gt; &lt;span class="s"&gt;http_503&lt;/span&gt; &lt;span class="s"&gt;http_504&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_cache_valid&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt; &lt;span class="mi"&gt;10m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;In this post, we have shown how Nginx can be used to direct requests dynamically between a new and a legacy system - which can be a powerful and cost-effective way to migrate from a legacy system. Let's finish this post with some properties of this approach, to ease the decision whether this approach is worth it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This approach (for websites) can only be used if the old and the new system have the same visual look-and-feel; i.e. HTML markup can be re-used.&lt;/li&gt;
&lt;li&gt;It best works for systems which are well-segmented; so we do not have lots of interconnections between the "old" and the "new" system. It is a lot harder if the old and the new system need to access the same underlying data store.&lt;/li&gt;
&lt;li&gt;The approach does not contain an in-built way to access shared data; i.e. a page is always rendered purely in the new, or purely in the old system. This makes it a bit harder to deal with global data like a search index, menus, or sitemap.xml (which has to be taken care of differently).&lt;/li&gt;
&lt;li&gt;The approach works best for read-heavy systems.&lt;/li&gt;
&lt;li&gt;This approach allows to use many powerful Neos features, like redirect management, also for content in the old system (as redirects are returned first, from the new system).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking forward to your feedback!&lt;br&gt;
All the best,&lt;br&gt;
Sebastian&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>devops</category>
    </item>
    <item>
      <title>How To Stop Poking and Start Structured Debugging</title>
      <dc:creator>Sebastian Kurfürst</dc:creator>
      <pubDate>Mon, 07 Jan 2019 20:08:25 +0000</pubDate>
      <link>https://dev.to/skurfuerst/how-to-stop-poking-and-start-structured-debugging-3e5g</link>
      <guid>https://dev.to/skurfuerst/how-to-stop-poking-and-start-structured-debugging-3e5g</guid>
      <description>&lt;p&gt;This post explains why structured debugging is hard; and introduces a method to make this process more straightforward. However, before that, we first need to introduce a basic mental model about software development, which will serve us as an analogy for later.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Mental Model: How We Develop Software
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bnhA1nx9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/e1a5ac3a43c675c4d83eec14abc05948679c19bb/diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bnhA1nx9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/e1a5ac3a43c675c4d83eec14abc05948679c19bb/diagram.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, when we start developing inside an existing, bigger application, I feel this process resembles a lot exploring an unchartered island. At the beginning, we only roughly know what we want to archive, but we do not know yet how to reach that goal. We have to first explore our nearby environment.&lt;/p&gt;

&lt;p&gt;Then, we go a few steps, and adjust our course as we go. At first, the steps we take are rather small; but then steps will become bigger as we know more and more about our island (depicted by the big gray area trailing behind you) and are thus able to make more correct assumptions about how the system behaves.&lt;/p&gt;

&lt;p&gt;Thus, over time, we are improving our development speed because our assumptions are getting better and better; and thus we can go multiple steps at once, before validating them all together by trying out the application again. Turns out this will become a problem lateron when we start debugging.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Developing in big existing applications is like charting a previously unchartered island.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Unexpected Behavior
&lt;/h2&gt;

&lt;p&gt;When an unexpected behavior happens, I often see people poking around; often changing various parameters at once before re-running the application. Basically, we this is what happens when we apply our thinking of efficient software development (see above) to debugging - but this leads us to a totally wrong path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Am9tRTTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/8714abdcd95186e6a84ade280b4e0316fc141d3a/diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Am9tRTTv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/8714abdcd95186e6a84ade280b4e0316fc141d3a/diagram.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We basically think "&lt;em&gt;we know how the system will behave&lt;/em&gt;" - and thus, we are going too far at once; hitting walls (depicted in orange) which do not lead us to our solution. When one of these routes does not work, we start again from scratch and retry a different direction - however again going too far into the other direction as well. The problem: &lt;strong&gt;By doing this, we do not learn anything new about our system anymore&lt;/strong&gt; (we just become confused).&lt;/p&gt;

&lt;p&gt;We need to apply another kind of thinking to solve this debugging challenge. Let's assume for a second &lt;em&gt;we did not know anything&lt;/em&gt; about our software when we hit a behavior violating our assumptions. How could we progress then?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Design Experiment; Run it; Analyze; Repeat
&lt;/h2&gt;

&lt;p&gt;We could assume our system is a black, opaque box, which we do not understand. Now, let's apply what a scientist would do to understand it better:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Design an experiment&lt;/strong&gt; which divides the problem space at around 50%, to figure out whether our unexpected behavior resides in the left or the right half of the problem space. It is important that this experiment returns definitive answers (and no assumptions and no probabilities). This is depicted with the blue line and the A/B sections in the image above.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Run the experiment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Analyze the experiment results&lt;/strong&gt;. You should now know definitely at which part of the problem space your unexpected behavior occurs.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Repeat with a new experiment&lt;/strong&gt;, again bisecting the relevant part of the problem space again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, even when doing this,it can happen that an experiment fails without yielding good results. Then, you need to understand that this has happened and design a new experiment, basically discarding the old experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Hints
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Designing good experiments &lt;em&gt;is the hardest part of the process&lt;/em&gt; above.&lt;/li&gt;
&lt;li&gt;  Designing good experiments &lt;em&gt;needs some experience;&lt;/em&gt; and you will see this gets easier over time.&lt;/li&gt;
&lt;li&gt;  When you start with designing experiments, you should &lt;em&gt;explicitely write down the experiment's assumption&lt;/em&gt; which should be validated or falsified. Furthermore, write down the experiment setup.&lt;/li&gt;
&lt;li&gt;  For systems consisting of multiple coarse components, it is usually a good start to create an experiment to isolate &lt;em&gt;which component is responsible for the unexpected behavior&lt;/em&gt; – so first bisecting at component boundaries is a good start. For client-server webapps, this means first figuring out whether the client-side portion of the application or the server-side portion of the application is responsible for the unexpected behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Basically, when developing, you want to understand as much as possible from the system; so I call this &lt;em&gt;White-Box Thinking&lt;/em&gt;. On the other hand, when debugging, you often need &lt;em&gt;Black-Box Thinking&lt;/em&gt;. Switching between the two is often difficult; I hope this essay can help to make this a little easier.&lt;/p&gt;

&lt;p&gt;Looking forward to your feedback,&lt;br&gt;&lt;br&gt;
Sebastian&lt;/p&gt;

&lt;p&gt;PS: This is quite similar to the behavior of &lt;em&gt;git bisect&lt;/em&gt;: In case you need to figure out when a certain regression has entered your codebase, you can use this to identify the commit since when the problem existed.&lt;br&gt;
PPS: This essay has been first published &lt;a href="https://sandstorm.de/de/blog/post/how-to-stop-poking-and-start-structured-debugging.html"&gt;at our company blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>computerscience</category>
      <category>productivity</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Writing React with TypeScript</title>
      <dc:creator>Sebastian Kurfürst</dc:creator>
      <pubDate>Wed, 02 Jan 2019 07:05:28 +0000</pubDate>
      <link>https://dev.to/skurfuerst/writing-react-with-typescript-o5j</link>
      <guid>https://dev.to/skurfuerst/writing-react-with-typescript-o5j</guid>
      <description>&lt;p&gt;Just a quick note today as I stumbled over a &lt;a href="https://github.com/sw-yx/react-typescript-cheatsheet"&gt;a nice GitHub repo&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;We've made good experiences writing React Applications with TypeScript -- and I just now stumbled across a good cheat sheet which summarizes many of the lessons learned:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/typescript-cheatsheets"&gt;
        typescript-cheatsheets
      &lt;/a&gt; / &lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet"&gt;
        react-typescript-cheatsheet
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Cheatsheets for experienced React developers getting started with TypeScript
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;h1&gt;
React+TypeScript Cheatsheets&lt;/h1&gt;
&lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/81"&gt;
  &lt;img height="90" width="90" alt="react + ts logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zF7jDW0h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/6764957/53868378-2b51fc80-3fb3-11e9-9cee-0277efe8a927.png"&gt;
&lt;/a&gt;
&lt;p&gt;Cheatsheets for experienced React developers getting started with TypeScript&lt;/p&gt;
&lt;p&gt;&lt;a href="https://react-typescript-cheatsheet.netlify.app/docs/basic/setup" rel="nofollow"&gt;&lt;strong&gt;Web docs&lt;/strong&gt;&lt;/a&gt; |
&lt;a href="https://github.com/fi3ework/blog/tree/master/react-typescript-cheatsheet-cn"&gt;中文翻译&lt;/a&gt; |
&lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet-es"&gt;&lt;strong&gt;Español&lt;/strong&gt;&lt;/a&gt; |
&lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/CONTRIBUTING.md"&gt;Contribute!&lt;/a&gt; |
&lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose"&gt;Ask!&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;👋 This repo is maintained by &lt;a href="https://twitter.com/swyx" rel="nofollow"&gt;@swyx&lt;/a&gt;, &lt;a href="https://twitter.com/ferdaber" rel="nofollow"&gt;@ferdaber&lt;/a&gt;, &lt;a href="https://twitter.com/sebsilbermann" rel="nofollow"&gt;@eps1lon&lt;/a&gt;, &lt;a href="https://twitter.com/IslamAttrash" rel="nofollow"&gt;@IslamAttrash&lt;/a&gt;, and &lt;a href="https://twitter.com/jsjoeio" rel="nofollow"&gt;@jsjoeio&lt;/a&gt;, we're so happy you want to try out TypeScript with React! If you see anything wrong or missing, please &lt;a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose"&gt;file an issue&lt;/a&gt;! 👍&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/typescript-cheatsheets/react-typescript-cheatsheet/master//CONTRIBUTORS.md"&gt;&lt;img src="https://camo.githubusercontent.com/653282190b3269a9733535d4cf2c0fa570cb294d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f747970657363726970742d63686561747368656574732f72656163742d747970657363726970742d636865617473686565743f636f6c6f723d6f72616e6765267374796c653d666c61742d737175617265" alt="All Contributors"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
All React + TypeScript Cheatsheets&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Basic Cheatsheet&lt;/strong&gt; (&lt;a href="https://raw.githubusercontent.com/typescript-cheatsheets/react-typescript-cheatsheet/master//README.md#basic-cheatsheet-table-of-contents"&gt;&lt;code&gt;/README.md&lt;/code&gt;&lt;/a&gt;) is focused on helping React devs just start using TS in React &lt;strong&gt;apps&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Focus on opinionated best practices, copy+pastable examples.&lt;/li&gt;
&lt;li&gt;Explains some basic TS types usage and setup along the way.&lt;/li&gt;
&lt;li&gt;Answers the most Frequently Asked Questions.&lt;/li&gt;
&lt;li&gt;Does not cover generic type logic in detail. Instead we prefer to teach simple troubleshooting techniques for newbies.&lt;/li&gt;
&lt;li&gt;The goal is to get effective with TS without learning &lt;em&gt;too much&lt;/em&gt; TS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Advanced Cheatsheet&lt;/strong&gt; (&lt;a href="https://react-typescript-cheatsheet.netlify.app/docs/advanced/intro" rel="nofollow"&gt;&lt;code&gt;/ADVANCED.md&lt;/code&gt;&lt;/a&gt;) helps show and…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
 

&lt;p&gt;We've summarized our own best practices at &lt;a href="http://sandstorm.de"&gt;sandstorm&lt;/a&gt; in a GitHub boilerplate (created by my great colleague &lt;a href="https://twitter.com/jamesalias"&gt;Robert Baruck&lt;/a&gt;), with the best practices summarized &lt;a href="https://sandstorm.github.io/typescript-react-app-kickstart-guide/"&gt;in a GitBook&lt;/a&gt;:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sandstorm"&gt;
        sandstorm
      &lt;/a&gt; / &lt;a href="https://github.com/sandstorm/typescript-react-app-kickstart-guide"&gt;
        typescript-react-app-kickstart-guide
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Kickstart guide for React Redux Apps written in TypeScript
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
React TypeScript kickstart&lt;/h1&gt;
&lt;p&gt;This the source for  a guide for kickstarting a new React project with preconfigured Redux, TypeScript, Storybook and testing - all powered by &lt;a href="https://docusaurus.io" rel="nofollow"&gt;docusaurus&lt;/a&gt;.
If you find errors, inconsistencies or want to contribute: Feel free to submit issues &amp;amp; pull requests.&lt;/p&gt;
&lt;h2&gt;
Prerequisites&lt;/h2&gt;
&lt;p&gt;These tools are needed to start developing.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; node version management&lt;/span&gt;
brew install nvm

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; node (latest lts version)&lt;/span&gt;
nvm install --lts

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn&lt;/span&gt;
brew install yarn --without-node&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
Editor&lt;/h2&gt;
&lt;p&gt;We recommend to use &lt;a href="https://code.visualstudio.com/" rel="nofollow"&gt;VSCode&lt;/a&gt; as editor.
Install the following Extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TSLint&lt;/code&gt; -&amp;gt; linting support directly in editor (&lt;a href="https://marketplace.visualstudio.com/items?itemName=eg2.tslint" rel="nofollow"&gt;marketplace&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Type safe React &amp;amp; Redux Snippets in TypeScript&lt;/code&gt; -&amp;gt; Snippets for boilerplate code as shown in Cookbook (&lt;a href="https://marketplace.visualstudio.com/items?itemName=Sandstorm.vscode-awesome-ts-react-redux-snippets" rel="nofollow"&gt;marketplace&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Cookbook&lt;/h2&gt;
&lt;p&gt;In the cookbook you will find skeletons for important modules. These skeletons are also available for VSCode as snippets in the VSCode &lt;a href="https://marketplace.visualstudio.com/items?itemName=Sandstorm.vscode-awesome-ts-react-redux-snippets" rel="nofollow"&gt;marketplace&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Example (Component with defaultProps)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Look, Ma' - Intellisense!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/sandstorm/typescript-react-app-kickstart-guide/master/images/Component&amp;amp;defaultProps.gif"&gt;&lt;img alt="component with defaultProps example" src="https://res.cloudinary.com/practicaldev/image/fetch/s--KhelAvE---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/sandstorm/typescript-react-app-kickstart-guide/master/images/Component%26defaultProps.gif"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sandstorm/typescript-react-app-kickstart-guide"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;We've also published [a VSCode Snippet Extension(&lt;a href="https://marketplace.visualstudio.com/items?itemName=Sandstorm.vscode-awesome-ts-react-redux-snippets"&gt;https://marketplace.visualstudio.com/items?itemName=Sandstorm.vscode-awesome-ts-react-redux-snippets&lt;/a&gt;) which helps to write TypeScript/React with little boilerplate.&lt;/p&gt;

&lt;p&gt;What are your experiences writing React + TypeScript?&lt;/p&gt;

&lt;p&gt;All the best,&lt;br&gt;
Sebastian&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>githunt</category>
    </item>
    <item>
      <title>Event Sourcing and CQRS</title>
      <dc:creator>Sebastian Kurfürst</dc:creator>
      <pubDate>Tue, 01 Jan 2019 14:10:07 +0000</pubDate>
      <link>https://dev.to/skurfuerst/event-sourcing-and-cqrs-4mo0</link>
      <guid>https://dev.to/skurfuerst/event-sourcing-and-cqrs-4mo0</guid>
      <description>&lt;p&gt;I've had the pleasure to join an EventSourcing and CQRS workshop with &lt;a href="http://verraes.net/"&gt;Mathias Verraes&lt;/a&gt; in Frankfurt, to figure out the next steps on how to apply Event Sourcing and CQRS to the Neos Content Repository.&lt;/p&gt;

&lt;p&gt;This blog post is about my learnings in general, and not about our specific implementation plans in Neos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the stage: How state is handled and modified
&lt;/h2&gt;

&lt;p&gt;Normally in web applications, people use relational databases to store their application state. Many frameworks apply patterns such as &lt;a href="http://www.martinfowler.com/eaaCatalog/activeRecord.html"&gt;Active Record&lt;/a&gt; or &lt;a href="http://martinfowler.com/eaaCatalog/domainModel.html"&gt;Domain Model&lt;/a&gt; to make state accessible and to modify it. No matter what pattern is used, usually an object is responsible for both reading from the state as well as updating it. This is different when using CQRS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CQRS&lt;/strong&gt; stands for Command Query Responsibility Seggregation; basically meaning that you'll use one object to read from the state (the Query), and a different object to modify the state (the Command).&lt;/p&gt;

&lt;p&gt;This allows you to separate the read from the write side; allowing to use different representations for state modification and for reading – and it allows &lt;strong&gt;multiple commands and multiple read models&lt;/strong&gt; to be used (more on that later)!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_VISeaza--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/13b5791af30275a6d5e725fe99aa73f71864a10f/diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_VISeaza--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/13b5791af30275a6d5e725fe99aa73f71864a10f/diagram.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Normally, you store state in your database. You have tables which contain e.g. the current user name, or the contents displayed currently on your website, or your currently available products. When this state is modified, this happens rather implicitely (e.g. through some method calls resulting in database queries). &lt;strong&gt;We'll now think of this state modification as an event.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core idea behind &lt;strong&gt;Event Sourcing&lt;/strong&gt; is different from the conventional approach: We won't store the current state, but rather &lt;strong&gt;all the events that led to it&lt;/strong&gt;. These events will be stored in an &lt;strong&gt;event store&lt;/strong&gt;, which is conceptually just a long, ordered, append-only list of all events which have ever happened in the system.&lt;/p&gt;

&lt;p&gt;This way, we can build up the current state by taking a "blank" state, then applying all events which have ever happened, and then we have the current state. Of course this would be horribly inefficient (more on this later, we're currently on the conceptual level). More than that, we're able to travel forth and back in time: We can also compute all previous states as they existed in the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if we don't store the current state, but rather all events that led to it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Having access to all previous states which happened in the system is an extremely powerful paradigm: You can, for example, see, how often your data was modified. By whom. What the old value was. So you have an audit log.&lt;/p&gt;

&lt;p&gt;Additionally (and that's for me the core benefit), you are able to take all old events in your system and use them to build up additional state for answering different questions than originally anticipated. We'll cover this in a bit.&lt;/p&gt;

&lt;p&gt;It turns out that event sourcing and CQRS work together beautifully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On the write side, you "basically" will just create events which you store in the event store.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the read side, you consume the events and build up the state you need for your application. This is called a &lt;strong&gt;projection&lt;/strong&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Commands, Events, and Projections
&lt;/h2&gt;

&lt;p&gt;Let's ensure we are on the same page regarding some core vocabulary:&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;command&lt;/strong&gt; is a state-mutation-intent. It has not yet happened. It might still fail. It corresponds to the "write" side of CQRS. Usually a command is written like "Create User" or "Add Node to the system".&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;event&lt;/strong&gt;, on the other hand, is the indication that a state mutation has happened. Usually it is written in past tense, like "User has been created" or "Node has been added to the system". An event is persisted in the &lt;strong&gt;event store&lt;/strong&gt;, which is an append-only log of all events.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;projection&lt;/strong&gt; reads all events and creates read-only state out of it. It corresponds to the "read" side of CQRS. When a new event comes in, the state is updated accordingly. Often, the projection state is stored in standard database tables. Projections, by nature, can always be re-created by clearing their state and applying all events (from the beginning of time) again. Basically, a projection is something like a cache.&lt;/p&gt;

&lt;h1&gt;
  
  
  Event Sourcing and CQRS – The Unified Model
&lt;/h1&gt;

&lt;p&gt;Following is a diagram which shows how CQRS and Event Sourcing work together. The diagram is split into three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  On top is the external/API side of our system.&lt;/li&gt;
&lt;li&gt;  On the right is the command side which mutates the state by generating events.&lt;/li&gt;
&lt;li&gt;  On the left is the read side which contains different projections which can be queried.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is &lt;strong&gt;inherent asynchronity&lt;/strong&gt; through the event store. This means that when a command is executed (and stored as event in the event store), it might take some time until the projections on the read side have been updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rOWU90GX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/6aaad03e357f91e95e45b93e6bff9904f0e73345/diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rOWU90GX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/6aaad03e357f91e95e45b93e6bff9904f0e73345/diagram.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - Simple Case - No Constraints
&lt;/h3&gt;

&lt;p&gt;In the most simple case, here's what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  1a - A command is sent which can always be applied ("Update the user's last name")&lt;/li&gt;
&lt;li&gt;  2a - The command is directly converted to an event ("User's last name has been updated") and stored in the event store.&lt;/li&gt;
&lt;li&gt;  (asynchronity)&lt;/li&gt;
&lt;li&gt;  3 - Sometimes later, the projections are updated, taking the event into account.&lt;/li&gt;
&lt;li&gt;  4 - Now, when the user queries the projections, he'll see the updated state.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2 - Hard Constraints - Enforced through Aggregates
&lt;/h3&gt;

&lt;p&gt;Sometimes, you need to ensure that an invariant on the state is always true. For example, it might be useful to define: "It is never possible to allocate a username twice." We basically need a safeguard to ensure that the "UserCreate" command always has distinct user names. This safeguard is &lt;strong&gt;called an aggregate.&lt;/strong&gt; (Do not confuse it with the term "Aggregate" in Domain-Driven-Design.) How does this safeguard work? It cannot read a projection, because this projection might be out-of-date.&lt;/p&gt;

&lt;p&gt;Thus, an aggregate works usually in the following way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  1b - A command is sent to an aggregate/command handler.&lt;/li&gt;
&lt;li&gt;  The Aggregate's state must be reconstituted so it can do its decision:

&lt;ul&gt;
&lt;li&gt;  2b - The aggregate first receives all events which it has previously emitted from the event store.&lt;/li&gt;
&lt;li&gt;  This way, it is able to reconstitute its state from previous events.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;  Then, the hard constraint is checked; i.e. in our example it is checked whether the username is already taken.&lt;/li&gt;
&lt;li&gt;  2c - If the constraint is fulfilled, the event is emitted to the store.&lt;/li&gt;
&lt;li&gt;  Otherwise, the command cannot be executed, and an error is returned.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3 - Soft Constraints - Query the read side to ensure invariants are "almost always" met
&lt;/h3&gt;

&lt;p&gt;It turns out that hard constraints are not always needed; quite to the contrary: If you think hard enough about a problem, you need them quite rarely. A soft constraint, on the other hand, is not a real constraint in the sense that an invariant is always met; but it can be extremely likely that the invariant is still met. We'll cover this more in-depth later. A workflow covering soft constraints works in the following way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  1c - A command is dispatched.&lt;/li&gt;
&lt;li&gt;  Before the command is transformed to an event, a soft constraint check can take place in the following way:&lt;/li&gt;
&lt;li&gt;  5 - We query some projection, knowing that it might not be fully up-to-date yet.&lt;/li&gt;
&lt;li&gt;  2a - Based on the projection result, we either accept the command and dispatch its corresponding event to the store, or we discard the command.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Consistency, Constraints and Invariants
&lt;/h1&gt;

&lt;p&gt;Before we dive into which constraints should be used when, let's talk a little about consistency.&lt;/p&gt;

&lt;p&gt;We often like to think about systems being &lt;strong&gt;immediately consistent&lt;/strong&gt; (also called &lt;strong&gt;strongly consistent&lt;/strong&gt;). This means that an event enters the system at a certain point in time, and everybody who accesses the system will be able to retrieve the new state directly after this event has been applied.&lt;/p&gt;

&lt;p&gt;On the other hand, systems might be &lt;strong&gt;not consistent&lt;/strong&gt; at all – this is generally a state which you try to avoid very hard; as usually you cannot easily recover back to consistent state from there.&lt;/p&gt;

&lt;p&gt;Between systems being immediately and not consistent, there's a big space in between which is called &lt;strong&gt;eventually consistent&lt;/strong&gt;. The core idea is that certain periods of time where the system is inconsistent might be acceptable, but it needs to be ensured that after "some time" (eventually) the system is consistent again. We'll explore this idea a bit further!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5s7933u8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/d06864b9e38991b457dc966017bd57ad0087ce89/diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5s7933u8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sandstorm.de/_Resources/Persistent/d06864b9e38991b457dc966017bd57ad0087ce89/diagram.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventual Consistency
&lt;/h2&gt;

&lt;p&gt;So, let's explore what Eventual Consistency actually can mean. Basically, we want to ensure the system &lt;strong&gt;should appear as consistent&lt;/strong&gt; as possible. "Appearing" consistent to me mostly means that a user gets a "consistent" view of what he did, i.e. when he created a comment on an article and reloads the page, he should see his comment; so we need to have a high probability that the relevant projection has already been updated.&lt;/p&gt;

&lt;p&gt;On the other hand, it does not really matter that much when other users see the comment; it is fine if there is a delay of a few seconds (which is a long time for "eventual consistency"). It also does not matter when e.g. a search index is updated.&lt;/p&gt;

&lt;p&gt;So, there are two tricks we can apply to make the system perceived as consistent, although "by the book" it is eventually consistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We usually do not need to update all projections synchronously, but rather many can be updated asynchronously.&lt;/li&gt;
&lt;li&gt;  When a change is visible for one user, it does not immediately need to be visible to other users of the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A small sidenote: Often it is suggested that a user interface should "simulate" the behavior, e.g. showing the new comment already before we got the confirmation from the server that the comment was successfully added. I personally think this is a nice trick to improve the perceived responsiveness of applications; but I still would ensure that the needed projections run mostly synchronous. Otherwise, you will get strange effects when e.g. pages are reloaded etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Soft Constraints are often sufficient
&lt;/h2&gt;

&lt;p&gt;I think this is best explained with an example. In the Neos content tree, there is a "MovedNode(source, target)" event indicating that the "source" node has been moved to "target". Let's say user 1 tries to move "A" inside "B", while user 2 tries to move "A" inside "C". Thus, there's a conflict.&lt;/p&gt;

&lt;p&gt;When I thought of preventing conflicts, I was directly thinking how a hard constraint with an aggregate could prevent this conflict. However, it might actually be not so easy enforcing this constraint with an aggregate.&lt;/p&gt;

&lt;p&gt;Let's for a moment think what happens when a soft constraint would be applied. If two people move the same node into different directions at the same time, the soft constraint check (5 in the image above) would succeed, because the projection was not yet updated. Thus, both move events would hit the event store. Now, during projection time, we have a few options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We can move the node from A inside B, discarding the move of user 2&lt;/li&gt;
&lt;li&gt;  We can move the node from A inside C, discarding the move of user 1&lt;/li&gt;
&lt;li&gt;  We can move the node from A inside B, and then move the node from inside B to inside C (or vice versa, depending on the event ordering)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all cases, one user will be a little confused because his change looks as if it was ignored by the system; while for the other user the end-result is the expected one. If we had hard constraints in place, then the "second" user would get an error that the move could not happen – this is unexpected for him as well. Thus, no matter whether we use hard or soft constraints, we'll always have one confused and one non-confused user in this example. Additional to that, the user whose command failed will probably just re-try his action; and chances are extremely high that the user's action will now work. (Unless, of course, another user moves the node again at exactly the same time :-) ). Thus, why should you use a hard constraint here if it has roughly the same experience for your end-user than when using a soft constraint?&lt;/p&gt;

&lt;p&gt;To sum it up, soft constraints are important because they catch the common case. They ensure your system is perceived as being consistent. They make it extremely likely that the system behaves predictable for your users.&lt;/p&gt;

&lt;p&gt;Often, you'll find very few cases where compensating an error would be very costly; these are usually good candidates for hard constraints. Then, try to create aggregates, where each of them should only care for one of these constraints.&lt;/p&gt;

&lt;p&gt;Soft constraints catch the common case. They ensure your system is perceived as being consistent.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation Details
&lt;/h1&gt;

&lt;p&gt;Here are some further implementation details which are important on a detail level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  As already stated, try to reduce the number of hard constraints as much as possible.&lt;/li&gt;
&lt;li&gt;  Treat your aggregates as implementation details of the write side. They are just very strong constraint checkers, after all.&lt;/li&gt;
&lt;li&gt;  Name your aggregates after the invariants they protect. Call them UserUniquenessAggregate instead of UserAggregate.&lt;/li&gt;
&lt;li&gt;  If one aggregate becomes too imperformant, you can often partition these further; e.g. have one UserUniquesAggregate per first-character of the user name.&lt;/li&gt;
&lt;li&gt;  Soft constraints should be checked inside your command pipeline [I still dislike this name]; e.g. before the command is converted to an event and persisted in the event store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's one topic which I did not cover at all yet, but which is important for many real-world applications: The concept of a &lt;strong&gt;Process Manager&lt;/strong&gt;. Basically, a process manager listens to emitted events (pretty much just like a projection); and can react to events by emitting new commands. They allow to encapsulate side-effects, such as accessing configuration or getting the current system time. Furthermore, they allow to orchestrate bigger flows, pretty much like React Redux Sagas.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we'll use all this in the Neos Content Repository
&lt;/h2&gt;

&lt;p&gt;This article covers my thinking and mindset which I currently use to approach the Neos Content Repository domain. It is not showing yet the specifics we want to use to apply the CQRS / Event Sourcing methodology. This is the topic for another blog post!&lt;/p&gt;

&lt;p&gt;PS: All views expressed here are my own; and of course, all errors and misunderstandings as well – &lt;a class="comment-mentioned-user" href="https://dev.to/mathias"&gt;@mathias&lt;/a&gt;
 - I hope there are not too many of them in here :-)&lt;br&gt;
PPS: &lt;em&gt;This is a cross-post of &lt;a href="https://sandstorm.de/de/blog/post/event-sourcing-and-cqrs.html"&gt;my post at our company blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>coding</category>
    </item>
  </channel>
</rss>
