<?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: Alberto Talone</title>
    <description>The latest articles on DEV Community by Alberto Talone (@bebetos92).</description>
    <link>https://dev.to/bebetos92</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%2F79410%2Fb84a7b7f-dcc4-422a-9e29-6a6291667b36.jpg</url>
      <title>DEV Community: Alberto Talone</title>
      <link>https://dev.to/bebetos92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bebetos92"/>
    <language>en</language>
    <item>
      <title>The Devil’s Clean Code: Lessons from Migrating a 20-Year-Old Legacy Project</title>
      <dc:creator>Alberto Talone</dc:creator>
      <pubDate>Mon, 19 Jan 2026 17:41:31 +0000</pubDate>
      <link>https://dev.to/bebetos92/the-devils-clean-code-lessons-from-migrating-a-20-year-old-legacy-project-2nhh</link>
      <guid>https://dev.to/bebetos92/the-devils-clean-code-lessons-from-migrating-a-20-year-old-legacy-project-2nhh</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write tests.&lt;/strong&gt; You don't truly realize how messy code is until you try to write a unit test for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand your annotations.&lt;/strong&gt; Don’t use &lt;code&gt;@Data&lt;/code&gt; when &lt;code&gt;@Getter&lt;/code&gt; and &lt;code&gt;@Setter&lt;/code&gt; are all you need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't fear the refactor.&lt;/strong&gt; If you have the chance to rewrite and simplify, take it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Ghost of Architecture Past
&lt;/h2&gt;

&lt;p&gt;In 2025, I took on a daunting challenge: migrating a 20-year-old JSP project into a modern microservice architecture.&lt;/p&gt;

&lt;p&gt;To understand the business logic, I had to dive deep into ancient JSP files, trying to decipher what a developer two decades ago was trying to achieve. The client’s initial request sounded simple but proved to be a nightmare: &lt;em&gt;"Copy the models into the new project and transform the beans into services."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The reality was a mess. I found hundreds of model classes scattered across dozens of domain packages. Every package contained at least one "utility" class bloated with static methods for manipulating DAOs and DTOs. The inheritance trees were like Matryoshka dolls—classes extending classes, extending other classes, until the original purpose was lost.&lt;/p&gt;

&lt;p&gt;Under pressure to move fast, we made a classic mistake: we copy-pasted the old structures into the new service. We thought converting stateful variables into stateless method parameters would be enough. We were wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Confronting the "Bugfest"
&lt;/h2&gt;

&lt;p&gt;Once the code lived in its new "modern" home, we ran it through &lt;strong&gt;SonarQube&lt;/strong&gt;. It was a disaster.&lt;/p&gt;

&lt;p&gt;The report was a "bugfest" of epic proportions: SQL injection vulnerabilities, non-standard naming conventions, and massive blocks of duplicated code. My daily routine became a cycle of frustration: cursing the original developers, questioning my career choices, and ultimately, rolling up my sleeves to clean the mess.&lt;/p&gt;

&lt;p&gt;By the end of the cleanup phase, I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deleted nearly 2,000 unused classes.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eliminated 30% of duplicated code.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed hundreds of bugs&lt;/strong&gt; and suppressed legacy warnings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "microservice" was finally starting to look like one, sitting at 900 classes and 55,000 lines of code. It was time for the final boss: &lt;strong&gt;80% test coverage.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Writing Tests for the "Devil's Clean Code"
&lt;/h2&gt;

&lt;p&gt;Writing tests for legacy code you didn't author is a unique kind of challenge. I leaned heavily on AI assistants to generate test scaffolding, which significantly sped up the process. However, as I looked at the logic I was testing, I realized I was reading the "Devil’s version" of &lt;em&gt;Clean Code&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I encountered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Indentation Hell:&lt;/strong&gt; Methods with 8 to 10 levels of nested &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt; loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition Fatigue:&lt;/strong&gt; &lt;code&gt;if&lt;/code&gt; statements with 10~15 different logic gates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead Wood:&lt;/strong&gt; Massive amounts of unreachable code and unused variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Testing forced me to confront these issues. If a branch is impossible to reach in a test, it shouldn't exist in the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned (The Hard Way)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Tests are a Diagnostic Tool
&lt;/h3&gt;

