<?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: Kirill Novik</title>
    <description>The latest articles on DEV Community by Kirill Novik (@kino6052).</description>
    <link>https://dev.to/kino6052</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%2F180985%2F9d02972a-158e-4fbb-a294-13986c501ade.png</url>
      <title>DEV Community: Kirill Novik</title>
      <link>https://dev.to/kino6052</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kino6052"/>
    <language>en</language>
    <item>
      <title>Computational Prime Number Framework Proofs</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 22 Mar 2025 06:43:25 +0000</pubDate>
      <link>https://dev.to/kino6052/computational-prime-number-framework-proofs-33a9</link>
      <guid>https://dev.to/kino6052/computational-prime-number-framework-proofs-33a9</guid>
      <description>&lt;p&gt;This article introduces a specific way of thinking about prime numbers and twin prime pairs using step-by-step filtering methods, like using a sieve. We call this the "Computational Prime Number Framework".&lt;/p&gt;

&lt;p&gt;Our goal is to show how defining primes based on these filtering processes leads to interesting conclusions, particularly about whether these types of primes go on forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; This framework uses its own specific rules and definitions. The results we discuss are based &lt;em&gt;only&lt;/em&gt; on these rules. This isn't intended as a proof using standard mathematical methods but rather as an exploration of ideas based on computational processes. More detailed explanations and rigorous arguments are available in further readings (Levels 2 and 3).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Filter: A "Sieve"
&lt;/h2&gt;

&lt;p&gt;Imagine a tool that filters lists of numbers. You give it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; A "block list" (e.g., &lt;code&gt;[2, 3]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; A list of numbers to check (e.g., &lt;code&gt;[2, 3, 4, ..., 20]&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tool removes any number from the check list if it's a multiple of &lt;em&gt;any&lt;/em&gt; number in the block list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This function acts as our number filter or "sieve"
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers_to_check&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Keeps numbers that are NOT multiples of anything in block_list.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;survivors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers_to_check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;is_multiple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Check divisibility
&lt;/span&gt;                &lt;span class="n"&gt;is_multiple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_multiple&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Keep numbers that survived
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;

&lt;span class="c1"&gt;# Example 1: Block multiples of 2
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sieving with [2]: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sieve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Output: Sieving with [2]: [3, 5, 7, 9, 11, 13]
&lt;/span&gt;
&lt;span class="c1"&gt;# Example 2: Block multiples of 2 OR 3
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sieving with [2, 3]: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sieve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Output: Sieving with [2, 3]: [5, 7, 11, 13]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finding Primes by Repeating the Filter ("Sifting")
&lt;/h2&gt;

&lt;p&gt;We can find prime numbers by using this sieve repeatedly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Start with an empty block list &lt;code&gt;[]&lt;/code&gt; and numbers &lt;code&gt;[2, 3, 4, ...]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Filter the list. Smallest survivor is 2. Add 2 to the block list &lt;code&gt;[2]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Filter the remaining numbers with &lt;code&gt;[2]&lt;/code&gt;. Smallest survivor is 3. Add 3 to the block list &lt;code&gt;[2, 3]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Filter the remaining numbers with &lt;code&gt;[2, 3]&lt;/code&gt;. Smallest survivor is 5. Add 5 to the block list &lt;code&gt;[2, 3, 5]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Keep repeating this: filter, take the smallest survivor, add it to the block list.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This function performs the step-by-step prime finding
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers_to_check&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Finds primes by repeating the sieve process.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;survivors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers_to_check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# Stop if no numbers left
&lt;/span&gt;
    &lt;span class="n"&gt;next_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# The smallest survivor is the next prime
&lt;/span&gt;    &lt;span class="c1"&gt;# Continue the process with the rest of the survivors
&lt;/span&gt;    &lt;span class="n"&gt;remaining_primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_list&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_prime&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_prime&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;remaining_primes&lt;/span&gt;

&lt;span class="c1"&gt;# Example: Find primes up to 50
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found primes up to 50: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Output: Found primes up to 50: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step-by-step "sifting" process generates the familiar sequence of prime numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Prime-Finding Process Never Stops
&lt;/h2&gt;

&lt;p&gt;A key result, similar to Euclid's ancient proof, applies here: this sifting process for primes never has to end.&lt;/p&gt;

&lt;p&gt;Why? Because no matter how many primes you've found and put in your block list, there's a proven method (explained in more detail in further readings) to construct a number that is &lt;em&gt;guaranteed&lt;/em&gt; to survive the next filtering step. Since a survivor can always be found, the process can always continue to find the &lt;em&gt;next&lt;/em&gt; prime.&lt;/p&gt;

&lt;p&gt;Conclusion within the framework: This prime-generating process continues infinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Twin Primes with a Special Filter
&lt;/h2&gt;

&lt;p&gt;Twin primes are prime pairs separated by 2, like (5, 7) or (11, 13). We can devise a similar step-by-step filtering process for them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Potential twin primes (except 3, 5) come in pairs like &lt;code&gt;(6n - 1, 6n + 1)&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt; is an index number (1, 2, 3,...).

&lt;ul&gt;
&lt;li&gt;n=1 gives (5, 7)&lt;/li&gt;
&lt;li&gt;n=2 gives (11, 13)&lt;/li&gt;
&lt;li&gt;n=3 gives (17, 19)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; We create a "twin sieve" that filters the &lt;em&gt;indices&lt;/em&gt; &lt;code&gt;n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; This twin sieve uses blocker numbers derived from the pairs corresponding to previously found indices &lt;code&gt;p&lt;/code&gt; (specifically, numbers like &lt;code&gt;6p-1&lt;/code&gt; and &lt;code&gt;6p+1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; It keeps an index &lt;code&gt;n&lt;/code&gt; only if &lt;em&gt;neither&lt;/em&gt; number in its pair &lt;code&gt;(6n-1, 6n+1)&lt;/code&gt; is divisible by any of the blocker numbers.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The special filter for twin prime indices
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twin_sieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found_indices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Filters indices n based on twin prime rules.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;found_indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;
    &lt;span class="n"&gt;last_found_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;found_indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Create block list from numbers 6p-1 and 6p+1 using found indices p
&lt;/span&gt;    &lt;span class="n"&gt;block_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Use a set for efficiency
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_found_index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;

    &lt;span class="n"&gt;surviving_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pair_num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;pair_num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;is_blocked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="c1"&gt;# Check the pair (6n-1, 6n+1) against all blockers
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;block_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair_num1&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;pair_num2&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;blocker&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;is_blocked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_blocked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;surviving_indices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;surviving_indices&lt;/span&gt;

&lt;span class="c1"&gt;# The step-by-step process for twin prime indices
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twin_recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found_indices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Finds twin prime indices step-by-step.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;survivors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;twin_sieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found_indices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indices_to_filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;next_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;remaining_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;twin_recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found_indices&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;survivors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;remaining_indices&lt;/span&gt;

&lt;span class="c1"&gt;# Helper to see the actual pairs
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_pairs_from_indices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Turns indices n back into pairs (6n-1, 6n+1)&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Example: Find twin prime indices up to n=50 (conceptually starts with index 1)
&lt;/span&gt;&lt;span class="n"&gt;indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;found_twin_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;twin_recursive_sifting&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="c1"&gt;# Start process after index 1
&lt;/span&gt;&lt;span class="n"&gt;all_found_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;found_twin_indices&lt;/span&gt; &lt;span class="c1"&gt;# Add index 1 back
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found twin indices: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;all_found_indices&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corresponding pairs: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;generate_pairs_from_indices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_found_indices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Output will show indices like [1, 2, 3, 5, 7...] and pairs like [(5, 7), (11, 13), ...]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "twin sifting" process finds pairs that behave like twin primes according to our framework's rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Twin Prime Process Also Never Stops
&lt;/h2&gt;

&lt;p&gt;Similar to the process for single primes, this step-by-step process for finding twin prime indices (and thus pairs) also never has to end.&lt;/p&gt;

&lt;p&gt;The reasoning is analogous: no matter how many twin prime indices have been found, there's a method (detailed in further readings) to construct a new index &lt;code&gt;n&lt;/code&gt; whose pair &lt;code&gt;(6n-1, 6n+1)&lt;/code&gt; is &lt;em&gt;guaranteed&lt;/em&gt; to survive the twin sieve's filtering step. Since a survivor can always be found, the twin sifting process can always continue to find the &lt;em&gt;next&lt;/em&gt; twin prime index.&lt;/p&gt;

&lt;p&gt;Conclusion within the framework: This twin-prime-generating process continues infinitely. Furthermore (as shown in detailed proofs), the pairs generated correspond exactly to conventional twin primes (except 3,5).&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This framework defines primes and twin primes based on specific, repeatable filtering processes ("sieves").&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The process for single primes matches known primes and demonstrably never stops.&lt;/li&gt;
&lt;li&gt;The process for twin primes identifies pairs matching known twin primes and also demonstrably never stops &lt;em&gt;within this framework's logic&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These results follow logically from the way the filtering processes are defined. While this approach is different from standard mathematics, it provides a computational perspective suggesting the infinite nature of both primes and twin primes. For the rigorous mathematical details behind the "always find a survivor" claims, please consult the more advanced levels of this documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplified Q&amp;amp;A
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;What's a sieve in this context?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;It's a defined process (like a function) that filters a list of numbers, removing multiples of numbers from a "block list".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;How does this framework find primes?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;By repeatedly using the sieve: filter numbers, take the smallest survivor, add it to the block list, and repeat. This finds standard primes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;How does it find twin primes?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Using a similar repeat-filtering process ("twin sieve"), but it works on &lt;em&gt;indices&lt;/em&gt; &lt;code&gt;n&lt;/code&gt; that represent pairs &lt;code&gt;(6n-1, 6n+1)&lt;/code&gt;, filtering them based on previous results.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Does this process ever stop?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No. The core argument (detailed elsewhere) is that you can &lt;em&gt;always&lt;/em&gt; construct a number (or an index for a pair) that will survive the next filtering step, so both processes continue infinitely.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Are the results the same as normal primes and twin primes?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Yes, the step-by-step processes generate numbers and pairs that match the conventional definitions of primes and twin primes (except the pair (3,5) for twins).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Is this a standard mathematical proof?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No, it's a proof based &lt;em&gt;only&lt;/em&gt; on the specific rules and definitions of this "Computational Prime Number Framework". It's an alternative way to explore the ideas.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;All Three Levels of Proof: &lt;a href="https://gist.github.com/kino6052/89114a5110f834c4faf4549a59a9dc5d" rel="noopener noreferrer"&gt;https://gist.github.com/kino6052/89114a5110f834c4faf4549a59a9dc5d&lt;/a&gt;&lt;/p&gt;

</description>
      <category>math</category>
      <category>python</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Building a legacy-proof app</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Fri, 31 May 2024 06:47:50 +0000</pubDate>
      <link>https://dev.to/kino6052/building-a-legacy-proof-app-3eb9</link>
      <guid>https://dev.to/kino6052/building-a-legacy-proof-app-3eb9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous articles, I shared some insights regarding why UI projects tend to become instant legacy.&lt;/p&gt;

&lt;p&gt;Everything was boiled down to two core needs: instant feedback and proper design patterns. Where, in terms of design patterns, the requirement for hard separation between view and logic was emphasized.&lt;/p&gt;

&lt;p&gt;I even suggested that Elm MVU was a way to go.&lt;/p&gt;

&lt;p&gt;However, despite MVU being an architecture that allows for the hard separation of view and logic, I have become convinced that MVU (and functional programming for that matter) suffers from being somewhat alien to a "natural" process of thinking and programming.&lt;/p&gt;

&lt;p&gt;By the word "natural", I mean something that correlates to the language we use in everyday life. Because functional programming can't always be described via such a language (e.g. despite monads (including Observable streams) being a relatively simple term, you won't be able to express it in such a language). I became convinced that programming that would better correlate to natural language is multiparadigm programming, where things are not strictly OOP and not strictly functional, but one or the other depending on clarity and the ease to work with.&lt;/p&gt;

&lt;p&gt;Therefore programming of the core of the application (the model/domain layer) isn't really about right or wrong, the model behind an application is a description of how a person who wrote it understands the program conceptually, and it better be one person or a group who is on the same conceptual page.&lt;/p&gt;

&lt;p&gt;In this article, I demonstrate a process of building an application that will have the necessary components of good architecture (according to Uncle Bob Martin) with some extra ones that I personally find valuable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;General

&lt;ul&gt;
&lt;li&gt;Testable&lt;/li&gt;
&lt;li&gt;Scalable&lt;/li&gt;
&lt;li&gt;Maintainable&lt;/li&gt;
&lt;li&gt;Follows SOLID&lt;/li&gt;
&lt;li&gt;Communicates a conceptual understanding of the creator&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Details

&lt;ul&gt;
&lt;li&gt;Dependency Inversion

&lt;ul&gt;
&lt;li&gt;Allows to postpone decisions of which tools to use

&lt;ul&gt;
&lt;li&gt;Framework agnostic&lt;/li&gt;
&lt;li&gt;Allows to optimize for performance, security, and the rest at later stages of development&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Design as a single source of truth for the view layer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Development process

&lt;ul&gt;
&lt;li&gt;Outside-in&lt;/li&gt;
&lt;li&gt;TDD&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But enough of philosophizing, let's dive into the paraphernalia. Shall we? &lt;/p&gt;

&lt;h2&gt;
  
  
  Development
&lt;/h2&gt;

&lt;p&gt;In this article, I will demonstrate a process of creating an application in an outside-in fashion. Where the ultimate source of truth is the design in Figma.&lt;/p&gt;

&lt;p&gt;We will then create a pure view as a function of state. It will not have any logic or state (other than a few details like scrolling unrelated to the domain logic).&lt;/p&gt;

&lt;p&gt;The logic will be created in an OOP manner as a composition of classes via DI in a composition root. This will allow us to postpone details like the choice of storage and possibly some other details.&lt;/p&gt;

&lt;p&gt;The Model will be connected to the view using a mapping function similar to ViewModel. It will have the necessary functionality to represent the view, but will not know anything about the details of the view (like a library used or DOM, etc.) &lt;/p&gt;

&lt;p&gt;Having a ViewModel will allow us to write the application in a TDD fashion not worrying about complex view libraries/framework runtimes and even allowing us to swap these.&lt;/p&gt;

&lt;p&gt;Because both the Model as well as ViewModel will be pure JS Objects (like POJOs), they should also be easily convertible to other languages.&lt;/p&gt;

&lt;p&gt;It is important to remember that this approach is all about writing legacy-proof apps (legacy-proof = “adaptable to change” = scalable), which we argued require instant feedback (via Storybook and black-box tests in Jest for example) and good design patterns, which in our case is MVVM and DI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Designs
&lt;/h3&gt;

&lt;p&gt;Here I explain how designs will be converted to Storybook stories.&lt;/p&gt;

&lt;p&gt;Since the tools for conversion are still far from perfect, we should rely on ourselves to implement components for the first time. However, as we change something in the designs, we can ask LLMs to adapt the changes to what we already have in the component code. This is possible because components, when implemented correctly, tend to be rather small and easily understood by LLMs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/community/file/1378258280093869378/conduit"&gt;Here is the link to the Figma file.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Storybook
&lt;/h3&gt;

&lt;p&gt;Once we convert designs to Storybook we can use the components to represent scenarios by putting together sequences of pre-setup pages (with certain props), and since we know what props need to happen in transition given certain user interactions we are preparing ourselves for writing black-box tests.&lt;/p&gt;

&lt;p&gt;The structure of the stories will resemble the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kino6052/conduit-mvu/tree/master/src/details/view/components"&gt;They will contain the actual component presentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Pages

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kino6052/conduit-mvu/tree/master/src/details/view/pages"&gt;Pages composed out of the components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Scenarios

&lt;ul&gt;
&lt;li&gt;A sequence of pages with various props for us to understand how props should change through interaction, which will allow us to write tests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;App

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kino6052/conduit-mvu/blob/master/src/details/view/App.stories.ts"&gt;The actual functional app with connected test doubles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It is important to note that we don’t need to connect actual databases or any other IO other than the view&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: MVVM &amp;amp; TDD
&lt;/h3&gt;

&lt;p&gt;As we write our tests, we implement the domain logic. &lt;/p&gt;

&lt;p&gt;I admit that I developed the sample application with very few tests and relied on the TypeScript type system for immediate feedback, so as a personal TODO, I will have to make sure I learn this practice, as I believe it ultimately saves a lot of time for larger projects like this one.&lt;/p&gt;

&lt;p&gt;While our tests need to tell whether the functionality is correct, the domain logic structure itself is really not about right or wrong. The conceptual model behind an application is a description of how a person who wrote it understands the program conceptually, and it better be one person or a group who is on the same conceptual page.&lt;/p&gt;

&lt;p&gt;As a philosophical side note, Immanuel Kant revolutionized philosophy by shifting the focus from the idea that we directly perceive the world as it truly is to the idea that we perceive the world as it appears to us through our own minds. This means we study our experiences of the world, not the world itself.&lt;/p&gt;

&lt;p&gt;Similarly, when developing a program, we shouldn't aim for a single "correct" solution. Instead, we should aim to create a program that effectively represents our understanding and concepts. The quality of this understanding can vary, but as long as the program follows SOLID principles, is testable, works correctly, and is understood by those who use it, we have achieved our goal.&lt;/p&gt;

&lt;p&gt;To illustrate, a program doesn't have to be OOP or functional, as in reality, if we could think like computers, we would write optimized binary code directly without any programming languages.&lt;/p&gt;

&lt;p&gt;However, I believe that every developer has dreamt about representing their application as simple classes that read like simplified English.&lt;/p&gt;

&lt;p&gt;Technically, MobX allows you to do exactly this - represent your model as simple classes. However, there is a price to pay, your classes have to be wrapped with decorators that allow for automatic reactivity. However, representing your application as simple classes doesn't mean you have to rely on yet another framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kino6052/conduit/tree/master/src/app/entities"&gt;Au contraire, what MobX does still could be accomplished with just simple POJOs.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The View Model, in our case, is a step between simple representation and the view that is always connected to some framework (React, Angular, Vue, Flutter, etc.), but since it is not connected to a framework, and we can use it as a simplified representation of the view that we can actually can (and should) test. Because ViewModel in our case is the boundary, that will allow us to write tests from the intent perspective (similar to behavior-driven development), where the user clicks or interacts with something. This will then allow the frequent refactoring that is required for us to revise our conceptual understanding as often as it needs to be done.&lt;/p&gt;

&lt;p&gt;So we will always have an opportunity to refactor as long as tests pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Composition root&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is important to remember that the ultimate detail of the application that will change the most is the composition root, where all dependencies will be combined.&lt;/p&gt;

&lt;p&gt;It is important to demonstrate in the code repository how you assemble your application as transparently as possible. It means that whenever somebody looks at the repo and then looks inside the index file, they should be able to understand how the application is structured and what its intent is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kino6052/conduit-mvu/blob/master/src/details/index.ts"&gt;Link to the sample app composition root&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Connecting to IO
&lt;/h3&gt;

&lt;p&gt;The last and the coolest part will be the ability to delay very hard decisions about technology for storage and other IO as far into the future as possible, thus allowing us to keep our pace and implement features while knowing that we still have time to make an educated decision based on our app and stakeholder needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pros

&lt;ul&gt;
&lt;li&gt;Legacy-proof&lt;/li&gt;
&lt;li&gt;Easy-to-learn

&lt;ul&gt;
&lt;li&gt;This approach builds on top of a lot of established practices like OOP, MVVM, and Component Composition&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Natural programming style&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cons

&lt;ul&gt;
&lt;li&gt;Requires you to form a coherent conceptual understanding of your application

&lt;ul&gt;
&lt;li&gt;You will have to doubt, rethink, and refactor&lt;/li&gt;
&lt;li&gt;There is no set algorithm for creating a model, you will have to experiment until it fits your needs

&lt;ul&gt;
&lt;li&gt;Frequent refactoring&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Simplify and optimize the model

&lt;ul&gt;
&lt;li&gt;While View and IO could be optimized separately,&lt;/li&gt;
&lt;li&gt;It requires you to make sure your model is as simple as possible&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article was a demonstration of how applications can be written so they are kept legacy-proof and are adaptable to change as true software should be (software means that it is soft or malleable and adaptable to changes).&lt;/p&gt;

&lt;p&gt;This is a refreshing view on UI development as modern UI is always 100% tied to a particular framework, but as this article suggests it should not be the case, and in fact not marrying it to a framework makes the code look much simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/kino6052/conduit-mvu/tree/master"&gt;Sample Application&lt;/a&gt;: The application that was created to illustrates concepts in this article&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.oreilly.com/library/view/clean-code-a/9780136083238/"&gt;Clean Code by Robert Martin&lt;/a&gt;: The famous book that explains core principles of scalable software&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.manning.com/books/dependency-injection-principles-practices-patterns"&gt;Dependency Injection Principles, Practices, and Patterns&lt;/a&gt;: A book that I consider to be the practical implementation of the concepts outlined in "Clean Code"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ui</category>
      <category>cleancode</category>
      <category>oop</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Decoupler and future implications for legacy-proof UI code</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:01:33 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-7-decoupler-and-future-implications-for-legacy-proof-ui-code-bb9</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-7-decoupler-and-future-implications-for-legacy-proof-ui-code-bb9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Over the course of the previous articles, I was trying to answer the question of how to write legacy-proof code.&lt;/p&gt;

&lt;p&gt;The main point was to achieve two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Get the correctness feedback quickly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make use of good design patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Albeit, there could likely be many other solutions, I considered the MVU pattern.&lt;/p&gt;

&lt;p&gt;This pattern allowed us to take advantage of Figma as a declarative view generator and storybook as a quick correct feedback mechanism to check UI.&lt;/p&gt;

&lt;p&gt;This pattern also made the application logic easy to test in a black-box manner.&lt;/p&gt;

&lt;p&gt;IO-update MVU is a very flexible pattern. And with every flexible tool (like Redux or React), there are too many ways to shoot yourself in the foot.&lt;/p&gt;

&lt;p&gt;To use this pattern wisely, you really have to know what you are doing. And given the time constraints of projects, most of the time you won’t be able to think deeply about how to make sure the legacy isn’t born.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Design as the single source of truth and the core asset for communication
&lt;/h3&gt;

&lt;p&gt;Designs should be the core asset for reasoning about the application (not the architecture) because developers, designers, and business representatives can now reason about direct interaction with the product being built.&lt;/p&gt;

&lt;p&gt;If UI is the main source of truth, then it is much easier to map the concepts and intentions to code based on the structures used in designs as opposed to business required in traditional OOP practices that blur the notion of what is an object, and where one begins and ends.&lt;/p&gt;

&lt;p&gt;Essentially, design already has the necessary entities and we don’t need to introduce extra ones from user scenarios, which makes it much easier to understand what entities we need in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Division of labor
&lt;/h3&gt;

&lt;p&gt;This approach allows to separate design and layout concerns from logic.&lt;br&gt;
 So that you only develop logic only when designs are ready.&lt;/p&gt;

&lt;p&gt;And, usually, this makes it much easier, as the majority of expectations could already be demonstrated in Storybook.&lt;/p&gt;

&lt;p&gt;This approach might allow to have a dedicated person for refactoring. That is, as a developer, your task is to only make sure your code passes tests, and the purpose of the dedicated refactoring specialist is to make sure everything is consistent with the patterns. Usually, such people are very opinionated, so it’s better to make sure it’s one person to avoid arguments.&lt;/p&gt;

&lt;p&gt;Having a dedicated person for refactoring would make the code review process lighter and less prone to bottlenecks, as the main criterion for working code is whether the tests pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declarative low-code tooling
&lt;/h3&gt;

&lt;p&gt;For better or for worse, to avoid the trap of too much flexibility for a lot of simpler use cases, frameworks should be introduced.&lt;/p&gt;

&lt;p&gt;I believe that the Decoupler MVU pattern allows for the creation of low-code frameworks similar to what we see with Unity and Unreal Engine.&lt;/p&gt;

&lt;p&gt;This pattern could allow us to build UIs using declarative tools in an IDE, where logic could be composed similar to how you compose scripts in Unity, Cloud Serverless functions, nodes in Blender, or Blueprints in Unreal Engine.&lt;/p&gt;

&lt;p&gt;But even without the low-code tooling for business logic, having the ability to generate the view layer from designs already eliminates the duplication of effort of transferring designs to code.&lt;/p&gt;

&lt;p&gt;Regarding the IO, there could also be low-code tools. Swagger could be taken as inspiration. &lt;a href="https://swagger.io/tools/swagger-codegen/"&gt;Swagger codegen&lt;/a&gt; is a great tool that allows you to declaratively produce code to interact with APIs.&lt;/p&gt;

&lt;p&gt;We could introduce other similar low-code visual tools to connect various parts of the app and produce code based on these declarations.&lt;/p&gt;

&lt;p&gt;And to build on top of this even further, why not introduce a dedicated IDE for this task? After all various mobile platforms as well as game development platforms do exactly that.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-assisted coding
&lt;/h3&gt;

&lt;p&gt;Not at the present stage of the technology, but in the not-so-distant future, it seems plausible to expect that given black box pure-function tests of your application, you could feed them to an AI model and get the implementation that would satisfy these tests.&lt;/p&gt;

&lt;p&gt;This would make development super easy.&lt;/p&gt;

&lt;p&gt;In fact, ChatGPT already introduced its &lt;a href="https://openai.com/blog/chatgpt-plugins"&gt;code interpreter&lt;/a&gt; that attempts to do a similar task of passing tests iteratively running its own code, and getting feedback from the interpreter.&lt;/p&gt;

&lt;p&gt;It would also allow us to fine-tune constraints for low-coupling and high-cohesion declaratively. So that the AI agent turns it into an optimization problem.&lt;/p&gt;

&lt;p&gt;It definitely a possibility now to use AI to help with some parts of the coding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-side rendering
&lt;/h3&gt;

&lt;p&gt;If we rely on Figma as a declarative view generator along with Decoupler MVU pattern, we could export our view in a format of any static templating engine, so that the backend wouldn’t have to do excessive server-side rendering logic but instead do something that is very natural — generate static html with parameters given and not requiring the complex configuration or setup or reliance on frameworks for that.&lt;/p&gt;

&lt;p&gt;Server-side rendering is notoriously complicated and being able to simplify the problem, we could save time and effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It seems ironic, that at the end of my search for legacy-proof code, I arrive at a solution that tends to eliminate code altogether and instead introduce declarative tooling that provides a quick feedback loop about how correct everything is.&lt;/p&gt;

&lt;p&gt;The IO-update MVU pattern embodies this shift, offering a straightforward way to handle UI and application logic. Separating the design realm from the business logic realm.&lt;/p&gt;

&lt;p&gt;However, let’s keep things in perspective. Decoupler MVU is an effective pattern, an effective tool, not a magic wand. It’s designed to make sure code can adapt quickly, with some useful side-effects that allow to improve team communication, streamline the onboarding process, and foster efficiency through low-code tooling.&lt;/p&gt;

&lt;p&gt;As attractive as the notion of AI-assisted coding might be, we aren’t there yet.&lt;/p&gt;

&lt;p&gt;So, our focus should remain on making the most of the tools we have today.&lt;/p&gt;

&lt;p&gt;Creating legacy-proof code isn’t a destination but a journey. It’s about gradual progress, learning, and adapting as we go. &lt;/p&gt;

&lt;p&gt;I believe that this MVU pattern is a promising step in this direction — a useful addition to our toolbox that can help make our code more maintainable and robust, however, only when it goes through baptism with fire — when it’s used to create something large, only then could we see its true pros and cons.&lt;/p&gt;

&lt;p&gt;Also, I believe that if we formulate problems as optimization and mapping problems, then solutions would no longer be a matter of opinion but rather something measurable. I believe that this pattern has the potential for formulating business logic in this way, where we could specify constraints and solve them (constraints like expected results, coupling, cohesion, performance, etc) via an automated process.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this path we covered over the course of the articles as much as I have.&lt;/p&gt;

&lt;p&gt;Let me know your thoughts in the comments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kino6052/decoupler-mvu/blob/main/README.md"&gt;If you consider using this approach and create something that you want to highlight, please consider forking this documentation and adding link to your project.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/kino6052/decoupler-mvu/blob/main/README.md"&gt;Decoupler-MVU Documentation:&lt;/a&gt; I created this docs to highlight projects that consider using this pattern&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guide.elm-lang.org/architecture/"&gt;Elm Architecture Guide&lt;/a&gt;: This guide presents an introduction to the Elm Architecture and provides useful details on how to structure applications effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://elmprogramming.com/model-view-update-part-1.html"&gt;Model View Update in Elm&lt;/a&gt;: This tutorial explores the model-view-update pattern in Elm, a key concept for building interactive applications in the language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://swagger.io/tools/swagger-codegen/"&gt;Swagger Codegen&lt;/a&gt;: Swagger Codegen is a tool that allows developers to generate client SDKs, server stubs, and API documentation from an OpenAPI Specification.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://openai.com/blog/chatgpt-plugins"&gt;OpenAI’s Blog on ChatGPT Plugins&lt;/a&gt;: This OpenAI blog post provides insights about ChatGPT plugins, which extend the functionality of the ChatGPT language model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/nerd-for-tech/are-unreal-engine-blueprints-no-code-5b5db2dce5f"&gt;Are Unreal Engine Blueprints No-Code?&lt;/a&gt;: This article discusses Unreal Engine Blueprints and their position in the spectrum of no-code solutions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vercel.com/docs/concepts/functions/serverless-functions"&gt;Vercel’s Guide on Serverless Functions&lt;/a&gt;: Vercel’s documentation provides a comprehensive overview of serverless functions and their implementation on the Vercel platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/products/functions"&gt;Azure Functions&lt;/a&gt;: Here’s the official Azure Functions product page, where you can learn about the features, benefits, and pricing of Microsoft’s serverless computing service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://learn.unity.com/tutorial/working-with-scripts#5f68b18eedbc2a001fbffd0f"&gt;Working with Scripts in Unity&lt;/a&gt;: This Unity tutorial presents an in-depth guide on working with scripts in the Unity game development platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vuejs.org/guide/scaling-up/ssr.html"&gt;Scaling Up with Server Side Rendering in Vue.js&lt;/a&gt;: This guide from the official Vue.js documentation provides a comprehensive tutorial on scaling up applications with server-side rendering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/what-exactly-is-client-side-rendering-and-hows-it-different-from-server-side-rendering-bd5c786b340d/"&gt;Client-Side Rendering vs. Server-Side Rendering&lt;/a&gt;: This FreeCodeCamp article discusses the differences between client-side rendering and server-side rendering, explaining the pros and cons of each.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering"&gt;Building Your Application with Server-Side Rendering in Next.js&lt;/a&gt;: Next.js’ documentation provides a guide on how to build applications using server-side rendering, a technique that can optimize the performance and SEO of your web applications.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>ui</category>
      <category>ai</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>From Figma to React, Vue, Svelte, Preact, and beyond</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:01:27 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-6-from-figma-to-react-vue-svelte-preact-and-beyond-1723</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-6-from-figma-to-react-vue-svelte-preact-and-beyond-1723</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous article, we discussed Decoupler MVU pattern for application development that allows us to separate business logic from presentation logic so that we could make our code legacy-proof.&lt;/p&gt;

&lt;p&gt;Because our presentation layer is now stateless and unaware of the business logic, it matches the designs very closely.&lt;/p&gt;

&lt;p&gt;In Figma, you essentially create the same thing — a stateless component tree. Just like any modern UI framework, Figma relies on components.&lt;/p&gt;

&lt;p&gt;Naturally, a question arises: could we use Figma as a single declarative source of truth for our view and eliminate a tedious transfer of designs to code?&lt;/p&gt;

&lt;p&gt;And, fortunately, it is not as far-fetched as it might sound!&lt;/p&gt;

&lt;p&gt;With Figma having introduced its dev-mode as well as various third-party plugins, it is now possible to convert designs into a stateless component tree in React and other frameworks. This is absolutely mind-blowing, but of course not without its own problems, as many of such code generation plugins miss various features.&lt;/p&gt;

&lt;p&gt;Among the problems I faced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can’t pass props in a top-down manner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can’t have arrays to generate lists&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in general, it is possible. In this article, I will show some practical examples that demonstrate the perks of what the complete separation of the view layer from the rest of the app allows to accomplish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Files
&lt;/h2&gt;

&lt;p&gt;To experiment with this idea, &lt;a href="https://www.figma.com/file/Wg2vgwu770QgLVn7vRwYhR/Decoupler-Figma-Chat?type=design&amp;amp;node-id=0%3A1&amp;amp;mode=design&amp;amp;t=E9KZf7KgR76M4OUA-1"&gt;I created a Figma design for a simplified chat.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main component has a title, message area, and input.&lt;/p&gt;

&lt;p&gt;Messages component in turn composes a list of messages which are in turn composes components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code generation for storybook
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SGrxals3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2428/1%2AG5pO0mHkiiEXb7CwQgWa-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SGrxals3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2428/1%2AG5pO0mHkiiEXb7CwQgWa-g.png" alt="" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a particularly useful plugin for React code generation from Figma — Anima.&lt;/p&gt;

&lt;p&gt;It is not perfect, as you still have to fix quite a few things about styles and code here in there, but it does a pretty good job of structuring components.&lt;/p&gt;

&lt;p&gt;It also does a good job of generating TypeScript code.&lt;/p&gt;

&lt;p&gt;Having this code generated, I had to fix styles and properly pass props, as well as add EventWrapper on top of the interactive components.&lt;/p&gt;

&lt;p&gt;I didn’t have to touch any other piece of the logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond React
&lt;/h2&gt;

&lt;p&gt;Figma’s ability to generate React code (albeit with some flaws), naturally got me thinking if I could now convert this code to other view frameworks — like Vue, Svelte, and Preact.&lt;/p&gt;

&lt;p&gt;These frameworks don’t rely 100% on the same concepts, but the concepts from one framework generally map well to the concepts in other frameworks.&lt;/p&gt;

&lt;p&gt;Unfortunately, Anima only generates React code. Other plugins could be used for this task, but I wasn't able to find other code-generation tools that do as good of a job.&lt;/p&gt;

&lt;p&gt;Naturally, for this task, I used ChatGPT to help me convert the barebone view layer. And it did pretty well! I still had to fix some issues, but it did 90% bona fide work.&lt;/p&gt;

&lt;p&gt;I was feeding it component by component to generate the final result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/dashboard/sandboxes/Decoupler?workspace=9005181b-aa56-4906-8899-3240322a44e1"&gt;Here are the sandboxes with the result.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And because it’s all javascript code, you could replace this part of the application with the view in a desired framework. Although, it would probably be easier to do it the other way, where you add all non-view logic to the project with a desired view, as its configuration is probably relying heavily on the chosen framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  How about going cross-platform?
&lt;/h2&gt;

&lt;p&gt;Having proof that I can now change tooling as I please (with a bit of extra work of course but still), why not take it to the next level?&lt;/p&gt;

&lt;p&gt;How about we turn our code to Flutter?&lt;/p&gt;

&lt;p&gt;Concepts in React and other frameworks don’t correspond 100% to what Flutter relies on, but it is very very close. It maps relatively well, and if we had some extra information that we could generate from Figma, we would be able to map to all frameworks easily.&lt;/p&gt;

&lt;p&gt;Initially, I wasn’t using ChatGPT to generate code in this case. I used another plugin in Figma — Figma-to-code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X-BMhF-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AUAMbpUPyqqhWe2jYR-A8-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X-BMhF-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AUAMbpUPyqqhWe2jYR-A8-Q.png" alt="" width="509" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike Anima, it didn’t do as good of a job with generating components, but it still generated the entire tree. And, most importantly, the generated code worked.&lt;/p&gt;

&lt;p&gt;I then broke it down into components and stored them in separate files.&lt;/p&gt;

&lt;p&gt;Then I restructured it to match the file structure of the React project.&lt;/p&gt;

&lt;p&gt;Once the structure matched my React project, I started converting non-react code to dart with ChatGPT.&lt;/p&gt;

&lt;p&gt;ChatGPT did a great job. Some issues with types I was able to fix easily as Dart has great type-checking and hints.&lt;/p&gt;

&lt;p&gt;I then regenerated components from React project and put them into the Flutter project.&lt;/p&gt;

&lt;p&gt;It was a miracle to see that I was able closely to match all the concepts and structures relatively easily with these great tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kino6052/flutter-test/tree/master/chatgpt_clone/lib"&gt;Here is the result project.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, I attempted to provide a practical example, of what I mean by making design the single declarative source of truth for UI.&lt;/p&gt;

&lt;p&gt;Despite the fact that the code-generation tooling is still quite limited in functionality, it allows for eliminating the duplication of effort of converting a design to a view as well as not being tied to a single framework or library.&lt;/p&gt;

&lt;p&gt;The reason I was able to accomplish the conversion of React project to Vue, Svelte, Preact, and Flutter relatively easily was because of the decomposition that we achieved with the MVU pattern.&lt;/p&gt;

&lt;p&gt;Maybe ChatGPT would be able to provide me with 90% working code if it was coupling all the logic, but fixing the remaining 10% would definitely be more challenging in that case.&lt;/p&gt;

&lt;p&gt;Having a decoupled stateless view layer is easily convertible to view layers written using different technologies.&lt;/p&gt;

&lt;p&gt;Converting the pure update function as well as tests is the easiest part as the only issue you might face is working with types, but having tests and various type checks in place you would be able to fix it relatively easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-7-decoupler-and-future-implications-for-legacy-proof-ui-code-bb9"&gt;Part 7 — Decoupler and the future for legacy-proof UI:&lt;/a&gt; Further exploration of perks that this approach allows that go even beyond legacy-proof code considerations&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;At first, I wanted to have a full-blown copy of ChatGPT UI, but that was too ambitious, you can see &lt;a href="https://codesandbox.io/s/decoupler-chatgpt-ui-987x9l"&gt;my attempt at that in this sandbox&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.animaapp.com/figma"&gt;Anima &lt;/a&gt;— Excellent Figma to React code generator&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.figma.com/community/plugin/842128343887142055/Figma-to-Code-(HTML%2C-Tailwind%2C-Flutter%2C-SwiftUI)"&gt;Figma-to-Code Plugin&lt;/a&gt; — Great plugin for generating code for various frameworks from Figma&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://swagger.io/tools/swagger-codegen/"&gt;Swagger Codegen &lt;/a&gt;— An excellent example of a code generation tooling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.figma.com/"&gt;Figma Official Website&lt;/a&gt;: Figma is a popular tool for UI/UX design and prototyping. With its collaborative interface, it enables multiple designers to work together in real-time. This can be especially handy when working on a legacy-proof UI project, as it allows for a seamless transition from design to code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://designcode.io/ui-design-handbook-turn-your-designs-into-code"&gt;UI Design Handbook by Design+Code&lt;/a&gt;: This handbook provides a detailed guide on how to turn your designs into code. It covers everything from working with shapes, icons, and images, to handling typography, layout, and spacing. A perfect resource for developers who want to create pixel-perfect UIs that match the initial designs closely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.figma.com/hc/en-us/articles/5601345554967-Widget-Code-Generator-by-Figma"&gt;Widget Code Generator by Figma&lt;/a&gt;: This article introduces a powerful tool provided by Figma — the Widget Code Generator. It automatically generates code for your designs, helping to streamline the development process and reduce the gap between design and implementation. It can be particularly useful for our legacy-proof UI project, enabling faster and more accurate transition from design to code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>elm</category>
      <category>figma</category>
      <category>ai</category>
    </item>
    <item>
      <title>MVU architecture in a React application</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:01:20 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-5-mvu-architecture-in-a-react-application-4kgi</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-5-mvu-architecture-in-a-react-application-4kgi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;How to introduce the MVU pattern in a React application?&lt;/p&gt;

&lt;p&gt;In the previous articles, we arrived at the conclusion that in order for code to not become legacy we would need to separate our view from business logic in a different way than Redux and Elm are doing it as both approaches not allowing to disentangle view from the business logic completely.&lt;/p&gt;

&lt;p&gt;I demonstrated a way to make React a decoupled stateless view similar to how it is done in Elm as part of our quest of trying to make code legacy-proof.&lt;/p&gt;

&lt;p&gt;Now, a natural question arises — how about the rest of the pattern? How can we tie everything together?&lt;/p&gt;

&lt;h2&gt;
  
  
  Elm MVU Pattern
&lt;/h2&gt;

&lt;p&gt;Elm handles UI unidirectional flow using an MVU pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x8uEkq6A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AWDx06Z80iYEJlyVl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x8uEkq6A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2AWDx06Z80iYEJlyVl.png" alt="Elm MVU pattern" width="640" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a model — data that represents our application state.&lt;/p&gt;

&lt;p&gt;This model is used by the view layer to display the correct state of the UI.&lt;/p&gt;

&lt;p&gt;When a user interacts with the UI a message is sent to an update function that returns a new model (new state), which in turn is consumed by the view thus going full circle.&lt;/p&gt;

&lt;p&gt;There is another part to it, however, commands that produce side effects as well as subscriptions that seem to unnecessarily complicate this pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupler MVU
&lt;/h2&gt;

&lt;p&gt;In reality, a better abstraction of this would be to make the view as well as all other side effect logic one and the same — after all, they all represent IO agents.&lt;/p&gt;

&lt;p&gt;IO agent is really a part of this loop, a non-pure function that takes the model (state), does something with it and the outside world and then returns a message.&lt;/p&gt;

&lt;p&gt;In the case of view, these actions are button clicks and other user actions. The user sees a certain screen, does some decision-making, and as a result, there is an interaction that results in a message. (User-UI interaction can be abstracted as an IO agent)&lt;/p&gt;

&lt;p&gt;In the case of other IO, like HTTP requests, the IO agent sees some state of the application and based on certain parameters decides to fetch, or not to fetch, something and then sends a message.&lt;/p&gt;

&lt;p&gt;This abstraction, where both view, requests, and other non-pure functions are just a form of an IO agent, makes it easy to decouple IO logic from the core of the application and thus allowing us to make the unidirectional flow easy to test, as the update function is just a pure function (that could be tested in a black box testing manner) and IO agents now could be swapped with simplified representations for the ease of testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ywrpnfr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AE4Ga-DTk5-DjfpTQrplNSQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ywrpnfr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AE4Ga-DTk5-DjfpTQrplNSQ.png" alt="" width="262" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This abstraction also makes sense for the vast majority of the UI applications as the majority of them are IO-bound applications (as opposed to CPU-bound or GPU-bound), where their main purpose is to communicate with various Input-Output components (side-effects) — like HTTP requests, WebSockets, UI-user interaction and many more.&lt;/p&gt;

&lt;p&gt;So to simplify this pattern and to allow for more flexibility and decouple components better we could just use this IO-Update pattern.&lt;/p&gt;

&lt;p&gt;The unidirectional flow of the application now can be represented as a simple function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;applicationLoop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;applicationLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;applicationLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&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;p&gt;This representation of an application seems to be both simple and natural to think about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying this pattern
&lt;/h2&gt;

&lt;p&gt;In the endeavor of ensuring unidirectional flow, I adopted the MIU pattern and created a class that I named ‘decoupler’. This class connects the view with the rest of the application seamlessly. You can see this in action in the linked application here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kino6052/figma-chat-react"&gt;Here is the link to the app where I connected the view and the rest of the application using this pattern.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to this, I incorporated black box tests for the update function and devised a simple IO agent to facilitate server communication. It is important to underscore the significance of these black box tests. They not only ensure the functionality of our code but also provide the flexibility to refactor it. By refactoring, we can introduce necessary design patterns to prevent our logic from becoming convoluted.&lt;/p&gt;

&lt;p&gt;The real advantage of this pattern is its flexibility and adaptability. It doesn’t dictate how you implement the various components, thus providing freedom to choose appropriate tools for each part of the application. This flexibility extends to allowing timely refactoring and introduction of design patterns, which are crucial for maintaining legacy-proof code.&lt;/p&gt;

&lt;p&gt;Importantly, this flexibility allows for the introduction of code generation and various automation.&lt;/p&gt;

&lt;p&gt;Furthermore, the decoupler pattern offers an incremental approach to its implementation. It doesn’t impose any restrictions on how the different parts should be implemented. Therefore, you have the liberty to put Redux behind the update function or customize it to suit your needs.&lt;/p&gt;

&lt;p&gt;In essence, this pattern offers highly desirable outcomes — ease of receiving feedback and the ability to incorporate good design patterns. These are both essential components for maintaining legacy-proof code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we built on top of the previous article, where we introduced a decoupled view layer, and now considered a practical example of how to implement MVU pattern making this view interactive.&lt;/p&gt;

&lt;p&gt;This article also introduced a slightly modified and simplified version of MVU that I term IO-update.&lt;/p&gt;

&lt;p&gt;As mentioned in the previous examples, among the advantages that we will consider in future articles is the ability to automate the conversion of designs to code, where the view layer no longer has to be tied to a particular technology as well as the ease of writing black box tests for the update&lt;/p&gt;

&lt;p&gt;We now were able to implement an MVU pattern that will allow us to make code legacy-proof.&lt;/p&gt;

&lt;p&gt;In the next article, we will put this approach to the test and see where it could get us.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-6-from-figma-to-react-vue-svelte-preact-and-beyond-1723"&gt;Part 6 — From Figma to React, Vue, Svelte, Preact, and Beyond:&lt;/a&gt; Exploring the legacy-proof (adaptability) benefits of having a completely separate view that matches designs closely&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guide.elm-lang.org/architecture/"&gt;Elm Architecture Explained&lt;/a&gt;: This guide introduces you to the Elm Architecture. It’s a good starting point to understand the Model-View-Update (MVU) pattern and how it is implemented in Elm. It can offer insights on how we can incorporate these principles into our React application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.figma.com/"&gt;Figma Official Website&lt;/a&gt;: Figma is a popular tool for UI/UX design and prototyping. With its collaborative interface, it enables multiple designers to work together in real-time. This can be especially handy when working on a legacy-proof UI project, as it allows for a seamless transition from design to code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://designcode.io/ui-design-handbook-turn-your-designs-into-code"&gt;UI Design Handbook by Design+Code&lt;/a&gt;: This handbook provides a detailed guide on how to turn your designs into code. It covers everything from working with shapes, icons, and images, to handling typography, layout, and spacing. A perfect resource for developers who want to create pixel-perfect UIs that match the initial designs closely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.figma.com/hc/en-us/articles/5601345554967-Widget-Code-Generator-by-Figma"&gt;Widget Code Generator by Figma&lt;/a&gt;: This article introduces a powerful tool provided by Figma — the Widget Code Generator. It automatically generates code for your designs, helping to streamline the development process and reduce the gap between design and implementation. It can be particularly useful for our legacy-proof UI project, enabling faster and more accurate transition from design to code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>react</category>
      <category>elm</category>
      <category>webdev</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>React as a decoupled stateless view in Storybook</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:01:12 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-4-react-as-a-decoupled-stateless-view-in-storybook-323o</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-4-react-as-a-decoupled-stateless-view-in-storybook-323o</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;How to make React a stateless view with Storybook?&lt;/p&gt;

&lt;p&gt;In the previous articles, we arrived at the conclusion that in order for code to not become legacy we would need to separate our view from business logic in a different way than Redux and Elm are doing it as both approaches not allowing to disentangle view from the business logic completely.&lt;/p&gt;

&lt;p&gt;Let’s see how this could be achieved.&lt;/p&gt;

&lt;h2&gt;
  
  
  React view as a pure function of state
&lt;/h2&gt;

&lt;p&gt;React has changed how we approach UI — its philosophy is based on the simple yet powerful concepts of using &lt;strong&gt;components&lt;/strong&gt; as well as &lt;strong&gt;unidirectional data flow&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is also believed that React introduced reactivity into UI, but this is not the case as MVVM patterns, as well as frameworks, that rely heavily on reactivity were introduced long before React.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not only are these concepts very natural ways of thinking about UIs, but they also bring design and development onto the same page.&lt;/p&gt;

&lt;p&gt;Elm relies on similar concepts and uses pure composable view functions (stateless components).&lt;/p&gt;

&lt;p&gt;However, React falls short as soon as it introduces statefulness and inverse data flow to the picture thus opening the door for high coupling between business logic and presentation logic.&lt;/p&gt;

&lt;p&gt;Redux, despite being designed to mimic Elm in part, still tightly couples with the view via the concept of containers.&lt;/p&gt;

&lt;p&gt;To make React take full advantage of patterns that Elm follows, we would need to remove inverse data flow from it as well as enforce top-down data flow (as opposed to Redux container components).&lt;/p&gt;

&lt;p&gt;I will try to demonstrate that this approach allows for what we’re looking for — decoupled view and less boilerplate.&lt;/p&gt;

&lt;p&gt;Regarding concerns of prop-drilling, props are not going to be drilled in a traditional sense, but just like we describe a view as a declarative tree, the props would just match that pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a static version of the application using Storybook
&lt;/h2&gt;

&lt;p&gt;To remove the inverse data flow and to enforce top-down data flow, we would need to compose our state using props without any callback functions following the first two steps of the React documentation (&lt;a href="https://react.dev/learn/thinking-in-react#start-with-the-mockup"&gt;https://react.dev/learn/thinking-in-react#start-with-the-mockup&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kino6052.github.io/figma-chat-react/?path=/story/decoupler-interactiveapp--interactive-app"&gt;Here is an example of static version of the app we want to build in storybook.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fEJZbzYo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AZ7Wjb1JfuqYW90f8GNi3cw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fEJZbzYo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AZ7Wjb1JfuqYW90f8GNi3cw.png" alt="" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dEf_U4L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AKd7qLxnQYOxaCxAHmxJcFw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dEf_U4L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AKd7qLxnQYOxaCxAHmxJcFw.png" alt="" width="182" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The props for the entire view are easily composable as a structure that matches exactly the component structure and is statically typed.&lt;/p&gt;

&lt;p&gt;This way allows us to easily generate various substates that we would need to check various states of the UI.&lt;/p&gt;

&lt;p&gt;Thus helping us to quickly gauge the correctness of our UI using Storybook.&lt;/p&gt;

&lt;p&gt;One thing to note, however, is that now as our UI is closely matching Figma designs, it seems a bit tedious to convert the designs to components, and this ideally should be automated.&lt;/p&gt;

&lt;p&gt;This is one of the reasons why UI development is so hard — there is a lot of labor that goes into making a high-fidelity transfer of designs to code.&lt;/p&gt;

&lt;p&gt;At one of my previous jobs a manager asked why, despite the fact that all we do day and night is making UIs, it still takes us so very long to make a page with React and other fancy tooling we are using.&lt;/p&gt;

&lt;p&gt;It really got me thinking, as I myself didn’t quite understand why that was the case, but now, as I look back, I see that aside from quick feedback and design pattern, the transfer of designs to code is also a big part of the problem.&lt;/p&gt;

&lt;p&gt;We would return to this point in a future article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Wrapper
&lt;/h2&gt;

&lt;p&gt;We made our static view and it works as a pure function from state.&lt;/p&gt;

&lt;p&gt;However, to make this UI interactive, similar to Elm’s MVU, we still need to produce some actions, however, we need to be mindful to not tightly-couple to business logic as we do this.&lt;/p&gt;

&lt;p&gt;An approach that we could follow is to introduce declarative wrappers that take metadata: ids and event information and send it to an observable subject, that we could then subscribe to as needed. We shouldn’t however send any data about what action we want to perform as it would tightly couple us to the business logic. (This is often done both in Elm and Redux)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is important to note that the point of having this wrapper is that it could be added declaratively (ideally without even touching the code and instead relying on code generation tooling to generate code from designs, which we will return in future articles).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As an example, this is what such a declarative pattern might look like.&lt;br&gt;
Note that this is just a demonstration of the concept. To be fully usable, it will need to be optimized for a variety of use cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;controlId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;uniqueId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;childrenWithProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isValidElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nx"&gt;EventSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nx"&gt;EventSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;onKeyDown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KeyboardEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;EventSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// NOTE: This should be extensible for various handlers&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;childrenWithProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can wrap our interactive components with this wrapper like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would probably make more sense to declaratively select what handlers we would need like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onChange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onFocus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if cloning the children subtree is too much for us, it might make sense to use it more imperatively, although this should still be easy to generate such code with code generation tooling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
      &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; 
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IdObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IdObject&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here EventWrapper methods return handlers that pass the necessary information to the subject and work exactly like the initial wrapper does.&lt;/p&gt;

&lt;p&gt;Note that for list elements we would need to provide extra metadata about them to be able to differentiate between them. A ‘controlId’ helps us identify which control element is being referred to, while a ‘uniqueId’ allows us to distinguish between various elements in a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;controlId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;controlId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;uniqueId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uniqueId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;EventWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Side-notes
&lt;/h2&gt;

&lt;p&gt;It is still possible to use Storybook for gauging quick feedback about how correct the application functions even when the view layer is not completely decoupled from logic.&lt;/p&gt;

&lt;p&gt;However, because of this coupling, there will be a need for mocking and it can become very complicated, or it might cause you to rely on the actual communication with the integrated parts of the application.&lt;/p&gt;

&lt;p&gt;It might work for a while, but over time will become complex to manage, unreliable, and potentially unusable.&lt;/p&gt;

&lt;p&gt;Keeping the view layer pure, will allow us to reliably check the view layer in necessary states, be able to reason about it, and rely on automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we considered a practical example of how to make the view layer completely disjoint from the rest of the application and used Storybook to be able to check quickly the various states this view can be in.&lt;/p&gt;

&lt;p&gt;The ability to separate the view layer completely and make a pure function offers many advantages.&lt;/p&gt;

&lt;p&gt;Among the advantages that we will consider in future articles is the ability to automate the conversion of designs to code, where the view layer no longer has to be tied to a particular technology.&lt;/p&gt;

&lt;p&gt;Also, now that we made our stateless view produce actions, we can finally connect in the unidirectional data-flow loop to make it interactive.&lt;/p&gt;

&lt;p&gt;We will explore the rest of the MVU pattern in the next article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-5-mvu-architecture-in-a-react-application-4kgi"&gt;Part 5 — MVU architecture in a React application:&lt;/a&gt; Example of how to make a completely stateless view interactive&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://reactjs.org/docs/thinking-in-react.html"&gt;Thinking in React&lt;/a&gt;: This is a guide provided by the official React documentation that walks you through the mindset you need to effectively use React in your projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://storybook.js.org/docs/react/get-started/introduction"&gt;Storybook Documentation&lt;/a&gt;: Storybook is a powerful tool for UI development, and this documentation will get you up to speed on using it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guide.elm-lang.org/architecture/"&gt;Elm Architecture&lt;/a&gt;: This link explains the architecture of Elm apps, which heavily inspired the creation of Redux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://reactjs.org/docs/components-and-props.html"&gt;React Components and Props&lt;/a&gt;: This page in the official React documentation explains how to use components and props in React.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/understanding-reacts-data-flow-718e111f1541/"&gt;Understanding React’s Unidirectional Data Flow&lt;/a&gt;: This article gives a detailed understanding of the unidirectional data flow in React.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@learnreact/container-components-c0e67432e005"&gt;React Container Components&lt;/a&gt;: This article discusses the concept of container components in React and Redux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://rxjs.dev/guide/subject"&gt;React Observable Subject&lt;/a&gt;: This guide explains how to use observable subjects in React.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.figma.com/"&gt;Figma Design Tool&lt;/a&gt;: Figma is a web-based UI design and prototyping tool. The link leads to the official website where you can learn more about the tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kino6052.github.io/figma-chat-react/?path=/story/decoupler-interactiveapp--interactive-app"&gt;Example of a Static Version of an App&lt;/a&gt;: This is an example of a static version of an app built with Storybook.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>storybook</category>
      <category>elm</category>
    </item>
    <item>
      <title>How to make UI testable and easy to change?</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:01:05 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-3-how-to-make-uis-testable-and-easy-to-change-65</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-3-how-to-make-uis-testable-and-easy-to-change-65</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;How to make UI testable and easy to change?&lt;/p&gt;

&lt;p&gt;In the previous articles, we arrived at the conclusion that in order for code to not become legacy there needs to be quick correctness feedback and good patterns in place.&lt;/p&gt;

&lt;p&gt;Given these two conditions will exhibit the ability to be changed easily.&lt;/p&gt;

&lt;p&gt;However, there exist problems with current UI approaches that make these two conditions difficult to achieve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems with architecture and design patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  React and similar view libraries
&lt;/h3&gt;

&lt;p&gt;React and many other similar front-end libraries tend to fall into the same trap. They tightly couple business, IO, and state management logic.&lt;/p&gt;

&lt;p&gt;You develop your components with hot reloading, adding server requests (IO) logic inside of the body of the component, as well as adding redux or similar hooks. Not only it is very convenient, but also allows you to develop something that works and do so very quickly.&lt;/p&gt;

&lt;p&gt;This works well for small projects. But this does not work for development at scale.&lt;/p&gt;

&lt;p&gt;By allowing you this flexibility, you introduced everything that makes you view layer not just the view layer, but a mix of various layers, and it’s now going to be hard to turn back.&lt;/p&gt;

&lt;p&gt;Surprisingly, React was introduced as a view library, that was intended for only handling the view, but in reality, it rarely does handle just view as hooks have now taken over the world.&lt;/p&gt;

&lt;h3&gt;
  
  
  Survey of architectural approaches
&lt;/h3&gt;

&lt;p&gt;The problem of tight coupling of logic with view is not new and there have been many approaches to solve this problem.&lt;/p&gt;

&lt;h4&gt;
  
  
  Model-View-Controller (MVC)
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Related frameworks: Ruby on Rails (Ruby), Django (Python), Laravel (PHP), Spring MVC (Java), ASP.NET MVC (C#)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The MVC pattern is perhaps the most classic architectural pattern in UI development. This pattern separates application logic into three interconnected components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Model manages the data, logic, and rules of the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The View abstracts the details of the technology used for presentation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Controller accepts inputs and converts them to commands for the Model or View&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue with MVC is that it can often become convoluted as the application scales, with the controller handling a significant portion of the logic. It becomes challenging to manage and test due to the increased dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF MVC ==&lt;/span&gt;

&lt;span class="c1"&gt;// MODEL&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// VIEW&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;updateLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// CONTROLLER&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buttonClicked&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;buttonClicked&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Main&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buttonModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buttonView&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Model-View-Presenter (MVP):
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Related frameworks: GWT (Java), Vaadin (Java)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;MVP is a derivative of the MVC architecture and is mostly used for building user interfaces. In MVP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Model is the data layer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The View is just like in MVC but now handles subscription to the events too (not in Controller anymore) as well as keeps a reference to the presenter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Presenter is a essentially a controller but without subscriptions that is a bit easier to test on its own.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though the pattern was meant to make testing easier, in reality, we get the complete opposite of what we wanted: the view layer knows everything about the presenter, and presenter doesn't know anything about the view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF MVP ==&lt;/span&gt;

&lt;span class="c1"&gt;// MODEL&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// VIEW&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;setPresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presenter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;updateLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// PRESENTER&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonPresenter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setPresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Main&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonPresenter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonPresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buttonView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buttonModel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Model-View-ViewModel (MVVM)
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Related frameworks: Knockout.js (JavaScript), Vue.js (JavaScript), Angular (JavaScript/TypeScript), WPF (Windows Presentation Foundation) with C#&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;MVVM is another derivative of MVC where the controller is really a controller that also handles pub-sub data binding for the view layer. It also relies on declarative markup. However, testing presentation in separation is very difficult as there is not explicit state view can be easily set to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF MVVM ==&lt;/span&gt;

&lt;span class="c1"&gt;// MODEL&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// VIEWMODEL&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ButtonViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Binding the ViewModel's method to the button's click event&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;updateView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize ViewModel&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonViewModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ButtonViewModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Model-View-Update (MVU)
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Popular frameworks: Elm (Elm Language), Fabulous (F#), SwiftUI (Swift)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The MVU pattern, popularized by The Elm Architecture, is a relatively new approach to front-end development. In MVU, the model defines the state of the application, the view renders the UI based on the state (model), and the update function modifies the state based on messages (like user actions or server responses). This unidirectional data flow ensures that the UI is predictable and easier to debug.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF MVU ==&lt;/span&gt;

&lt;span class="c1"&gt;// MODEL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;clickCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// VIEW&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterLabel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;counterLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// UPDATE&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;clickCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&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;h4&gt;
  
  
  Flux
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Popular frameworks: Original Flux, Redux, Alt.js, RefluxJS, Marty.js, McFly, Fluxible, Delorean, NuclearJS&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Flux is an application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow, making the application’s behavior more predictable and easier to understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Components of Flux Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: These are payloads of information that send data from the application to the Dispatcher.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dispatcher&lt;/strong&gt;: A central hub that manages all data flow in the application. It is essentially a registry of callbacks into the stores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;: This contains the application state and logic. They are somewhat similar to models in a traditional MVC pattern but manage the state of many objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View&lt;/strong&gt;: The final output of the application based on the current state of the Store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Flux, user interactions, server responses, and form submissions are all examples of Actions. The dispatcher processes these Actions and updates the Stores. The View retrieves the new state from the Stores and updates the UI accordingly. This unidirectional flow (Action -&amp;gt; Dispatcher -&amp;gt; Store -&amp;gt; View) is similar to MVU’s (Model-View-Update) data flow where the user input generates a message, the Model updates based on the message, and the View is a function of the Model.&lt;/p&gt;

&lt;p&gt;Redux builds upon the Flux architecture but simplifies it by enforcing a few rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Source of Truth&lt;/strong&gt;: The state of your whole application is stored in one object tree within a single store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State is read-only&lt;/strong&gt;: The only way to change the state is to emit an action, which is an object describing what happened.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changes are made with pure functions&lt;/strong&gt;: To specify how the state tree is transformed by actions, you write pure reducers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These rules help maintain consistency and predictability within the application, making it easier to track state changes and debug the application.&lt;/p&gt;

&lt;p&gt;Redux is closer to MVU than traditional MVC. Redux, like MVU, uses a unidirectional data flow where an Action (analogous to MVU’s “message”) triggers a change in the application’s state (Redux’s “single source of truth” is similar to MVU’s “Model”), and the View is updated based on this new state.&lt;/p&gt;

&lt;p&gt;While these approaches provide a structured way of developing UIs, they come with their own sets of challenges.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While none of these approaches is a magic wand, I have to clearly state that the philosophy behind these articles is based on the assumption — gained from the insight from years of experience — that the tight coupling of the view layer to the rest of the application is the root of all evils and, therefore, will be exploring the only approach that allows overcoming this — the MVU pattern.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF FLUX ==&lt;/span&gt;

&lt;span class="c1"&gt;// DISPATCHER&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dispatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_callbacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Dispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CID_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_lastID&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_callbacks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Dispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_callbacks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_callbacks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AppDispatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dispatcher&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// STORE&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ButtonStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;clickCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;clickCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;AppDispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;updateView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getCount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="c1"&gt;// ACTIONS&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ButtonActions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;AppDispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// VIEW&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterLabel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;counterLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ButtonStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ButtonActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&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;h3&gt;
  
  
  &lt;strong&gt;Elm MVU&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Elm is a much better solution for front-end development in terms of architectural design patterns, particularly for its ability to completely decouple the view as a pure function of state via its use of Model-View-Update (MVU) pattern.&lt;/p&gt;

&lt;p&gt;Unfortunately, even though it’s a great tool, it lives in a completely different world with a very peculiar language and isolated ecosystem, it exhibits an unattractive pattern of not being able to opt-in gradually (like with TypeScript), which makes it hard to jump on the bandwagon as it would vendor-lock you in.&lt;/p&gt;

&lt;p&gt;If Elm wasn’t a tightly coupled combination of an ML language, framework, and MVU pattern all baked into one, enforcing all-or-nothing choice, I would have been just exploring Elm.&lt;/p&gt;

&lt;p&gt;Because Elm is a really great technology, of course, there were attempts to introduce similar patterns that Elm relies on, like unidirectional data flow, and similar decoupling of IO, with Redux.&lt;/p&gt;

&lt;p&gt;Elm and Redux are similar in many ways, as both implement a functional programming style and a unidirectional data flow, but they have different approaches when it comes to connecting the view to the application’s state.&lt;/p&gt;

&lt;p&gt;In Elm, the pattern is Model-Update-View. The whole model is passed to the view function each time an update occurs, meaning the entire state of the app is available when rendering the view.&lt;/p&gt;

&lt;p&gt;Redux, on the other hand, is more flexible and less prescriptive about how you connect your state to your views. With Redux, you can use the connect function (when using React-Redux) to bind just the part of the state that the specific component needs, rather than the entire state.&lt;/p&gt;

&lt;p&gt;In Redux, however, this makes view tightly coupled to the rest of the loop, so you can’t swap the view easily, without disentangling it properly, which is very tricky and no fun. Another way both Redux and Elm tightly couple view and the rest of the loop is by dispatching actions from controls (UI elements) thus connecting to the logic.&lt;/p&gt;

&lt;p&gt;For example, if you have a button that is supposed to increment a value by one, you name an action “increment” and add that to the handler of a button.&lt;/p&gt;

&lt;p&gt;However, if later on you decide, to change the underlying logic to use “multiply”, you would have to go to the view and change it.&lt;/p&gt;

&lt;p&gt;But view shouldn’t really know about business logic, as well as business logic shouldn’t know about the view.&lt;/p&gt;

&lt;p&gt;Therefore, actions should be separated from the view layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- == EXAMPLE OF ELM MVU ==&lt;/span&gt;

&lt;span class="c1"&gt;-- Import necessary modules&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Browser&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Events&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Main function to start the application&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sandbox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- Define the Model (the state of our application)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;clickCount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- Initialize the model with a default state&lt;/span&gt;
&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- Define possible actions that can change the state&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Increment&lt;/span&gt;

&lt;span class="c1"&gt;-- The update function describes how to handle each action and update the state&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;Increment&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;-- The view function displays the state&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="kt"&gt;Increment&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Click Me!"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clicked: "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromInt&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; times"&lt;/span&gt;&lt;span class="p"&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;h3&gt;
  
  
  Model-View-Intent (MVI) with Cycle.js
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Frameworks: Cycle.js (JavaScript)&lt;/em&gt;&lt;br&gt;
Another great framework that I've learned recently about is Cycle.js&lt;/p&gt;

&lt;p&gt;Just like Elm, it also allows to completely decouple the view layer from the rest of the application.&lt;/p&gt;

&lt;p&gt;Cycle.js is a functional and reactive JavaScript framework for cleaner code. It introduces a variant of the MVU pattern called Model-View-Intent (MVI). In Cycle.js, each of these components has a unique and well-defined role:&lt;/p&gt;

&lt;p&gt;Intent: This handles all user inputs or events, such as button clicks and form submissions. The intention behind the user's interaction is processed and mapped into an object or "message" to be utilized by the Model.&lt;/p&gt;

&lt;p&gt;Model: The Model takes the "message" from the Intent and uses it to update the state of the application. This is done in a predictable, deterministic way, thus ensuring the consistency of state across the application.&lt;/p&gt;

&lt;p&gt;View: The View in Cycle.js is a pure function that transforms the application's state into a Virtual DOM tree to be displayed to the user. The advantage of using a Virtual DOM is that it only updates parts of the actual DOM that have changed, enhancing performance.&lt;/p&gt;

&lt;p&gt;Cycle.js and the MVI pattern offer a different approach to UI architecture. Rather than propagating actions throughout the application as in traditional MVC, Cycle.js enforces a unidirectional data flow and decouples the application's state from the UI. It also uses Observables to manage asynchronous data flow, further promoting the separation of concerns.&lt;/p&gt;

&lt;p&gt;It's very similar to MVU in Elm. So far this framework checks out best for the criteria that help to avoid legacy code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// == EXAMPLE OF MVI ==&lt;/span&gt;

&lt;span class="c1"&gt;// INTENT&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// MODEL&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;clickCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INCREMENT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;clickCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clickCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// VIEW&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterLabel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;counterLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Clicked: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize&lt;/span&gt;
&lt;span class="nx"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Design patterns
&lt;/h3&gt;

&lt;p&gt;Each known architectural approach has many prescribed design patterns. I will not go in-depth on them but will attempt to provide some resources at the end of the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems with testing
&lt;/h2&gt;

&lt;p&gt;In the previous articles, we mentioned that design patterns help to partially solve the problem of the tendency behind code becoming legacy, a much more important task is the quick correctness feedback in a black-box manner. MVU is going to prove quite helpful in ensuring that such black-box feedback is easy to obtain.&lt;/p&gt;

&lt;p&gt;React, as well as many other frameworks, have various solutions for testing, however, there are also very important shortcomings.&lt;/p&gt;

&lt;p&gt;For libraries that rely on running React under the hood, as RTL does, tests become integration tests.&lt;/p&gt;

&lt;p&gt;And since they are integration tests, the setup might become very complex. The setup for the RTL library itself is straightforward, but the procedure of mocking the dependencies can become unwieldy for larger projects.&lt;/p&gt;

&lt;p&gt;And since we mentioned that requirements will change often, the tests might also become obsolete, so we would need to be able to adapt quickly, which could be quite difficult when we have to be aware of many dependencies.&lt;/p&gt;

&lt;p&gt;In the context of the metaphor of a line with dots, our tests would be equivalent to locating the dots, and at some point, this process might get too complex and unwieldy making it a burden rather than the solution.&lt;/p&gt;

&lt;p&gt;Regarding Redux, even though it’s a library that (finally) allows you to have a unidirectional pure-function-like flow, I haven’t seen a single test written to test its behavior in real-world applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we do better?
&lt;/h2&gt;

&lt;p&gt;To improve the situation, we should separate business logic from view. This would allow us to test both (very complex) parts of applications separately, and be able to swap one part without touching the other.&lt;/p&gt;

&lt;p&gt;This approach would allow us to put the entire view in Storybook, where we would be able to see it in different states easily. Would also allow us to do visual snapshots that would help us with refactoring.&lt;/p&gt;

&lt;p&gt;Regarding the business logic, if it follows the unidirectional data flow and is separate from view and other IO, we could write pure-function black box tests that would let us easily check if everything is correct.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Very important to note, that once we have these black-box tests we can refactor our code, implementing the necessary design patterns that would allow us to keep our logic from becoming jumbled.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This would then allow us to refactor the underlying code accordingly and would allow us to do timely refactoring and introduction of necessary design patterns — one of the most important aspects of legacy-proof code.&lt;/p&gt;

&lt;p&gt;On top of that, we could then connect this business logic and the view in Storybook again to see how they interact.&lt;/p&gt;

&lt;p&gt;Overall, this approach would be highly storybook-friendly, which, in turn, means that the most important part about developing legacy-proof code would be out of the way — quick feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we mentioned earlier, in order for code to not become legacy there needs to be quick correct feedback and good patterns in place.&lt;/p&gt;

&lt;p&gt;Given these two conditions will exhibit the ability to be changed easily.&lt;/p&gt;

&lt;p&gt;I wanted to demonstrate that there exists an inherent problem with coupling in UI development that makes these conditions hard to achieve.&lt;/p&gt;

&lt;p&gt;This problem makes it difficult to adapt code as well as get quick feedback.&lt;/p&gt;

&lt;p&gt;Among the known architectural solutions, only the MVU pattern helps to provide a strong separation of view from the rest of the application, which is an important consideration and aligns best with the philosophy behind these articles.&lt;/p&gt;

&lt;p&gt;However, the current solutions relying on unidirectional flow still exhibit a high coupling of business logic and view, and this needs to be resolved if we want to be able to get quick feedback as well as adapt quickly.&lt;/p&gt;

&lt;p&gt;Over the course of the next articles, we will attempt to resolve this problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-4-react-as-a-decoupled-stateless-view-in-storybook-323o"&gt;Part 4 — React as a decoupled stateless view in Storybook:&lt;/a&gt; In this article, we will consider an example of what it means to have a stateless view separate from business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@ankit.sinhal/mvc-mvp-and-mvvm-design-pattern-6e169567bbad"&gt;Survey of Common Architectural Approaches:&lt;/a&gt; Useful article gives a brief overview of the major architectural approaches in UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful Links on Cycle.js and the Model-View-Intent Pattern&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cycle.js.org/"&gt;Cycle.js Official Website&lt;/a&gt;: This is the primary resource for all things related to Cycle.js. It offers detailed guides and API references.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@arranlomas/the-problem-with-mvp-a2c017e4e662"&gt;Problem with MVP&lt;/a&gt;: Article that explores shortcomings of MVP pattern&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://sourcemaking.com/design_patterns"&gt;Design patterns&lt;/a&gt; — A comprehensive guide to software design patterns. Each pattern is explained in detail with examples to help understand when and where to use them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/"&gt;SOLID Principles: Explanation and examples&lt;/a&gt; — This FreeCodeCamp post breaks down the SOLID principles in an easy-to-understand way with lots of examples.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://reactjs.org/docs/getting-started.html"&gt;React Documentation&lt;/a&gt;: The official React documentation is a must-visit resource for anyone working with React.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://redux.js.org/introduction/getting-started"&gt;Redux Documentation&lt;/a&gt;: The official Redux documentation provides a comprehensive guide to getting started with Redux, as well as more advanced topics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guide.elm-lang.org/"&gt;Elm Language Guide&lt;/a&gt;: This is the official guide to the Elm language, providing a detailed look at the language’s syntax and features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://react-redux.js.org/api/connect"&gt;React-Redux connect function Documentation&lt;/a&gt;: This part of the Redux documentation gives specific information about the ‘connect’ function, which is critical to understanding the connection between state and views in Redux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://testing-library.com/docs/react-testing-library/intro"&gt;Testing React Applications&lt;/a&gt;: The React Testing Library (RTL) documentation offers a guide on how to test React components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://storybook.js.org/docs/react/get-started/introduction"&gt;Storybook for React&lt;/a&gt;: Storybook is an open-source tool for developing UI components in isolation. This link leads to the specific documentation for using Storybook with React.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guide.elm-lang.org/architecture/"&gt;Model-View-Update (MVU) pattern&lt;/a&gt;: This page of the Elm guide explains the Model-View-Update (MVU) pattern, which is a key concept in the Elm language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://flaviocopes.com/react-unidirectional-data-flow/"&gt;Understanding Unidirectional Data Flow in React&lt;/a&gt;: This article explains the concept of unidirectional data flow in React and Redux.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nalexn.github.io/clean-architecture-swiftui/"&gt;Clean Architecture for SwiftUI&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://thomasbandt.com/model-view-update"&gt;Model-View-Update&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://iosexample.com/swift-implementation-of-the-elm-architecture-tea/"&gt;SwiftUI TEA&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>elm</category>
      <category>react</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Why is UI development legacy prone?</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:00:57 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-2-why-is-ui-development-legacy-prone-4ho8</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-2-why-is-ui-development-legacy-prone-4ho8</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Why is UI development legacy prone?&lt;/p&gt;

&lt;p&gt;Using the line metaphor from the &lt;a href="https://kirill-novik.medium.com/part-1-why-does-code-becomes-legacy-b2acbe702c2e"&gt;previous article&lt;/a&gt;, we arrived at a definition of what legacy code is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Legacy code — code that is very hard to change without everything going down in flames and that is as costly to refactor as rewrite it from scratch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This code happens when we have complex and ever-changing constraints and requirements when the correctness feedback loop is delayed, as well as when the codebase grows increasingly large.&lt;/p&gt;

&lt;p&gt;And this sounds a lot like what UI development (in general) is. And web UI development is no different. There is probably no other field where requirements change as often as in areas related to UI.&lt;/p&gt;

&lt;p&gt;Disclaimer: All of the below examples are contrived, simplified, and only needed for illustration purposes — any semblance to real people is coincidental.&lt;/p&gt;

&lt;h2&gt;
  
  
  From inception to legacy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Greenfield one-man-gig project
&lt;/h3&gt;

&lt;p&gt;There exist lucky people who start working on a project from scratch. This is the happiest place to be if you are a developer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sOBTYrpW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AfD8akOWJzTTTdK1xoJiidg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sOBTYrpW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AfD8akOWJzTTTdK1xoJiidg.png" alt="Greenfield project" width="524" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you receive the requirements, the idea behind what needs to be built is generally straightforward, the backlog is fresh and well organized, and designs are in, for the most part.&lt;/p&gt;

&lt;p&gt;You begin working on it, setting up the project, hustling a bit with configurations initially, but once you figure that step out, the game is on, and you start building.&lt;/p&gt;

&lt;p&gt;As you build your first components, you see quick progress, you don’t need tests, as you are able to navigate the entire application in a couple of clicks. You can see your UI with the help of your dev server or some sandbox environment. Your priority is to fulfill the requirements over making the code last.&lt;/p&gt;

&lt;p&gt;With some setbacks (we are living in the real world), you manage to get everything delivered on time and everyone is pretty happy.&lt;/p&gt;

&lt;p&gt;The end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Brownfield project
&lt;/h3&gt;

&lt;p&gt;It’s much more likely you are going to be in a different situation and be working on somebody else’s greenfield project and not by yourself anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--znskOz_m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aw0yJlXqYi3kPzgpcn399Hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--znskOz_m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Aw0yJlXqYi3kPzgpcn399Hw.png" alt="Brownfield project" width="524" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will be much more difficult to understand the thought process of the person who built the application.&lt;/p&gt;

&lt;p&gt;The last person most likely didn’t pay much attention to anything other than the requirements, so little (if any) testing, tightly coupled, and convoluted logic due to cutting corners during development.&lt;/p&gt;

&lt;p&gt;As you now receive requirements, it will be mostly guesswork for you how long something will take to make it work.&lt;/p&gt;

&lt;p&gt;As you start working on it, you are mostly debugging through code.&lt;/p&gt;

&lt;p&gt;You can no longer click through the UI and know where everything is located.&lt;/p&gt;

&lt;p&gt;As you develop, you try to avoid modifying the original logic as much as possible. Layer by layer, you tightly couple one feature on top of the other, as you try to understand the original code and get work done by the end of a sprint.&lt;/p&gt;

&lt;p&gt;Most likely, you won’t be able to test things properly, as you are already overwhelmed and struggling with requirements and debugging.&lt;/p&gt;

&lt;p&gt;Yet, if you are lucky, you start writing tests for your code, however, you probably make them white-box tests, meaning they are tied to implementation as opposed to testing overall logic with inputs and outputs, which would be part of the problem later on.&lt;/p&gt;

&lt;p&gt;Layer by layer, the codebase becomes what’s known as legacy code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Legacy project
&lt;/h3&gt;

&lt;p&gt;It’s most likely, however, that you will be working on a legacy project as a developer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F6XF6JP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AN1rIV5Q2D8wuxY2ufo8efg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F6XF6JP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AN1rIV5Q2D8wuxY2ufo8efg.png" alt="Legacy project" width="524" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, there is almost no hope for refactoring the legacy part.&lt;/p&gt;

&lt;p&gt;The feedback loop for most of the applications is going to be delayed.&lt;/p&gt;

&lt;p&gt;The process of covering the application with tests will always be lagging behind and draining motivation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;UI development is legacy prone because quick feedback and effective design patterns allowing for modularity aren’t built into the project during the stage when it’s still a green-field project.&lt;/p&gt;

&lt;p&gt;However, the purpose of this article series is not to paint a bleak picture but to explore and propose solutions. While it is true that many of our lines of code may not stand the test of time, it is not an inescapable fate. By understanding the root causes and learning from the experiences of countless developers before us, we can anticipate and mitigate these issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-3-how-to-make-uis-testable-and-easy-to-change-65"&gt;Part 3 — How to make UIs testable and easy to change?:&lt;/a&gt; A concise survey of known approaches to UI in the context of the problem outlined in the previous articles and where they fall short as well as proposing a new solution&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;p&gt;To delve deeper into the topics discussed in this article, consider visiting the following resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://understandlegacycode.com/"&gt;Understanding Legacy Code:&lt;/a&gt;&lt;/strong&gt; This website is a rich resource for understanding legacy code and strategies to effectively deal with it. You’ll find a wealth of information that can help you navigate and improve legacy systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.linkedin.com/pulse/greenfield-vs-brownfield-giorgi-bastos"&gt;Greenfield vs Brownfield:&lt;/a&gt;&lt;/strong&gt; In this LinkedIn article by Giorgi Bastos, the concepts of greenfield and brownfield projects are explored in detail. Giorgi provides great insight into the differences, advantages, and challenges of both approaches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://synoptek.com/insights/it-blogs/greenfield-vs-brownfield-software-development/"&gt;Greenfield vs Brownfield in Software Development:&lt;/a&gt;&lt;/strong&gt; Synoptek provides a detailed comparison between greenfield and brownfield software development, further enhancing the understanding of these concepts and their implications in UI development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.javatpoint.com/advantages-and-disadvantages-of-white-box-testing"&gt;Advantages and Disadvantages of White Box Testing&lt;/a&gt;:&lt;/strong&gt; This page on JavaTpoint gives a balanced view of white box testing, discussing its advantages and limitations in detail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.seguetech.com/white-box-testing-pros-cons/"&gt;White Box Testing: Pros and Cons:&lt;/a&gt;&lt;/strong&gt; Segue Technologies provides another perspective on white box testing, detailing its pros and cons. This article helps you understand why white box testing can be part of the problem in maintaining UI code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>ui</category>
      <category>designpatterns</category>
      <category>testing</category>
    </item>
    <item>
      <title>Why does code become legacy?</title>
      <dc:creator>Kirill Novik</dc:creator>
      <pubDate>Sat, 15 Jul 2023 14:00:02 +0000</pubDate>
      <link>https://dev.to/kino6052/legacy-proof-ui-part-1-why-does-code-become-legacy-1pm2</link>
      <guid>https://dev.to/kino6052/legacy-proof-ui-part-1-why-does-code-become-legacy-1pm2</guid>
      <description>&lt;h2&gt;
  
  
  Metaphor
&lt;/h2&gt;

&lt;p&gt;Why does code become legacy?&lt;/p&gt;

&lt;p&gt;Writing code is like connecting two points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BSi2VYjS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AOIXITcotV6QFkokPup9LfA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BSi2VYjS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AOIXITcotV6QFkokPup9LfA.png" alt="Writing code is like connecting two points" width="454" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Naturally, you would like to take the most straightforward path — a straight line, from A to B. This works for a lot of simple cases, but for the majority of real-world scenarios, you just can’t, because aside from connecting the points, you will have to move around the obstacles.&lt;/p&gt;

&lt;p&gt;But, aside from the need to maneuver a little bit, there is no problem.&lt;/p&gt;

&lt;p&gt;Let’s increase the number of obstacles in the path by an order of magnitude. The line just keeps on becoming more convoluted.&lt;/p&gt;

&lt;p&gt;Now let’s make these obstacles move (which, I, unfortunately, have no animation for), albeit pretty slowly, but enough to cause us trouble of needing to reconnect the points. This isn’t the nice straight-line scenario at all anymore. This is getting serious!&lt;/p&gt;

&lt;p&gt;Well, as if that wasn’t enough, how about we now make the points move around as well? And not only that, but will make sure that these points aren’t glued to the lines, and you have to follow them to make sure they stay connected. Well, that’s even more annoying!&lt;/p&gt;

&lt;p&gt;But this isn’t everything! What if we only knew the approximate location of the points, and the only way we could tell is by being able to request their location every 5 minutes? How crazy would that be?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oYHeohgh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ArMH7R19qErs6KNq6lGlSVg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oYHeohgh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ArMH7R19qErs6KNq6lGlSVg.png" alt="What if we only knew the approximate location of points?" width="624" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And yet this is pretty much what real-world development is often like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion
&lt;/h2&gt;

&lt;p&gt;In the context of this metaphor, the points are the functional requirements of what the software should do. It’s great when we know exactly whether our code connects to them properly. However, in reality, these requirements change (hence moving points), and we have to update our code accordingly. Yet, it’s not always easy to tell whether we connected the points correctly, and only through rigorous testing could that be determined.&lt;/p&gt;

&lt;p&gt;The obstacles could be limitations in technology, performance, programming paradigms, various process, and everything else that could stand in our way — and there is always something — to which we, as problem solvers, are quite accustomed.&lt;/p&gt;

&lt;p&gt;Naturally, given this dynamic setup, the code that started out with the best intents and practices possible turns into an ugly squiggle that bears testament to the tortures a developer had to go through to make it work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This type of code is known as legacy — code that is very hard to change without everything going down in flames and that is as costly to refactor as rewrite it from scratch.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like jumbled yarn, legacy code usually exhibits high coupling between pieces of logic, that similar to yarn you wouldn’t be able to disentangle easily.&lt;/p&gt;

&lt;p&gt;This begs the question of whether there is something that we could do to avoid our code becoming legacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to solve this problem?
&lt;/h3&gt;

&lt;p&gt;Well, this problem is solved partially by the use of so-called design patterns — bite-sized solutions that we could assemble together like Lego blocks to make the process faster and more controlled.&lt;/p&gt;

&lt;p&gt;But design patterns are not enough. It’s much more important to know that we’re going in the correct direction as soon as possible than going in the wrong direction “correctly”. And yes, there is a bunch of legacy code that follows great design patterns. In fact, the overuse of design patterns beyond necessary is called “over-engineering.”&lt;/p&gt;

&lt;p&gt;We should know where the points are located as soon as possible and to do that, we need some automated, instantaneous way of getting this feedback. That’s what testing your code accomplishes. Not every test would do, but black box tests specifically check the points and not some parts along the path.&lt;/p&gt;

&lt;p&gt;So, in order to solve the problem of constantly changing position of the points and the obstacles we need to meet two conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To know that we are going in the right direction ASAP (correctness feedback in the form of black box tests)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use some preconceived solutions to build the path faster and in a more controlled manner (design patterns)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pKaQQJd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AsIYwgh1M2rsybhG48qYsQA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pKaQQJd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AsIYwgh1M2rsybhG48qYsQA.png" alt="Code with correctness feedback and design patterns in place" width="444" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As simple as these two objectives sound, they are pretty difficult to achieve within the context of UI development, and yet this is what we will try to solve over the course of these articles.&lt;/p&gt;

&lt;p&gt;However, in these articles, most focus will be placed on the first aspect (the immediate feedback) requirement as this aspect proved to be the most painful, whereas the design patterns are relatively well studied and known, thus would only be mentioned as a brief survey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kino6052/legacy-proof-ui-part-2-why-is-ui-development-legacy-prone-4ho8"&gt;Part 2 — Why is UI development legacy-prone?:&lt;/a&gt; Another illustration that builds on top of the previous one, further clarifying the problem&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.guru99.com/black-box-testing.html"&gt;Black Box Testing: An In-Depth Tutorial&lt;/a&gt; — This tutorial on Guru99 provides a comprehensive guide on black-box testing. It covers its techniques, types, methods, advantages, and disadvantages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://sourcemaking.com/design_patterns"&gt;Design patterns&lt;/a&gt; — A comprehensive guide to software design patterns. Each pattern is explained in detail with examples to help understand when and where to use them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/"&gt;SOLID Principles: Explanation and examples&lt;/a&gt; — This FreeCodeCamp post breaks down the SOLID principles in an easy-to-understand way with lots of examples.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>ui</category>
      <category>legacycode</category>
      <category>designpatterns</category>
    </item>
  </channel>
</rss>