&lt;p&gt;Tests are the best way to understand someone else's code. They reveal exactly where the "spaghetti" is. If a method is too hard to test, it’s a signal that the code needs to be rewritten, not just patched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE: The "Pyramid of Doom" (Deeply nested logic)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processLegacyRuo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RuoDir&lt;/span&gt; &lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTPRuo&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuoArr&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RuoItem&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuoArr&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGG&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Business logic buried 5 levels deep&lt;/span&gt;
                        &lt;span class="n"&gt;performOperation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER: Flattened logic using Guard Clauses and Streams&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processRuo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RuoDir&lt;/span&gt; &lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Exit early if the object is invalid or not in the right state&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="s"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTPRuo&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Handle null collections gracefully&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuoArr&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Use Functional Programming to handle the collection&lt;/span&gt;
    &lt;span class="n"&gt;ruoDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuoArr&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGG&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performOperation&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. The Lombok Trap
&lt;/h3&gt;

&lt;p&gt;One of my biggest "Aha!" moments involved &lt;strong&gt;Lombok&lt;/strong&gt;. We initially used &lt;code&gt;@Data&lt;/code&gt; on all our models to save time. However, we realized our branch coverage was suffering. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Because &lt;code&gt;@Data&lt;/code&gt; automatically generates &lt;code&gt;@EqualsAndHashCode&lt;/code&gt; and &lt;code&gt;@ToString&lt;/code&gt;. These methods create many hidden logical branches that need to be tested to reach high coverage percentages. By switching to specific &lt;code&gt;@Getter&lt;/code&gt; and &lt;code&gt;@Setter&lt;/code&gt; annotations, we removed unnecessary complexity and made our coverage targets achievable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE: @Data generates equals, hashCode, and toString, adding hidden branches&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER: Explicit annotations only for what we actually use&lt;/span&gt;
&lt;span class="nd"&gt;@Getter&lt;/span&gt;
&lt;span class="nd"&gt;@Setter&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Don't Fear the Rewrite
&lt;/h3&gt;

&lt;p&gt;Legacy code can be intimidating, but you shouldn't be afraid to change it. If you understand the intent of the code, rewrite it for clarity. Your future self (and your team) will thank you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE: A maintenance nightmare with 20+ conditions&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDtVersAA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDtVersAA&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDtVersMM&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDtVersMM&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... imagine 15 more lines of this ...&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCodFisc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCodFisc&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Do something if everything is empty&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER: Using Method References and Streams for clarity&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fieldsToCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;input:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getDtVersAA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;    &lt;span class="nl"&gt;input:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getDtVersMM&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
        &lt;span class="c1"&gt;// ... add all 15 more lines ...&lt;/span&gt;
        &lt;span class="nl"&gt;input:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getCodFisc&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// We use a helper method (checkCampoVuoto) and allMatch to verify the state&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;allFieldsEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fieldsToCheck&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldGetter&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;checkCampoVuoto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldGetter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allFieldsEmpty&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Logic is now readable and easy to extend&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Migrating legacy systems isn't just about moving code from one place to another; it's about translating old ideas into modern standards. It’s a messy, frustrating, but ultimately rewarding process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s the worst legacy code you’ve ever had to migrate? Let’s swap horror stories in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Microfrontend Architecture: Breaking Down Monolith Frontends</title>
      <dc:creator>Alberto Talone</dc:creator>
      <pubDate>Tue, 11 Feb 2025 22:57:33 +0000</pubDate>
      <link>https://dev.to/bebetos92/microfrontend-architecture-breaking-down-monolith-frontends-omb</link>
      <guid>https://dev.to/bebetos92/microfrontend-architecture-breaking-down-monolith-frontends-omb</guid>
      <description>&lt;p&gt;A microfrontend is an architectural style for frontend development where a web application is divided into smaller, independent modules or features. Each module can be developed, deployed, and maintained autonomously, much like the concept of microservices in backend architecture.&lt;/p&gt;

&lt;p&gt;In a traditional monolithic frontend, all parts of the application (like the navigation bar, product listing, checkout page, etc.) are together. This makes the system tightly coupled, which can lead to challenges as the application grows. &lt;br&gt;
Using microfrontends, you can treat each part of the application as a standalone piece, that can be managed independently.&lt;/p&gt;

&lt;p&gt;Keep in mind that this architecture is not a &lt;strong&gt;silver bullet&lt;/strong&gt;...so let's dive into a simple analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Principles of Microfrontends
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Independence&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each microfrontend is a self-contained unit that operates independently from the others. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams can develop and deploy their microfrontend without waiting for changes in other parts of the application.&lt;/li&gt;
&lt;li&gt;Each microfrontend has its own &lt;strong&gt;build, deployment, and runtime process&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If one microfrontend fails, the rest of the application remains unaffected, improving resilience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in an e-commerce application, the &lt;strong&gt;checkout module&lt;/strong&gt; can be deployed separately from the &lt;strong&gt;product listing page&lt;/strong&gt; without disrupting the overall user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Technology Agnosticism&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends allow different parts of the application to be built using different technologies. This flexibility provides several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams can select the best tool for their specific needs, such as &lt;strong&gt;React for product catalogs&lt;/strong&gt;, &lt;strong&gt;Vue for shopping carts&lt;/strong&gt;, or &lt;strong&gt;Angular for checkout pages&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Organizations can gradually migrate from older technologies (e.g., from AngularJS to React) without a complete rewrite.&lt;/li&gt;
&lt;li&gt;It enables &lt;strong&gt;incremental upgrades&lt;/strong&gt;, allowing different teams to evolve their stacks independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, technology diversity should be managed carefully to avoid excessive complexity in the integration process.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Isolated Codebases&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each microfrontend has its own &lt;strong&gt;repository, build process, and deployment pipeline&lt;/strong&gt;. This separation leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lower interdependencies:&lt;/strong&gt; A change in one module does not require modifying others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster development cycles:&lt;/strong&gt; Teams can work in parallel without conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier debugging and maintenance:&lt;/strong&gt; Since each module has its own lifecycle, it is easier to identify and fix issues in isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if the &lt;strong&gt;user profile module&lt;/strong&gt; has a bug, developers can debug and patch it without affecting the &lt;strong&gt;navigation bar or search module&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Team Ownership&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In a microfrontend architecture, different teams own and manage specific microfrontends. This decentralized approach offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous development:&lt;/strong&gt; Teams can work independently with full control over their features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain-driven design (DDD):&lt;/strong&gt; Each team focuses on a &lt;strong&gt;business domain&lt;/strong&gt; (e.g., payments, search, or authentication).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved collaboration:&lt;/strong&gt; Since teams have clear ownership, they can align better with business goals and user needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a &lt;strong&gt;dedicated team for checkout&lt;/strong&gt; ensures that the payment process is always optimized for performance and security without affecting the rest of the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Seamless Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Even though microfrontends are built independently, they must integrate smoothly to create a &lt;strong&gt;unified user experience&lt;/strong&gt;. This requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent design:&lt;/strong&gt; UI components and styles should match across different microfrontends (e.g., using a shared design system).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State management strategies:&lt;/strong&gt; Communication between microfrontends should be handled carefully to ensure data consistency (e.g., using events, APIs, or shared state managers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing and navigation:&lt;/strong&gt; Users should not notice any difference when transitioning between microfrontends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, when switching from the &lt;strong&gt;homepage&lt;/strong&gt; to the &lt;strong&gt;cart module&lt;/strong&gt;, the user experience should feel seamless, as if it's a single-page application rather than multiple independent apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of Microfrontends
&lt;/h2&gt;

&lt;p&gt;Microfrontend architecture offers several advantages over traditional monolithic frontend applications. By breaking down a large frontend into smaller, independently managed pieces, organizations can improve scalability, flexibility, and overall development efficiency. Below are some of the key benefits:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Scalability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends enable teams to scale both their development processes and infrastructure efficiently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Independent Team Development:&lt;/strong&gt; Different teams can work on separate microfrontends without interfering with each other. This allows for parallel development and faster feature releases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Distribution:&lt;/strong&gt; Since each microfrontend can be deployed separately, resources can be allocated dynamically based on demand, optimizing performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular Growth:&lt;/strong&gt; As the application expands, new microfrontends can be added without significantly impacting existing functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in an e-commerce application, the search functionality can scale independently from the checkout system, ensuring a smooth user experience even during high traffic periods.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Faster Deployments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With microfrontends, teams can deploy updates and new features more frequently without affecting the entire application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smaller Codebases:&lt;/strong&gt; Each microfrontend has a smaller, more manageable codebase, reducing build times and deployment complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent Deployment Pipelines:&lt;/strong&gt; Teams can deploy changes to their specific microfrontend without waiting for other teams to finish their work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Downtime:&lt;/strong&gt; Since deployments are smaller and isolated, the risk of breaking the entire application is significantly reduced.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a company can push an update to the product recommendation section without requiring a full application redeployment, allowing for rapid experimentation and A/B testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Flexibility in Technology Choices&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends allow teams to choose the best technology for their specific use case, rather than being locked into a single framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technology-Agnostic Approach:&lt;/strong&gt; Each microfrontend can be built using different frameworks or libraries (e.g., React for one module, Vue for another).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Migrations:&lt;/strong&gt; Organizations can migrate legacy applications gradually by introducing new microfrontends while still maintaining the old ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freedom for Innovation:&lt;/strong&gt; Different teams can experiment with new technologies without disrupting the rest of the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a company using Angular for its existing frontend can introduce a new dashboard built with React without needing to rewrite the entire application.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Resilience and Fault Isolation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of the major advantages of microfrontends is that failures in one module do not necessarily impact the entire application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved Fault Tolerance:&lt;/strong&gt; If one microfrontend crashes or experiences a bug, the rest of the application remains functional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Decomposition:&lt;/strong&gt; Each microfrontend can operate independently, reducing the risk of widespread failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful Degradation:&lt;/strong&gt; If a microfrontend fails, fallback mechanisms (e.g., loading a static version) can be used to maintain usability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if the shopping cart microfrontend encounters an error, the user can still browse products and use other features without being blocked.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Improved Developer Productivity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends promote team autonomy and improve the efficiency of the development lifecycle.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decentralized Ownership:&lt;/strong&gt; Each team owns its microfrontend, enabling them to focus on delivering high-quality features without dependencies on other teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Onboarding:&lt;/strong&gt; New developers can quickly ramp up by working on a single microfrontend instead of navigating a massive monolithic codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Code Boundaries:&lt;/strong&gt; Smaller, well-defined codebases are easier to maintain and refactor over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a newly hired developer can start contributing to the "user profile" microfrontend without needing to understand the entire application.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Better Maintainability and Code Reusability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends help in keeping the codebase maintainable and encourage reusability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smaller, More Manageable Codebases:&lt;/strong&gt; Since each microfrontend focuses on a specific domain, it is easier to debug, refactor, and enhance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Upgrades:&lt;/strong&gt; If a new feature or optimization is needed, only the affected microfrontend needs modification, reducing the overall risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a company using a shared component library can update the navigation bar across all microfrontends without rewriting each module separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;strong&gt;Enhanced User Experience Through Independent Improvements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With microfrontends, teams can improve individual features without waiting for large-scale application updates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Feature Releases:&lt;/strong&gt; Teams can introduce new UI/UX improvements in one microfrontend without requiring updates to the entire application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Localized Performance Optimization:&lt;/strong&gt; Performance bottlenecks in one microfrontend can be addressed independently, improving overall responsiveness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradual Feature Rollouts:&lt;/strong&gt; New features can be released to specific user segments for testing before a full rollout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a company can launch a redesigned checkout flow as an experimental microfrontend for a small percentage of users before making it the default experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Drawbacks of Microfrontend Architecture
&lt;/h2&gt;

&lt;p&gt;While microfrontend architecture offers numerous advantages, it also comes with challenges that developers and organizations must consider before adopting it. Below are some of the key drawbacks:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Increased Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontends introduce additional complexity in multiple areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Codebases:&lt;/strong&gt; Instead of a single frontend, you now have multiple repositories and projects to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Overhead:&lt;/strong&gt; Combining different microfrontends into a seamless application requires extra effort in routing, communication, and shared state management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build &amp;amp; Deployment Challenges:&lt;/strong&gt; Coordinating multiple independent deployments can be tricky, requiring careful versioning and testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, ensuring that microfrontends work correctly together when deployed separately can lead to integration headaches, requiring sophisticated CI/CD pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Performance Overhead&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since microfrontends are often loaded dynamically at runtime, they can introduce performance issues such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increased Bundle Size:&lt;/strong&gt; Loading multiple microfrontends means downloading multiple JavaScript bundles, potentially leading to slower page loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher Network Requests:&lt;/strong&gt; Each microfrontend might have its own dependencies, increasing HTTP requests and affecting performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Conflicts &amp;amp; Style Loading:&lt;/strong&gt; Ensuring that different microfrontends share consistent styles without conflicts can be challenging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a microfrontend loads React, but the host application already includes React, it might lead to unnecessary duplication, increasing load time.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;State Management Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since each microfrontend operates independently, &lt;strong&gt;sharing global state&lt;/strong&gt; between them can be difficult:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duplication of Data:&lt;/strong&gt; Each microfrontend might fetch the same data separately, leading to inefficiencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent User Experience:&lt;/strong&gt; If state synchronization is not handled properly, users might experience issues like cart data not updating across microfrontends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication Overhead:&lt;/strong&gt; Using APIs, event buses, or shared stores (e.g., Redux, Zustand) can add additional layers of complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example a logged user in one microfrontend, has to be logged in the others. So microfrontends need to be aware of the authentication state, requiring inter-module communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Difficult Debugging &amp;amp; Testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With microfrontends, debugging and testing become more complex because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Logs &amp;amp; Errors:&lt;/strong&gt; Since each microfrontend is independent, tracing errors across multiple modules can be challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Testing Pipelines:&lt;/strong&gt; Each microfrontend needs its own testing strategy, leading to increased testing effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Module Integration Testing:&lt;/strong&gt; Ensuring that all microfrontends work well together requires additional end-to-end (E2E) tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, an error in one microfrontend might not appear in isolation but only when integrated with others, making debugging more difficult.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Technology Fragmentation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Although microfrontends allow teams to use different frameworks and technologies, this can also become a disadvantage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent User Experience:&lt;/strong&gt; Different UI frameworks may result in slight variations in styles and interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Larger Bundle Sizes:&lt;/strong&gt; If different microfrontends use different versions of the same library, it increases the overall application size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Learning Curve:&lt;/strong&gt; Teams working on different stacks may struggle to collaborate effectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if microfrontends are built with different technologies (one with Vue, another with React)  maintaining a uniform UI and behavior can become a challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Security Risks&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Microfrontend architectures introduce additional security concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Origin Issues:&lt;/strong&gt; If microfrontends are served from different domains, CORS (Cross-Origin Resource Sharing) policies need to be carefully managed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Leaks:&lt;/strong&gt; Since multiple microfrontends interact with shared resources, they may accidentally expose sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication &amp;amp; Authorization:&lt;/strong&gt; Implementing a consistent authentication mechanism across multiple microfrontends requires careful planning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if authentication is handled differently in each microfrontend, users might experience inconsistent login behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;strong&gt;Higher Maintenance Effort&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Maintaining a microfrontend-based system requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More Infrastructure Management:&lt;/strong&gt; More services mean more DevOps work for deployments, monitoring, and logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Management:&lt;/strong&gt; Ensuring that all microfrontends stay up-to-date without breaking compatibility can be challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Coordination Between Teams:&lt;/strong&gt; Although teams work independently, they still need to align on integration points and shared resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a shared UI component library is updated, all microfrontends depending on it might need updates, leading to coordination challenges.&lt;/p&gt;




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

&lt;p&gt;While microfrontend architecture provides scalability, flexibility, and independent deployments, it also introduces challenges such as complexity, performance overhead, and debugging difficulties. An architect must carefully weigh the pros and cons before adopting this approach, ensuring that the benefits outweigh the added effort and technical debt.&lt;/p&gt;

&lt;p&gt;In essence, microfrontends empower organizations to build large-scale applications with greater flexibility and efficiency, overcoming many of the limitations of traditional monolithic frontends.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Shopping List: my way to learn stuff</title>
      <dc:creator>Alberto Talone</dc:creator>
      <pubDate>Sat, 14 Nov 2020 21:20:25 +0000</pubDate>
      <link>https://dev.to/bebetos92/shopping-list-my-way-to-learn-stuff-17hc</link>
      <guid>https://dev.to/bebetos92/shopping-list-my-way-to-learn-stuff-17hc</guid>
      <description>&lt;h1&gt;
  
  
  Shopping list
&lt;/h1&gt;

&lt;p&gt;Hi devs, I want to show you a simple app I have create for playing with Ionic 5 and Java Spring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let me introduce you to &lt;strong&gt;Shopping List&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Shopping List is a simple app for manage my stuff to buy from grocery to clothes and other stuff when I go out.&lt;/p&gt;

&lt;p&gt;But why create your own app when there are plenty of them? Just for learn some stuff, get my hands dirty and stress a bit my Raspberry :D&lt;/p&gt;

&lt;p&gt;Let's take a look to a few key elements for the app and the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  APP
&lt;/h2&gt;

&lt;p&gt;The app is created with Ionic 5 and Angular 10.&lt;/p&gt;

&lt;p&gt;The idea, behind this project, was to write some clean code and play a bit with RxJS operators, interceptors and guards.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
The HTTP interceptor is necessary because I have to inject the OAUTH2 Token for all the request to the server.&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="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nx"&gt;currentUser&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;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUserValue&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;currentUser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&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;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&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="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;token&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="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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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="s1"&gt;application/json&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="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accept&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="s1"&gt;application/json&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&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="c1"&gt;// TODO: Add 401 Handler&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;throwError&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="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;&lt;br&gt;&lt;br&gt;
I used the RxJS operators for manipulate all the Observables used for calling the server.&lt;/p&gt;

&lt;p&gt;I really used and loved a lot the &lt;em&gt;catchError&lt;/em&gt; for handling server error response and throw them were I have subscribed to this observables.&lt;/p&gt;

&lt;p&gt;Here is an example about an Observable I have created for retrieve the full list of shops.&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="nf"&gt;getShops&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IShopsResponse&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IShopsResponse&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getAll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;
      &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&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;let&lt;/span&gt; &lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IShopsResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&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;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&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;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;throwError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is where I subscribe to the Observable and how I manage the error, and what to show to the user.&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="nf"&gt;getAllShops&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;shopService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getShops&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IShopsResponse&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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="nx"&gt;error&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;let&lt;/span&gt; &lt;span class="nx"&gt;title&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;langService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ALERT.error&lt;/span&gt;&lt;span class="dl"&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;msg&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;langService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR.retrieve_list&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;alertService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showAlert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alertBox&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;alertBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present&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="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;Remember to take a look, if you haven't at &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators"&gt;RxJS documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SERVER
&lt;/h2&gt;

&lt;p&gt;The server is created using Spring Boot framework.&lt;/p&gt;

&lt;p&gt;The basic idea was to create a simple server with a basic authentication for the REST using OAuth2 following this &lt;a href="https://www.devglan.com/spring-security/spring-boot-security-oauth2-example"&gt;tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After following this tutorial I decided to take a look at Spring Boot potentials and I find out the possibility of retrieve user informations without doing a ping-pong with ids and other private informations using &lt;em&gt;SecurityContextHolder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here is a snipping of the function for the current user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;getCurrentUser&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
  &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecurityContextHolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContext&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAuthentication&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;AnonymousAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;optUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another element that I decide to add was a logger for request and response, a very usefull way to analyze future server errors.&lt;br&gt;
For achieve this I had to create a specific class that extends &lt;em&gt;HandlerInterceptorAdapter&lt;/em&gt; and with the some extra manipulation I was able to get my logs.&lt;/p&gt;

&lt;p&gt;Here are the methods I created for the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeRequestPayloadAudit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResettableStreamHttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;wrappedRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;requestHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getRawHeaders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrappedRequest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;requestBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IOUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrappedRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReader&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=================================== Request Start ==================================="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request Method: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;wrappedRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request URL: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;wrappedRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request Headers:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;requestHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request Body:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;requestBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"==================================== Request End ===================================="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Exception Request"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;writeResponsePayloadAudit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResettableStreamHttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;wrappedResponse&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;rawHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getRawHeaders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrappedResponse&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=================================== Response Start ==================================="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response Status: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;wrappedResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response Headers:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rawHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

  &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wrappedResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rawData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;()];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;wrappedResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rawData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;responseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response body:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;responseBody&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"==================================== Response End ===================================="&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is how my logs looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-10-30 18:32:35,583 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] =================================== Request Start ===================================
2020-10-30 18:32:35,584 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Request Method: GET
2020-10-30 18:32:35,585 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Request Headers:content-type:application/json,authorization:Bearer 6de79b7b-03bd-4e05-a8f8-af7f618d2fbc,user-agent:PostmanRuntime/7.26.5,accept:*/*,postman-token:18287157-4a9d-483f-9031-62cc2b3aa5dd,host:localhost:8080,accept-encoding:gzip, deflate, br,connection:keep-alive,
2020-10-30 18:32:35,585 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Request body:
2020-10-30 18:32:35,586 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] ==================================== Request End ====================================
2020-10-30 18:32:35,647 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] =================================== Response Start ===================================
2020-10-30 18:32:35,648 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Response Status: 200
2020-10-30 18:32:35,648 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Response Headers:Vary:Origin,Vary:Origin,Vary:Origin,
2020-10-30 18:32:35,649 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] Response body:{"status":200,"message":"","data":[[{"id":1,"name":"Supermercato 1","createdAt":"2020-10-29T22:44:33","updatedAt":"2020-10-29T22:44:33","deleted":0,"total":0,"bought":0,"items":[]}],[{"id":2,"name":"Supermercato 2","createdAt":"2020-10-29T22:44:41","updatedAt":"2020-10-29T22:44:41","deleted":0,"total":0,"bought":0,"items":[]}],[{"id":13,"name":"Supermercato 3","createdAt":"2020-10-29T22:49:06","updatedAt":"2020-10-29T22:49:06","deleted":0,"total":0,"bought":0,"items":[]}]]}
2020-10-30 18:32:35,649 INFO com.bebetos.shoppinglist.interceptors.LoggerInterceptor [http-nio-8080-exec-3] ==================================== Response End ====================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Special credits to my friend Alessandro Valenti for Angular advices.&lt;/p&gt;

&lt;p&gt;For extra code informations here is the link to the &lt;a href="https://github.com/BeBeToS92/my-shopping-list"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What are your opinions/advices? &lt;/p&gt;

</description>
      <category>showdev</category>
      <category>java</category>
      <category>ionic</category>
      <category>angular</category>
    </item>
  </channel>
</rss>
