<?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: JesúsB</title>
    <description>The latest articles on DEV Community by JesúsB (@bndf1).</description>
    <link>https://dev.to/bndf1</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%2F193854%2F7fa9c374-1e41-416c-aff3-3318f6a9b2ac.jpg</url>
      <title>DEV Community: JesúsB</title>
      <link>https://dev.to/bndf1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bndf1"/>
    <language>en</language>
    <item>
      <title>(Update: NgRx Signal Store Enhancements) Mastering State Management with NgRx Signal Store in Angular 🚀</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Mon, 10 Feb 2025 10:33:56 +0000</pubDate>
      <link>https://dev.to/bndf1/update-ngrx-signal-store-enhancements-mastering-state-management-with-ngrx-signal-store-in-4dln</link>
      <guid>https://dev.to/bndf1/update-ngrx-signal-store-enhancements-mastering-state-management-with-ngrx-signal-store-in-4dln</guid>
      <description>&lt;p&gt;With the recent updates to NgRx, several new features have been introduced that enhance the functionality and flexibility of the &lt;code&gt;SignalStore&lt;/code&gt;. In this update, I will outline the key changes in the new code compared to the original implementation, along with explanations based on the updated NgRx documentation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Changes and Additions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Introduction of &lt;code&gt;withProps&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The most notable change in the updated code is the use of the &lt;code&gt;withProps&lt;/code&gt; feature. This allows us to define additional properties within the store, such as services or custom observables, making the store more modular and easier to manage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original Code:&lt;/strong&gt;&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;withMethods&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastService&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;strong&gt;Updated Code:&lt;/strong&gt;&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;withProps&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="na"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="nf"&gt;withMethods&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;store&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;withProps&lt;/code&gt; function is used to inject dependencies like &lt;code&gt;PodcastService&lt;/code&gt; directly into the store. This makes the service available across all methods without needing to repeatedly inject it.&lt;/li&gt;
&lt;li&gt;This approach improves readability and reduces boilerplate by centralizing dependency injection.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  2. &lt;strong&gt;Improved Dependency Injection&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In the updated code, dependencies are grouped using &lt;code&gt;withProps&lt;/code&gt;, which aligns with the NgRx documentation's recommendation for managing shared dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Dependencies required across multiple store features can be grouped using &lt;code&gt;withProps&lt;/code&gt;."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example from Docs:&lt;/strong&gt;&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;withProps&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="na"&gt;booksService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BooksService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Logger&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;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By grouping dependencies, we ensure that services like &lt;code&gt;PodcastService&lt;/code&gt; are consistently injected and reused throughout the store.&lt;/li&gt;
&lt;li&gt;This also simplifies testing, as dependencies can be mocked or replaced more easily.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  3. &lt;strong&gt;Enhanced Method Definitions&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The updated code refactors method definitions to leverage destructuring of the store and its properties. This results in cleaner and more concise code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original Code:&lt;/strong&gt;&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;withMethods&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastService&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;strong&gt;Updated Code:&lt;/strong&gt;&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;withMethods&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;store&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The updated syntax uses object destructuring to extract &lt;code&gt;podcastService&lt;/code&gt; and the rest of the store (&lt;code&gt;...store&lt;/code&gt;) directly within the method definition.&lt;/li&gt;
&lt;li&gt;This eliminates the need to pass &lt;code&gt;podcastService&lt;/code&gt; as a separate parameter, improving clarity and reducing redundancy.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  4. &lt;strong&gt;Consistency with NgRx Documentation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The updated code aligns closely with the examples provided in the NgRx documentation, particularly in how &lt;code&gt;withProps&lt;/code&gt; and &lt;code&gt;withMethods&lt;/code&gt; are used together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation Example:&lt;/strong&gt;&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;withMethods&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;booksService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;store&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;async&lt;/span&gt; &lt;span class="nf"&gt;loadBooks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading books...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;books&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;booksService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Books loaded successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;strong&gt;Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Following the documented patterns ensures that the codebase adheres to best practices and remains maintainable.&lt;/li&gt;
&lt;li&gt;It also makes it easier for developers familiar with NgRx to understand and contribute to the project.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Summary of Benefits
&lt;/h3&gt;

&lt;p&gt;The updates to the NgRx Signal Store implementation bring several advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modularity:&lt;/strong&gt; Dependencies are centralized using &lt;code&gt;withProps&lt;/code&gt;, reducing duplication and improving organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability:&lt;/strong&gt; Refactored method definitions and destructuring make the code easier to read and maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alignment with Best Practices:&lt;/strong&gt; The updated code follows the latest NgRx documentation, ensuring compatibility and future-proofing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Developer Experience:&lt;/strong&gt; Cleaner syntax and reduced boilerplate enhance the overall development workflow.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The introduction of &lt;code&gt;withProps&lt;/code&gt; and the refinements to method definitions represent significant improvements in the NgRx Signal Store API. These changes not only simplify the code but also align it with modern Angular and NgRx best practices. As you continue to build and maintain your Angular applications, leveraging these updates will help you create more efficient and scalable state management solutions.&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>signals</category>
      <category>store</category>
    </item>
    <item>
      <title>Mastering State Management with NgRx Signal Store in Angular 🚀</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Mon, 10 Feb 2025 10:18:12 +0000</pubDate>
      <link>https://dev.to/bndf1/mastering-state-management-with-ngrx-signal-store-in-angular-35n1</link>
      <guid>https://dev.to/bndf1/mastering-state-management-with-ngrx-signal-store-in-angular-35n1</guid>
      <description>&lt;p&gt;In the ever-evolving landscape of Angular development, efficient state management is crucial for building scalable and maintainable applications. Enter NgRx Signal Store, a powerful solution that combines the simplicity of Angular's Signals API with the robustness of NgRx. Let's dive into how you can leverage NgRx Signal Store to streamline your state management in Angular applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is NgRx Signal Store?
&lt;/h2&gt;

&lt;p&gt;NgRx Signal Store is a state management library that integrates seamlessly with Angular's Signals API. It provides a structured way to manage application state, offering benefits such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralized state management&lt;/li&gt;
&lt;li&gt;Reactive updates with Signals&lt;/li&gt;
&lt;li&gt;Computed properties for derived state&lt;/li&gt;
&lt;li&gt;Type-safe state modifications&lt;/li&gt;
&lt;li&gt;Easy integration with Angular's dependency injection&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Setting Up NgRx Signal Store
&lt;/h3&gt;

&lt;p&gt;To get started with NgRx Signal Store, you first need to install it in your Angular project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun add @ngrx/signals@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Creating a Signal Store
&lt;/h3&gt;

&lt;p&gt;Let's look at a real-world example of how to create a Signal Store for managing podcast data:&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;type&lt;/span&gt; &lt;span class="nx"&gt;PodcastStoreState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&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;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desc&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PodcastStoreState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&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;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STORE_STATE&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;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PodcastStoreState&lt;/span&gt;&lt;span class="o"&gt;&amp;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;PodcastStore&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="na"&gt;factory&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="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PodcastStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;withState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STORE_STATE&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nx"&gt;withEntities&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;withComputed&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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="na"&gt;subscribedPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;podcast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;myPodcast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;myPodcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;podcast&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="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;sortByRating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;computed&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="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&lt;/span&gt;&lt;span class="dl"&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="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="nf"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;direction&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="nf"&gt;withMethods&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastService&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getMyPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;pods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMyPodcasts&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;withHooks&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMyPodcasts&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;strong&gt;Key components of the store:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State Definition&lt;/strong&gt;: We define the shape of our store state using TypeScript interfaces. Defined using an &lt;em&gt;InjectionToken&lt;/em&gt; allowing us to inject values, services, or configurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: We set up the initial state of our store. Let's say "empty" in this case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store Creation&lt;/strong&gt;: We can use the methods that signalStore provides to create our store, providing various configurations.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Computed Properties
&lt;/h3&gt;

&lt;p&gt;One of the powerful features of NgRx Signal Store is the ability to create computed properties.&lt;/p&gt;

&lt;p&gt;We can add computed signals to the store using the &lt;code&gt;withComputed&lt;/code&gt; feature, which takes a factory function as its input.&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;withComputed&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&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="na"&gt;subscribedPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;podcast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;myPodcast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;myPodcast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;podcast&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="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;sortByRating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;computed&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="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asc&lt;/span&gt;&lt;span class="dl"&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="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="nf"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;direction&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 function runs within the injection context and returns a dictionary of computed signals.&lt;/p&gt;

&lt;p&gt;It can leverage both previously defined state and existing computed signals accessible through the function's input argument.&lt;/p&gt;

&lt;p&gt;These computed properties allow us to efficiently derive state without unnecessary recalculations.&lt;/p&gt;




&lt;h3&gt;
  
  
  State Modifications
&lt;/h3&gt;

&lt;p&gt;NgRx Signal Store provides a clean way to modify state through methods:&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;withMethods&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;podcastService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastService&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAllPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;allPodcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allPodcasts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getMyPodcasts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;pods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lastValueFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMyPodcasts&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;patchState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;myPodcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;ul&gt;
&lt;li&gt;These methods encapsulate the logic for updating our store, making it easy to manage complex state changes.&lt;/li&gt;
&lt;li&gt;We can add methods to the store using the &lt;code&gt;withMethods&lt;/code&gt; feature, which takes a factory function as its input and returns a dictionary of methods.&lt;/li&gt;
&lt;li&gt;Like &lt;code&gt;withComputed&lt;/code&gt;, the &lt;code&gt;withMethods&lt;/code&gt; factory runs within the injection context, providing access to the store's instance, including previously defined state, computed signals, and methods.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Using the Store in Components
&lt;/h3&gt;

&lt;p&gt;To use our NgRx Signal Store in a component, we can simply inject it and access its properties and methods:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-podcasts-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @let podcasts = store.podcasts();
    @defer (when podcasts) {
      &amp;lt;h2 class="text-2xl font-semibold text-center text-gray-800"&amp;gt;
        All Podcasts
      &amp;lt;/h2&amp;gt;
      &amp;lt;div class="grid gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"&amp;gt;
        @for (podcast of podcasts; track podcast.id) {
          @defer (on viewport) {
            &amp;lt;app-podcast-item [podcast]="podcast" /&amp;gt;
          } @placeholder {
            &amp;lt;app-skeleton /&amp;gt;
          } @loading {
            &amp;lt;app-skeleton /&amp;gt;
          }
        }
      &amp;lt;/div&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastsContainerComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastStore&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 component injects our PodcastStore and uses its &lt;code&gt;podcasts&lt;/code&gt; signal in the template, demonstrating how easy it is to consume state from our store.&lt;/p&gt;




&lt;h3&gt;
  
  
  Benefits of NgRx Signal Store
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reactivity&lt;/strong&gt;: Changes to the store automatically update all subscribers, thanks to Signals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Computed properties and fine-grained updates lead to optimal performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: TypeScript integration provides excellent type checking and autocompletion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: The structure of Signal Stores makes unit testing straightforward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt;: Simplified API compared to traditional NgRx, reducing boilerplate.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;NgRx Signal Store represents a significant step forward in state management for Angular applications. By combining the power of NgRx with the simplicity of Signals, it offers a robust yet developer-friendly solution for managing application state.&lt;/p&gt;

&lt;p&gt;As you build your next Angular application, consider how NgRx Signal Store can help you create more maintainable, performant, and scalable state management solutions. Happy coding! 🚀&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>signals</category>
      <category>store</category>
    </item>
    <item>
      <title>Boosting Angular Performance: @defer, Lazy Loading, and Core Web Vitals</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Wed, 05 Feb 2025 11:55:08 +0000</pubDate>
      <link>https://dev.to/bndf1/boosting-angular-performance-defer-lazy-loading-and-core-web-vitals-1mp8</link>
      <guid>https://dev.to/bndf1/boosting-angular-performance-defer-lazy-loading-and-core-web-vitals-1mp8</guid>
      <description>&lt;h2&gt;
  
  
  🔍 Understanding Core Web Vitals
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's quickly recap what Core Web Vitals are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Largest Contentful Paint (LCP)&lt;/strong&gt;: Measures loading performance. 🖼️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interaction to Next Paint (INP)&lt;/strong&gt;: Measures overall responsiveness. ⚡ - INP replaced First Input Delay (FID) in March 2024.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cumulative Layout Shift (CLS)&lt;/strong&gt;: Measures visual stability. 📏&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: First Input Delay (FID) is no longer a Core Web Vital. It measured initial interactivity, aiming for values less than 100 milliseconds for a good user experience. INP now provides a more comprehensive measure of responsiveness throughout the user's entire session.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🧩 The Power of &lt;code&gt;@defer&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Angular's &lt;code&gt;@defer&lt;/code&gt; block is a game-changer for performance optimization. It allows you to defer the loading of component trees until they're needed. Here's an example:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;h1&amp;gt;Welcome to Our Podcast App&amp;lt;/h1&amp;gt;
    &amp;lt;app-featured-podcasts /&amp;gt;
    @defer (on viewport) {
      &amp;lt;app-podcast-list [podcasts]="podcasts" /&amp;gt;
    } @placeholder {
      &amp;lt;p&amp;gt;Scroll down to see more podcasts...&amp;lt;/p&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;podcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastStore&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;podcasts&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;In this example, the &lt;code&gt;app-podcast-list&lt;/code&gt; component will only be loaded when it enters the viewport, but it starts prefetching when the browser is idle.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;On idle&lt;/code&gt; will trigger the deferred loading once the browser has reached an idle state. This is the default behavior with a defer block.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Impact on Core Web Vitals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improves LCP&lt;/strong&gt;: Deferring non-critical content allows faster loading of main content. Lazy loading reduces initial bundle size, speeding up load times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhances INP&lt;/strong&gt;: By deferring non-essential interactivity, the app remains responsive throughout the user's session. Prefetching during idle time ensures smoother interactions when content is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimizes CLS&lt;/strong&gt;: Using placeholders prevents layout shifts as deferred content loads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏋️ Lazy Loading: The Perfect Companion
&lt;/h2&gt;

&lt;p&gt;Combine &lt;code&gt;@defer&lt;/code&gt; with lazy loading for even better performance:&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;podcasts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadComponent&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./podcasts/podcasts.component&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PodcastsComponent&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 approach loads the entire &lt;code&gt;PodcastsComponent&lt;/code&gt; only when the user navigates to the &lt;code&gt;/podcasts&lt;/code&gt; route.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Core Web Vitals impact
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Further improves LCP&lt;/strong&gt;: Initial bundle size is reduced, leading to faster load times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boosts FID&lt;/strong&gt;: Less JavaScript to parse on initial load means the app becomes interactive faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔧 Practical Implementation Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prioritize Above-the-fold Content
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;@defer&lt;/code&gt; for below-the-fold content to improve LCP.&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;app-header /&amp;gt;
    &amp;lt;app-featured-podcasts /&amp;gt;
    @defer (on viewport; prefetch on idle) {
      &amp;lt;app-podcast-categories /&amp;gt;
    } @placeholder {
      &amp;lt;div&amp;gt;...&amp;lt;/div&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Smart Prefetching
&lt;/h3&gt;

&lt;p&gt;For critical paths, use prefetch with &lt;code&gt;@defer&lt;/code&gt;:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;defer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;prefetch&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&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="nd"&gt;placeholder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple event triggers can be defined at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy Load Feature Modules
&lt;/h3&gt;

&lt;p&gt;Group related functionality into feature modules and lazy load them:&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./admin/admin.module&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AdminModule&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;
  
  
  Use Standalone Components
&lt;/h3&gt;

&lt;p&gt;They can be lazy-loaded individually, offering finer-grained control:&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadComponent&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./profile.component&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileComponent&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;h2&gt;
  
  
  🎭 Real-world Scenario: Podcast Streaming App
&lt;/h2&gt;

&lt;p&gt;Let's look at how we might apply these techniques in a podcast streaming app:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-podcasts-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @let podcasts = store.podcasts();
    @defer (when podcasts) {
      &amp;lt;h2 class="text-2xl capitalize lg:text-3xl"&amp;gt;All Podcasts&amp;lt;/h2&amp;gt;
      &amp;lt;div class="grid gap-8 mt-8"&amp;gt;
        @for (podcast of podcasts; track podcast.id) {
          @defer (on viewport) {
            &amp;lt;app-podcast-item [podcast]="podcast" /&amp;gt;
          } @placeholder {
            &amp;lt;app-skeleton /&amp;gt;
          }
        }
      &amp;lt;/div&amp;gt;
    }
    @defer (on interaction; prefetch when isLoggedIn()) {
      &amp;lt;app-add-to-favorites [podcast]="podcast" /&amp;gt;
    } @placeholder {
      &amp;lt;div&amp;gt;...&amp;lt;/div&amp;gt;
    }
    @defer (on timer(5s); prefetch on idle) {
      &amp;lt;app-related-podcasts [category]="podcast.category" /&amp;gt;
    } @placeholder {
      &amp;lt;div&amp;gt;...&amp;lt;/div&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastsContainerComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastStore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&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="nf"&gt;isLoggedIn&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 example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads critical content immediately.&lt;/li&gt;
&lt;li&gt;Defers episode list, loading when in viewport and prefetching during idle time.&lt;/li&gt;
&lt;li&gt;Defers and prefetches "Add to Favorites" based on user login state.&lt;/li&gt;
&lt;li&gt;Defers related podcasts, loading after 5 seconds but prefetching during idle time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach significantly improves all Core Web Vitals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LCP&lt;/strong&gt;: Critical content loads first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP&lt;/strong&gt;: Interactivity is improved by deferring non-essential components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS&lt;/strong&gt;: Placeholders prevent layout shifts as content loads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📊 Measuring the Impact
&lt;/h2&gt;

&lt;p&gt;Always measure the impact of your optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Chrome DevTools' Performance tab to analyze loading, scripting, and rendering times.&lt;/li&gt;
&lt;li&gt;Leverage Lighthouse for a comprehensive performance audit, including Core Web Vitals scores.&lt;/li&gt;
&lt;li&gt;Monitor real-user metrics using tools like Google Analytics or custom performance tracking.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;By leveraging &lt;code&gt;@defer&lt;/code&gt; blocks with placeholders, loading states, and prefetching, combined with lazy loading, you can significantly improve your Angular app's performance and Core Web Vitals scores. Remember, performance optimization is an ongoing process. Continuously measure, optimize, and iterate for the best results.&lt;/p&gt;

&lt;p&gt;The key is to understand your user's journey and prioritize content accordingly. Use &lt;code&gt;@defer&lt;/code&gt; and lazy loading strategically to create a fast, responsive, and smooth user experience.&lt;/p&gt;

&lt;p&gt;Have you implemented &lt;code&gt;@defer&lt;/code&gt; or lazy loading in your Angular projects? What improvements did you see? Share your experiences in the comments below! 💬&lt;/p&gt;

</description>
      <category>angular</category>
      <category>corewebvitals</category>
      <category>defer</category>
      <category>lazyloading</category>
    </item>
    <item>
      <title>DON'T MISS: Your angular forms strongly typed based on your interface :rocket:</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Wed, 05 Feb 2025 11:53:36 +0000</pubDate>
      <link>https://dev.to/bndf1/dont-miss-your-angular-forms-strongly-typed-based-on-your-interface-rocket-c9a</link>
      <guid>https://dev.to/bndf1/dont-miss-your-angular-forms-strongly-typed-based-on-your-interface-rocket-c9a</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/davidgarcia" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1627730%2Fdee7d909-64d7-48d6-a5da-4b8315b72bd8.png" alt="davidgarcia"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/davidgarcia/strongly-typed-forms-in-angular-without-duplicating-interfaces-1972" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;📌 Strongly Typed Forms in Angular Without Duplicating Interfaces&lt;/h2&gt;
      &lt;h3&gt;David Garcia ・ Feb 4&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angularforms&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>angular</category>
      <category>angularforms</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Architecting Angular Applications: A Case Study in Scalable and Maintainable Design 🚀</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Thu, 16 Jan 2025 14:42:42 +0000</pubDate>
      <link>https://dev.to/bndf1/architecting-angular-applications-a-case-study-in-scalable-and-maintainable-design-40oh</link>
      <guid>https://dev.to/bndf1/architecting-angular-applications-a-case-study-in-scalable-and-maintainable-design-40oh</guid>
      <description>&lt;p&gt;In the ever-evolving landscape of web development, creating a &lt;strong&gt;scalable&lt;/strong&gt; and &lt;strong&gt;maintainable Angular application&lt;/strong&gt; is crucial for long-term success. 🏗️ Today, we'll dive into a &lt;strong&gt;case study of an architecture&lt;/strong&gt; that promotes these qualities, examining its structure and benefits. We'll explore how this architecture was used to build a music streaming application (simplified for this example) with a growing library of podcasts and user features. 🎧&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is This Article For? 👨‍💻👩‍💻
&lt;/h2&gt;

&lt;p&gt;This article is designed for &lt;strong&gt;intermediate to advanced Angular developers&lt;/strong&gt; who are looking to refine their application architecture for better scalability and maintainability. If you're familiar with the basics of Angular components, services, and state management but want to dive deeper into best practices and architectural patterns, this is for you! 👍&lt;/p&gt;




&lt;h3&gt;
  
  
  The Folder Structure: A Foundation for Clarity 🗂️
&lt;/h3&gt;

&lt;p&gt;A well-organized folder structure is the backbone of a maintainable application. Here’s a &lt;strong&gt;folder structure&lt;/strong&gt; that has proven effective:&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="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;adapters&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;environments&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each folder serves a distinct purpose, contributing to a &lt;strong&gt;modular and scalable architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why This Structure? 🤔
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modularity&lt;/strong&gt;: Each folder serves a specific purpose, making it easy to locate and manage different aspects of the application. 🧩&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: As the application grows (e.g., adding new features like user playlists, music recommendations, etc.), new features can be added within their respective folders without cluttering the existing structure. 📈&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Clear separation between components, services, and data models promotes cleaner, more maintainable code. 🧹&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Components: The Building Blocks 🧱
&lt;/h3&gt;

&lt;p&gt;In this structure, the &lt;strong&gt;components folder&lt;/strong&gt; is further organized by feature:&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="nx"&gt;components&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;podcasts&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;podcast&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;podcast&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;episodes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;episodes&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;episode&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;episode&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup provides several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy location of related components&lt;/strong&gt;: As you scale, each feature or section of your app (e.g., podcasts, user authentication, playlists) remains self-contained. 📍&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: New features (like a "Now Playing" bar or user profile page) can be added without affecting existing ones. ➕&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of concerns&lt;/strong&gt;: Different parts of your app are kept distinct, reducing complexity. 🤯&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Smart vs. Dumb Components&lt;/strong&gt; 🧠&lt;/p&gt;

&lt;p&gt;Within this structure, we follow the pattern of smart (container) and dumb (presentational) components. For example, &lt;code&gt;podcast-container.component.ts&lt;/code&gt; would be a smart component that fetches podcast data from the store and passes it to the dumb component &lt;code&gt;podcast-item.component.ts&lt;/code&gt; for display. This further enhances the separation of concerns and reusability.🔄&lt;/p&gt;




&lt;h3&gt;
  
  
  Services: The Data Management Layer 🗄️
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;services folder&lt;/strong&gt; contains all services responsible for data management and business logic. Services are centralized to promote &lt;strong&gt;reusability&lt;/strong&gt; and &lt;strong&gt;consistency&lt;/strong&gt;:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;apiService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ApiService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;getAllPodcasts&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="nf"&gt;toSignal&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="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getAll&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;apiService&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;Broadcast&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="s2"&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;PATH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&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;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastAdapter&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 centralized approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promotes reusability&lt;/strong&gt; across the application. For example, the &lt;code&gt;PodcastService&lt;/code&gt; can be used by multiple components throughout the app. ♻️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplifies maintenance&lt;/strong&gt; by centralizing data fetching logic. If the API endpoint changes, you only need to update it in one place. 🛠️&lt;/li&gt;
&lt;li&gt;Provides a &lt;strong&gt;clear interface&lt;/strong&gt; for components to interact with data. 🤝&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Models: Defining the Shape of Data 📐
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;models folder&lt;/strong&gt; contains interfaces that define the shape of our data. This improves both &lt;strong&gt;type safety&lt;/strong&gt; and &lt;strong&gt;code readability&lt;/strong&gt;:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&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;title&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;description&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;image&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;category&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;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;website&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced type safety&lt;/strong&gt; across the application, reducing runtime errors. 🔒&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear structure&lt;/strong&gt; for incoming and outgoing data. 📊&lt;/li&gt;
&lt;li&gt;Easier refactoring and &lt;strong&gt;future-proofing&lt;/strong&gt;. 🔮&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Adapters: Bridging External and Internal Data Structures 🌉
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;adapters folder&lt;/strong&gt; transforms external API data into a format the application can easily consume:&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;PodcastAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Broadcast&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;pods&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="nx"&gt;pod&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&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="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;average_rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;website&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&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;By using adapters, you &lt;strong&gt;decouple&lt;/strong&gt; your application from external data structures, making it easier to handle API changes and ensuring consistent data transformations across your app. This is also beneficial for testing, as you can easily mock API responses by providing data that is already in the format expected by your application. 🧪&lt;/p&gt;




&lt;h3&gt;
  
  
  Store: Managing Application State with NgRx SignalStore 🚦
&lt;/h3&gt;

&lt;p&gt;For state management, we’re using &lt;strong&gt;NgRx SignalStore&lt;/strong&gt;, which combines the power of NgRx with the simplicity of Angular's Signals API. We chose SignalStore for this application because it provides a streamlined way to manage state and reactivity while leveraging the familiar concepts of NgRx.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why NgRx SignalStore? 🤔
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized State&lt;/strong&gt;: All state related to podcasts (and potentially other features like user authentication and playlists) is managed in one place. This makes it easier to track changes and debug issues. 🎯&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Computed Properties&lt;/strong&gt;: Computed signals help with derived state, like filtered or sorted podcasts, improving performance by only recalculating when dependencies change. ⚡️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods for State Changes&lt;/strong&gt;: Actions that modify state are defined as methods, simplifying logic and improving predictability. This makes it easier to reason about how state changes over time. 🧠&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Performance:&lt;/strong&gt; SignalStore can offer performance advantages over traditional NgRx stores, especially in applications with frequent state updates. 🚀
&lt;/li&gt;
&lt;/ul&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;PodcastStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;withState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PodcastStoreState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
  &lt;span class="nf"&gt;withComputed&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
  &lt;span class="nf"&gt;withMethods&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
  &lt;span class="nf"&gt;withHooks&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 setup allows for &lt;strong&gt;efficient reactivity&lt;/strong&gt;, &lt;strong&gt;centralized management&lt;/strong&gt;, and &lt;strong&gt;predictability&lt;/strong&gt; in state changes, making it easier to debug and test. 🐛&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While SignalStore offers many benefits, it's important to be aware of potential drawbacks. For example, debugging complex state changes can be challenging, and migrating from a traditional NgRx store can require significant refactoring. ⚠️&lt;/p&gt;




&lt;h3&gt;
  
  
  Benefits of This Architecture ✨
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: New features, like user profiles or personalized recommendations, can be added without disrupting existing code. 📈&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt;: Clear separation of concerns makes the code easier to understand, update, and debug. 🛠️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Services and components are modular, making them reusable across the app. ♻️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Modular structure facilitates easier unit testing. For instance, you can easily isolate components and mock dependencies like services and the NgRx SignalStore. 🧪&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration&lt;/strong&gt;: Teams can work on different parts of the app (e.g., a team focused on podcasts and another on user accounts) with minimal conflict. 🤝&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusion 🎉
&lt;/h3&gt;

&lt;p&gt;This architecture provides a solid foundation for building scalable and maintainable Angular applications. By separating concerns, promoting modularity, and following consistent patterns, you can create a codebase that evolves with your needs.&lt;/p&gt;

&lt;p&gt;Remember, the best architecture serves your specific project requirements. Be ready to adapt and evolve your structure as your application grows and new insights emerge.&lt;/p&gt;

&lt;p&gt;What has been your experience with Angular application architecture? Have you used similar patterns in your projects? Let’s discuss in the comments! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>patterns</category>
      <category>scalable</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Streamlining Data Flow in Angular: The Power of the Adapter Pattern 🔄</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Mon, 13 Jan 2025 13:57:07 +0000</pubDate>
      <link>https://dev.to/bndf1/streamlining-data-flow-in-angular-the-power-of-the-adapter-pattern-1804</link>
      <guid>https://dev.to/bndf1/streamlining-data-flow-in-angular-the-power-of-the-adapter-pattern-1804</guid>
      <description>&lt;p&gt;In modern web development, especially with Angular, we often grapple with data from various sources that don't align perfectly with our application's models. Enter the Adapter pattern - a game-changer for creating robust and maintainable Angular applications. Let's dive in!&lt;/p&gt;

&lt;p&gt;🧩 What is the Adapter Pattern?&lt;br&gt;
The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to collaborate. In Angular, we use it to transform external API data into a format our application can easily consume.&lt;/p&gt;

&lt;p&gt;🌟 Why Use the Adapter Pattern?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling&lt;/strong&gt;: Separates data fetching from data shaping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Easily adapt to API changes without affecting the entire app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Ensures uniform data structure throughout your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Simplifies testing data transformations in isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💻 Real-World Example&lt;br&gt;
Let's look at a PodcastAdapter from a podcast app:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Broadcast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@models&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PodcastAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Broadcast&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;pods&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="nx"&gt;pod&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&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="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;average_rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;website&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&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;🔍 Breaking It Down&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input&lt;/strong&gt;: Array of Broadcast objects (raw API data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output&lt;/strong&gt;: Array of Podcast objects (our app's model)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transformation&lt;/strong&gt;: Mapping each Broadcast to a Podcast, renaming properties as needed
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;apiService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ApiService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;getAllPodcasts&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="nf"&gt;toSignal&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="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getAll&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;apiService&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;Broadcast&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="s2"&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;PATH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&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;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastAdapter&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;🛠️ Where to Use the Adapter&lt;br&gt;
Typically in services, right after fetching API data:&lt;/p&gt;

&lt;p&gt;🎯 Benefits in Action&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API Resilience&lt;/strong&gt;: Only update the adapter if API changes, not every component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Consistency&lt;/strong&gt;: Uniform podcast data structure across the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Leverage TypeScript for better error catching and IDE support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolated Testing&lt;/strong&gt;: Easily unit test the adapter function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚀 Best Practices&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep It Simple&lt;/strong&gt;: Focus solely on data transformation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embrace TypeScript&lt;/strong&gt;: Define clear interfaces for input and output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralize Adapters&lt;/strong&gt;: Maintain a dedicated adapters folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider Inverse Adapters&lt;/strong&gt;: For sending data back to the API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 Pro Tip: Use adapters with Angular's new &lt;code&gt;toSignal()&lt;/code&gt; function for seamless integration with the signals API!&lt;/p&gt;

&lt;p&gt;🏁 Conclusion&lt;br&gt;
The Adapter pattern is a powerful tool for managing the complexities of data transformation in Angular. It creates a clear boundary between external data and internal structures, enhancing maintainability, flexibility, and robustness.&lt;/p&gt;

&lt;p&gt;As you build your next Angular masterpiece, consider how the Adapter pattern can elevate your data management game!&lt;/p&gt;

&lt;p&gt;🤔 Have you used the Adapter pattern in your Angular projects? What challenges did it help you overcome? Let's discuss in the comments!!.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>patterns</category>
      <category>adapter</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Mastering the Container-Presenter Pattern in Angular: A Deep Dive</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Thu, 19 Dec 2024 15:03:28 +0000</pubDate>
      <link>https://dev.to/bndf1/mastering-the-container-presenter-pattern-in-angular-a-deep-dive-3pk3</link>
      <guid>https://dev.to/bndf1/mastering-the-container-presenter-pattern-in-angular-a-deep-dive-3pk3</guid>
      <description>&lt;p&gt;In the world of Angular development, structuring your components effectively can make a significant difference in the maintainability and scalability of your application. Today, let's explore a powerful pattern that has become a cornerstone in many Angular projects: the Container-Presenter pattern.&lt;/p&gt;

&lt;p&gt;🧩 What is the Container-Presenter Pattern?&lt;br&gt;
The Container-Presenter pattern, also known as Smart and Dumb Components or Stateful and Stateless Components, is a design pattern that promotes a clear separation of concerns in your Angular components. Let's break it down:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Container (Smart) Components&lt;/strong&gt;: These components are responsible for how things work. They manage state, fetch data, and contain business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Presenter (Dumb) Components&lt;/strong&gt;: These components are responsible for how things look. They receive data via inputs and emit events via outputs, focusing solely on the presentation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🌟 Why Use This Pattern?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved Testability&lt;/strong&gt;: Presenter components are easier to test as they don't depend on services or state management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Reusability&lt;/strong&gt;: Presenter components can be reused across different parts of your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Separation of Concerns&lt;/strong&gt;: Each component has a clear, single responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Maintenance&lt;/strong&gt;: Changes to business logic or data fetching don't affect the presentation layer, and vice versa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💻 Real-World Example&lt;br&gt;
Let's look at a real-world example from a podcast application I've been working on:&lt;/p&gt;

&lt;p&gt;Container Component:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-podcasts-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PodcastItemComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SkeletonComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @let podcasts = store.podcasts();
    @defer (when podcasts) {
      &amp;lt;h2
        class="text-2xl font-semibold text-center text-gray-800 capitalize lg:text-3xl dark:text-white"
      &amp;gt;
        All Podcasts
      &amp;lt;/h2&amp;gt;
      &amp;lt;div class="grid gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"&amp;gt;
        @for (podcast of podcasts; track podcast.id) {
          @defer (on viewport) {
            &amp;lt;app-podcast-item [podcast]="podcast" /&amp;gt;
          } @placeholder {
            &amp;lt;app-skeleton [type]="'CARD'" /&amp;gt;
          } @loading {
            &amp;lt;app-skeleton [type]="'CARD'" /&amp;gt;
          }
        }
      &amp;lt;/div&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastsContainerComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PodcastStore&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 container component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Injects the PodcastStore to access the application state&lt;/li&gt;
&lt;li&gt;Uses the &lt;a class="mentioned-user" href="https://dev.to/defer"&gt;@defer&lt;/a&gt; directive for lazy loading and better performance&lt;/li&gt;
&lt;li&gt;Iterates over the podcasts and renders PodcastItemComponent for each&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Presenter Component:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-podcast-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;NgOptimizedImage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @if (podcast(); as podcast) {
      &amp;lt;div
        class="overflow-hidden bg-white rounded-lg shadow-lg dark:bg-gray-800"
      &amp;gt;
        &amp;lt;div class="px-4 py-2"&amp;gt;
          &amp;lt;h1 class="text-xl font-bold text-gray-800 uppercase dark:text-white"&amp;gt;
            {{ podcast.title }}
          &amp;lt;/h1&amp;gt;
          &amp;lt;p class="mt-1 text-sm text-gray-600 dark:text-gray-400"&amp;gt;
            {{ podcast.description }}
          &amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;img
          class="object-cover w-full h-48 mt-2"
          [src]="podcast.image"
          [alt]="podcast.title"
        /&amp;gt;
        &amp;lt;div class="flex items-center justify-between px-4 py-2 bg-gray-900"&amp;gt;
          &amp;lt;h1 class="text-lg font-bold text-white"&amp;gt;{{ podcast.rating }}&amp;lt;/h1&amp;gt;
          &amp;lt;button
            class="px-2 py-1 text-xs font-semibold text-gray-900 uppercase transition-colors duration-300 transform bg-white rounded hover:bg-gray-200 focus:bg-gray-400 focus:outline-none"
          &amp;gt;
            Subscribe
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastItemComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;podcast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Podcast&lt;/span&gt;&lt;span class="o"&gt;&amp;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 presenter component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receives a podcast input&lt;/li&gt;
&lt;li&gt;Focuses solely on rendering the podcast information&lt;/li&gt;
&lt;li&gt;Has no knowledge of where the data comes from or how it's managed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 Benefits in Action&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: The PodcastItemComponent can be easily reused in other parts of the application, such as a "Featured Podcasts" section or a search results page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Testing the PodcastItemComponent is straightforward as we can simply pass in mock podcast data and assert on the rendered output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: The PodcastsContainerComponent handles data fetching and state management, while PodcastItemComponent focuses purely on presentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: By using ChangeDetectionStrategy.OnPush, we optimize change detection for both components.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚀 Conclusion&lt;br&gt;
The Container-Presenter pattern is a powerful tool in an Angular developer's arsenal. It promotes clean, maintainable, and scalable code by clearly separating concerns between data management and presentation.&lt;/p&gt;

&lt;p&gt;As you structure your Angular applications, consider how this pattern can benefit your project. It may require a bit more initial setup, but the long-term benefits in terms of maintainability, testability, and scalability are well worth it.&lt;/p&gt;

&lt;p&gt;💬 Have you used the Container-Presenter pattern in your Angular projects? What benefits or challenges have you encountered? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>patterns</category>
      <category>container</category>
      <category>presenter</category>
    </item>
    <item>
      <title>Modernizing Angular: Embracing Fetch API for Better Performance and Security</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Tue, 17 Dec 2024 11:52:57 +0000</pubDate>
      <link>https://dev.to/bndf1/modernizing-angular-embracing-fetch-api-for-better-performance-and-security-5df5</link>
      <guid>https://dev.to/bndf1/modernizing-angular-embracing-fetch-api-for-better-performance-and-security-5df5</guid>
      <description>&lt;p&gt;As Angular evolves, it brings exciting changes that streamline our development process and enhance our applications. One such change is the introduction of &lt;code&gt;app.config.ts&lt;/code&gt;, where we now define providers for bootstrapping our main component. Today, let's highlight a simple yet powerful feature: switching Angular's HttpClient to use the Fetch API.&lt;/p&gt;

&lt;p&gt;🔄 The Shift from XMLHttpRequest to Fetch&lt;br&gt;
Traditionally, Angular's HttpClient relied on XMLHttpRequest (XHR) for handling HTTP requests. While XHR has served us well, the web platform has evolved, offering more modern alternatives.&lt;/p&gt;

&lt;p&gt;Enter the &lt;strong&gt;Fetch API&lt;/strong&gt; - a contemporary approach to making HTTP requests. With Angular's new configuration options, we can now easily switch HttpClient to use Fetch instead of XHR.&lt;/p&gt;

&lt;p&gt;🌟 Why Consider the Switch?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance Boost&lt;/strong&gt;: Fetch is designed with modern web applications in mind, offering potential performance improvements, especially for complex applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Fetch comes with better support for modern security features like CORS and Content Security Policy, helping to fortify our applications against common vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Promise-based API&lt;/strong&gt;: Fetch provides a cleaner, more intuitive API based on Promises, aligning well with modern JavaScript practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future-Proofing&lt;/strong&gt;: As the web evolves, Fetch is more likely to receive updates and improvements compared to the older XHR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🛠️ How to Make the Switch&lt;br&gt;
Implementing this change is surprisingly simple. In your &lt;code&gt;app.config.ts&lt;/code&gt;, use the &lt;code&gt;withFetch()&lt;/code&gt; option when providing HttpClient:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withFetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other providers&lt;/span&gt;
    &lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withFetch&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 small change can have a significant impact on your application's performance and security posture.&lt;/p&gt;

&lt;p&gt;⚖️ Considerations&lt;br&gt;
While Fetch offers numerous advantages, it's worth noting that it has some limitations. For instance, it doesn't support upload progress events, which might be crucial for certain applications. Always evaluate your specific needs before making the switch.&lt;/p&gt;

&lt;p&gt;🎯 Conclusion&lt;br&gt;
As Angular continues to embrace modern web standards, features like &lt;code&gt;withFetch()&lt;/code&gt; offer us simple ways to keep our applications cutting-edge. By adopting these new capabilities, we not only potentially improve performance and security but also future-proof our applications.&lt;/p&gt;

&lt;p&gt;💬 Have you tried switching to Fetch in your Angular applications? I'd love to hear about your experiences! Share your thoughts in the comments - did you notice any performance improvements? Any challenges you faced? Let's discuss and learn from each other's experiences!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>performance</category>
      <category>fetch</category>
    </item>
    <item>
      <title>New in Angular: Bridging RxJS and Signals with toSignal!</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Tue, 17 Dec 2024 11:33:49 +0000</pubDate>
      <link>https://dev.to/bndf1/new-in-angular-bridging-rxjs-and-signals-with-tosignal-35e8</link>
      <guid>https://dev.to/bndf1/new-in-angular-bridging-rxjs-and-signals-with-tosignal-35e8</guid>
      <description>&lt;p&gt;Angular developers, are you ready to simplify your reactive programming? Let me introduce you to &lt;code&gt;toSignal&lt;/code&gt;, a game-changing feature that seamlessly connects RxJS Observables with Angular's new Signals API.&lt;/p&gt;

&lt;p&gt;🔗 What is &lt;code&gt;toSignal&lt;/code&gt;?&lt;br&gt;
It's a function that converts an Observable into a Signal, giving you the best of both worlds - the power of RxJS and the simplicity of Signals.&lt;/p&gt;

&lt;p&gt;💡 Key benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Streamlined code: No more async pipe in templates&lt;/li&gt;
&lt;li&gt;Automatic subscription management&lt;/li&gt;
&lt;li&gt;Use anywhere in your app, not just in templates&lt;/li&gt;
&lt;li&gt;Improved performance and change detection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a quick example from a recent project:&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;class&lt;/span&gt; &lt;span class="nc"&gt;EpisodesService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/episodes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ApiService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;getAllEpisodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Episode&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="nf"&gt;toSignal&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="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;api&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;Chapter&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;path&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="nx"&gt;EpisodeAdapter&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialValue&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;And here's how you can use it in a component:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-episodes-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @for (episode of episodes(); track episode.id) {
      &amp;lt;app-episodes-item [episode]="episode" /&amp;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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EpisodesContainerComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;episodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EpisodesService&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getAllEpisodes&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;We're fetching data from an API, transforming it with EpisodeAdapter, and then wrapping the resulting Observable with toSignal(). Now, any component using this service can easily consume the episode data as a Signal!&lt;/p&gt;

&lt;p&gt;In the template, we can directly use episodes() to access the latest value, just like any other Signal!&lt;br&gt;
⚠️ Important Note: The RxJS Interop package (&lt;code&gt;@angular/core/rxjs-interop&lt;/code&gt;) is currently available for developer preview. While it's ready for experimentation, be aware that it might undergo changes before reaching a stable release.&lt;/p&gt;

&lt;p&gt;🚀 Ready to level up your Angular skills? Start experimenting with &lt;code&gt;toSignal&lt;/code&gt; in your projects today!!&lt;/p&gt;

&lt;p&gt;What do you think? Want to dive deeper into Signals and RxJS integration? Let me know in the comments!.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>signals</category>
    </item>
    <item>
      <title>Modern Testing Practices in Angular: From Unit to Integration Testing</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Mon, 16 Dec 2024 11:01:03 +0000</pubDate>
      <link>https://dev.to/bndf1/modern-testing-practices-in-angular-from-unit-to-integration-testing-2c01</link>
      <guid>https://dev.to/bndf1/modern-testing-practices-in-angular-from-unit-to-integration-testing-2c01</guid>
      <description>&lt;p&gt;In the dynamic world of web development, ensuring the reliability and maintainability of your applications is paramount. 🌐 Angular, one of the leading frontend frameworks, has been at the forefront of this endeavor, evolving its testing strategies to keep pace with industry best practices.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore the insights shared by Rainer Hanekamp, a trainer and consultant at Angular Architects, who advocates for a significant shift from traditional unit testing to more comprehensive integration testing in Angular applications. 🚀&lt;/p&gt;

&lt;p&gt;All insights in this article are based on &lt;a href="https://youtu.be/lbiOP-VLKGI?si=P6xVa5GFV1VmGEw6" rel="noopener noreferrer"&gt;Rainer Hanekamp's video&lt;/a&gt;, which provides a deep dive into modern testing practices in Angular. 🎥&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Modern Testing in Angular
&lt;/h2&gt;

&lt;p&gt;Angular has long been a favorite among developers, not just for its robust features but also for its seamless integration with testing tools. 🛠️&lt;/p&gt;

&lt;p&gt;The Angular CLI, for instance, automatically generates test files for each new component or service, promoting a unit-test-per-file approach. However, as applications grow in complexity, this method can become cumbersome and less effective. ⚡&lt;/p&gt;

&lt;p&gt;Rainer Hanekamp highlights that modern testing practices are moving towards more holistic tests that cover multiple files, aligning with industry trends and recommendations from the Angular team itself. 🌟&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Testing Terms and Types
&lt;/h2&gt;

&lt;p&gt;Before diving deeper, it's crucial to establish a common understanding of testing terminology, as definitions can vary across different teams and projects. 📖&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unit Tests&lt;/strong&gt;: Focus on individual classes or components in isolation. They interact directly with the TypeScript class methods and properties, mocking all dependencies to ensure that only the unit under test is evaluated. ✅&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Component Tests&lt;/strong&gt;: Similar to unit tests but involve interacting with the component's template via the DOM. This means simulating user interactions like clicks and inputs and asserting changes in the rendered output. 🖱️&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration Tests&lt;/strong&gt;: Broader in scope, these tests cover multiple components and services working together. They aim to verify that different parts of the application interact correctly, without mocking as many dependencies as unit tests. 🤝&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;End-to-End (E2E) Tests&lt;/strong&gt;: Simulate real user scenarios by testing the entire application flow from start to finish. They operate outside the Angular context, interacting with the application as a user would, regardless of the frontend framework used. 🔄&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Traditional Unit Testing in Angular
&lt;/h2&gt;

&lt;p&gt;The traditional unit testing approach would involve:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Isolate the Component&lt;/strong&gt;: Focus solely on component, ignoring its template and child components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mock Dependencies&lt;/strong&gt;: Replace services with mocks to ensure the test only evaluates the component's logic. 🧩&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assert Internal State&lt;/strong&gt;: Verify that methods are called with expected arguments and that internal properties behave as intended. 📋&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While this approach ensures that the component's logic works in isolation, it doesn't provide confidence that the component interacts correctly with other parts of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Integration Testing
&lt;/h2&gt;

&lt;p&gt;Integration testing addresses the limitations of unit testing by evaluating how different parts of the application work together. In the context of Angular: 🕸️&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interaction via the DOM&lt;/strong&gt;: Tests simulate user interactions such as clicking buttons and filling forms, then assert changes in the DOM. 🖱️&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real Dependencies&lt;/strong&gt;: Instead of mocking all dependencies, integration tests use real services and components where feasible, mocking only external systems like HTTP requests. 🌐&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Coverage&lt;/strong&gt;: A single integration test can cover multiple components and services, providing a broader overview of the application's functionality. 🌟&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparing Unit Tests and Integration Tests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unit Tests
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;:&lt;br&gt;
✅ &lt;strong&gt;Speed&lt;/strong&gt;: Unit tests are typically faster to execute since they focus on small, isolated units.&lt;br&gt;
✅ &lt;strong&gt;Precision&lt;/strong&gt;: They can pinpoint specific issues within a component or service.&lt;br&gt;
✅ &lt;strong&gt;Edge Case Handling&lt;/strong&gt;: Ideal for testing complex logic and handling edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;:&lt;br&gt;
⚠️ &lt;strong&gt;Tight Coupling&lt;/strong&gt;: Unit tests are closely tied to implementation details, making refactoring challenging.&lt;br&gt;
⚠️ &lt;strong&gt;High Maintenance&lt;/strong&gt;: Changes in the codebase often require updates to numerous unit tests.&lt;br&gt;
⚠️ &lt;strong&gt;Limited Scope&lt;/strong&gt;: They don't provide insights into how different parts of the application interact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration Tests
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;:&lt;br&gt;
✅ &lt;strong&gt;Realistic Scenarios&lt;/strong&gt;: By interacting with the DOM and using real dependencies, integration tests better simulate real user behavior.&lt;br&gt;
✅ &lt;strong&gt;Refactoring-Friendly&lt;/strong&gt;: Less dependent on specific implementations, allowing for easier codebase refactoring.&lt;br&gt;
✅ &lt;strong&gt;Broader Coverage&lt;/strong&gt;: A single test can cover multiple components and services, enhancing overall coverage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;:&lt;br&gt;
⚠️ &lt;strong&gt;Slower Execution&lt;/strong&gt;: Integration tests can be slower than unit tests due to their broader scope.&lt;br&gt;
⚠️ &lt;strong&gt;Complex Setup&lt;/strong&gt;: Requires a more sophisticated testing environment and handling of dependencies.&lt;br&gt;
⚠️ &lt;strong&gt;Potential for Flakiness&lt;/strong&gt;: More components interacting can introduce variability, though this is mitigated with proper tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern Testing Models and Recommendations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Testing Trophy Model 🏆
&lt;/h3&gt;

&lt;p&gt;Moving away from the traditional Testing Pyramid, the Testing Trophy model prioritizes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static Tests&lt;/strong&gt;: TypeScript type checks and linting. 🔍&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Tests&lt;/strong&gt;: The bulk of testing efforts focus here. 🤝&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-End Tests&lt;/strong&gt;: Fewer but essential tests covering critical user flows. 🔄&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt;: Reserved for complex logic and edge cases where necessary. ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Insights from the Angular Team on Testing Practices
&lt;/h2&gt;

&lt;p&gt;Jeremy Elborn, the tech lead of the Angular project, reinforces the importance of realistic and resilient tests:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You want your tests to be as representative of real life as is practical... Use the real implementation when it makes sense... Only use mocks as really a last resort when you have no other options." 🎤&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This perspective underscores the shift towards integration testing, advocating for tests that mirror actual user interactions and application behavior rather than focusing solely on isolated units. 🌍&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Action Points for Developers&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate Current Testing Tools&lt;/strong&gt;: Assess whether your existing testing setup aligns with modern practices. 🛠️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan for Transition&lt;/strong&gt;: If considering Playwright or other integration-focused tools, develop a roadmap for adoption. 🗺️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invest in Training&lt;/strong&gt;: Equip your team with the skills needed to utilize new testing frameworks effectively. 📚&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revise Testing Guidelines&lt;/strong&gt;: Update your internal documentation to reflect current best practices. 📝&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Have thoughts or experiences with modern Angular testing? Share them in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>testing</category>
    </item>
    <item>
      <title>Modernizing Angular: What's New in Angular 19</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Tue, 26 Nov 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/bndf1/modernizing-angular-whats-new-in-angular-19-4dmn</link>
      <guid>https://dev.to/bndf1/modernizing-angular-whats-new-in-angular-19-4dmn</guid>
      <description>&lt;p&gt;Angular 19 has officially arrived, and it's packed with a range of features aimed at improving developer experience, performance, and adaptability.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk you through the key highlights and what makes Angular 19 a pivotal step forward for modern web development.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Incremental Hydration: A Game Changer for SSR
&lt;/h2&gt;

&lt;p&gt;The introduction of &lt;strong&gt;incremental hydration&lt;/strong&gt; in Angular 19 takes Server-Side Rendering (SSR) to new heights. Unlike the traditional full hydration approach, incremental hydration allows the server-rendered components to hydrate only when they enter the viewport or become interactive.&lt;/p&gt;

&lt;p&gt;This results in faster load times and a better user experience. This feature is currently in &lt;strong&gt;developer preview&lt;/strong&gt;, but it’s showing great promise for optimizing the initial load and improving Lighthouse scores.&lt;/p&gt;

&lt;p&gt;To achieve this, Angular collaborated with Chrome Aurora to bring a more seamless SSR experience that is adaptable to real-world usage, focusing on &lt;strong&gt;lazy hydration&lt;/strong&gt;. Developers can now use directives like &lt;code&gt;@defer&lt;/code&gt; to control exactly when a component should be hydrated, making the process highly efficient.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideClientHydration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withIncrementalHydration&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideClientHydration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withIncrementalHydration&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@defer (hydrate on viewport) {
  &lt;span class="nt"&gt;&amp;lt;shopping-cart&amp;gt;&amp;lt;/shopping-cart&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Event Replay: Ensuring Smooth User Interactions
&lt;/h2&gt;

&lt;p&gt;A common problem in server-side rendered apps is the delay between a user interaction and the JavaScript responsible for handling that interaction being loaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event replay&lt;/strong&gt;, now enabled by default in Angular 19, captures user events during the initial load and replays them when the necessary JavaScript becomes available. This ensures a smooth user experience, even if the app is still in the process of hydrating.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;event dispatch&lt;/strong&gt; is powered by the same library used by Google Search (Wiz) and has been tested by billions of users.&lt;/p&gt;

&lt;p&gt;To enable event replay, Angular uses the following setup in the hydration provider:&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;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideClientHydration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withEventReplay&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 ensures that any user interactions that occur before the JavaScript is fully loaded are not lost, providing a seamless experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Route-Level Render Mode: Fine-Grained Control Over Rendering
&lt;/h2&gt;

&lt;p&gt;Angular 19 introduces &lt;strong&gt;route-level render mode&lt;/strong&gt;, which allows developers to specify how individual routes in an application should be rendered—either on the server, client, or prerendered during the build process.&lt;/p&gt;

&lt;p&gt;This provides fine-grained control over rendering strategy, allowing developers to optimize for performance and SEO based on the specific needs of each route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A login route can be server-side rendered for faster initial load times, while a dashboard route can be client-side rendered to enhance interactivity. This flexibility helps ensure that each part of the application is optimized for its intended use case.&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;serverRouteConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ServerRoute&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;renderMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RenderMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;renderMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RenderMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;renderMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RenderMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Prerender&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;Angular also provides an easy way to resolve route parameters during prerendering, allowing for highly customizable prerendered pages:&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;routeConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ServerRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/product/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getPrerenderPaths&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;dataService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ProductService&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;ids&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;dataService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIds&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;ids&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="nx"&gt;id&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;id&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 new interface, &lt;strong&gt;ServerRoute&lt;/strong&gt;, gives developers greater control over how content is delivered, improving both user experience and SEO.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Hot Module Replacement (HMR) Just Got Instant
&lt;/h2&gt;

&lt;p&gt;Angular 19 introduces &lt;strong&gt;instant HMR&lt;/strong&gt;, allowing styles and templates to be updated without reloading the entire app. This means that developers can see the effect of their changes immediately, making the development cycle much smoother and faster. Hot module replacement for styles is enabled by default in v19! To try HMR for templates use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NG_HMR_TEMPLATES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To disable this feature specify "hmr": false as a development server option, or alternatively use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve &lt;span class="nt"&gt;--no-hmr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Zoneless Support: Continued Evolution
&lt;/h2&gt;

&lt;p&gt;Six months ago, Angular introduced experimental &lt;strong&gt;zoneless&lt;/strong&gt; support. Since then, Angular has been iterating over the APIs and enhancing them—adding support for server-side rendering and improving the testing experience.&lt;/p&gt;

&lt;p&gt;Angular partnered with the Google Fonts team to make their application zoneless and evaluate the developer experience. The results exceeded expectations, but there are still a few more polishing touches before moving this API to developer preview.&lt;/p&gt;

&lt;p&gt;Angular 19 continues to push towards a future where zoneless operation becomes the default, significantly simplifying change detection and making applications leaner.&lt;/p&gt;

&lt;p&gt;To experiment with zoneless, use the following setup:&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;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideExperimentalZonelessChangeDetection&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;h2&gt;
  
  
  6. Linked Signals: Reactive State with Contextual Awareness
&lt;/h2&gt;

&lt;p&gt;One of the coolest new additions is &lt;strong&gt;linked signals&lt;/strong&gt;. With this feature, signals that are tied together maintain their relationships even when data updates. This is particularly useful for scenarios where multiple data points need to stay in sync dynamically. For instance, maintaining the state of a dropdown or a selection that is derived from another reactive source is now more straightforward and requires less boilerplate.&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Apple&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;Banana&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;Cherry&lt;/span&gt;&lt;span class="dl"&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;selectedOption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;linkedSignal&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;options&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;// Initial value&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectedOption&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Output: 'Apple'&lt;/span&gt;

&lt;span class="c1"&gt;// Update the selected option manually&lt;/span&gt;
&lt;span class="nx"&gt;selectedOption&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;Banana&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectedOption&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Output: 'Banana'&lt;/span&gt;

&lt;span class="c1"&gt;// Update the options array, and the linked signal will update accordingly&lt;/span&gt;
&lt;span class="nx"&gt;options&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;Kiwi&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;Pineapple&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;selectedOption&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Output: 'Kiwi'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;linkedSignal&lt;/strong&gt; API provides a simple way to express dependencies between stateful elements without resorting to effects. The new API has two forms: a simplified version (shown here) and an advanced version that gives developers access to previous values of both the linked and source signals.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Angular Material Upgrades
&lt;/h2&gt;

&lt;p&gt;Angular Material also got a significant upgrade in Angular 19. There's now a new, more customizable &lt;strong&gt;theming API&lt;/strong&gt;, allowing developers to easily override styles and tweak the look and feel of Angular Material components without diving into deeply nested CSS. Each component's documentation also includes a &lt;strong&gt;Styling tab&lt;/strong&gt; for easier reference on how to make these changes.&lt;/p&gt;

&lt;p&gt;The much-anticipated &lt;strong&gt;Drag and Drop&lt;/strong&gt; component has finally been added natively to Angular Material, allowing developers to implement sophisticated drag-and-drop interactions without relying on third-party libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s1"&gt;'@angular/material'&lt;/span&gt; &lt;span class="nt"&gt;as&lt;/span&gt; &lt;span class="nt"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;core&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$my-theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define-light-theme&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;
  &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define-palette&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$indigo-palette&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;accent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define-palette&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$pink-palette&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A400&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="o"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all-component-themes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$my-theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To customize individual components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;mat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sidenav-overrides&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'content-background-color'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;purple&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'container-divider-color'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;orange&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Migration Scripts for Signals
&lt;/h2&gt;

&lt;p&gt;Migrating your app to the new signals-based reactivity model is now simpler thanks to the built-in &lt;strong&gt;migration scripts&lt;/strong&gt;. These scripts help transition your existing inputs, outputs, and queries to use signals instead of the older Angular decorators, ensuring your app stays modern with minimal effort.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular/core:signal-input-migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Enhanced Content Security Policy
&lt;/h2&gt;

&lt;p&gt;Security is another key focus of this release. Angular 19 introduces support for &lt;strong&gt;auto CSP&lt;/strong&gt; (Content Security Policy), which automatically adds a secure CSP configuration to your application to prevent XSS attacks and other vulnerabilities by default. This is a significant step towards better security practices with less manual configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"security"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"autoCsp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. The Future of Testing in Angular
&lt;/h2&gt;

&lt;p&gt;Lastly, a major note on testing—&lt;strong&gt;Karma&lt;/strong&gt; is being deprecated in favor of more modern tools like &lt;strong&gt;Jest&lt;/strong&gt; and &lt;strong&gt;Web Test Runner&lt;/strong&gt;. By mid-2025, Karma will no longer be supported, which gives developers ample time to migrate to a more reliable testing setup that integrates smoothly with the rest of the modern Angular ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Angular 19 isn't just an update; it's a forward-thinking version that optimizes for both developer and user experience. With features like incremental hydration, event replay, route-level render modes, instant HMR, the move towards zoneless, and a plethora of productivity enhancements, this version brings Angular closer to its ideal—a modern, high-performance, developer-friendly framework.&lt;/p&gt;

&lt;p&gt;If you're looking to migrate or start a new project, Angular 19 provides a solid foundation that supports cutting-edge features and evolving best practices. Let me know what features you're most excited about, or if you have any questions about adopting Angular 19 in your projects!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>PIT, a mutation testing system for Java.</title>
      <dc:creator>JesúsB</dc:creator>
      <pubDate>Tue, 15 Feb 2022 14:22:01 +0000</pubDate>
      <link>https://dev.to/bndf1/pit-a-mutation-testing-system-for-java-3nnp</link>
      <guid>https://dev.to/bndf1/pit-a-mutation-testing-system-for-java-3nnp</guid>
      <description>&lt;p&gt;Mutation test introduces a way to find faults in our software components, verifying that our tests are able to detect unexpected behaviour. If they are able to find out the bugs caused by the mutations, we can affirm that our tests have good quality. However if defective tests are present, we should bear in mind that maybe a refactor of our tests will be needed to ensure good quality software.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://pitest.org/" rel="noopener noreferrer"&gt;PIT&lt;/a&gt;, is a mutation testing tool for JAVA, which is applicable in real world projects. PIT, is fast, robust and well integrated with other frameworks or tools, as it can be used vía Maven, Ant or terminal.&lt;/p&gt;

&lt;p&gt;Thanks to this mutation tool, we will be able to apply a huge quantity of mutation of our code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it not code coverage enough?.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; No.&lt;/p&gt;

&lt;p&gt;Nowadays it is well known by everybody the fact that software testing aims to check the expected behaviour of the software, making us to be able to detect bugs. One of the most important metrics in the industry of software development is &lt;em&gt;code coverage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But, is this a proper approach?. Should we care about something else? Why is not that enough?.&lt;/p&gt;

&lt;p&gt;We can answer all theses questions with only one answer: because although our test is &lt;em&gt;passing&lt;/em&gt; and we assume that our program works properly, having our lines covered does not mean that our &lt;em&gt;pieces&lt;/em&gt; are well tested.&lt;/p&gt;

&lt;p&gt;That's why &lt;strong&gt;mutation testing&lt;/strong&gt; can be &lt;em&gt;our friend&lt;/em&gt; - this technique will introduce defects vía small code modifications, and thanks to that and if our tests are consistent enough (so tests will fails if mutants are present), we can increase how well our software is tested.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;👉 Code Coverage is a measurement of the percentage of code lines executed during the test suite.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutation testing.
&lt;/h2&gt;

&lt;p&gt;Before jumping to the practical example, let's review the &lt;a href="http://pitest.org/quickstart/basic_concepts/" rel="noopener noreferrer"&gt;basic concepts&lt;/a&gt; of mutation testing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mutant operators:&lt;/strong&gt; The ones who transform the syntax of the program, for instance, the expression &lt;code&gt;a + b&lt;/code&gt; will be changed to &lt;code&gt;a - b&lt;/code&gt; or a operator like &lt;code&gt;&amp;lt;&lt;/code&gt; can be changed to &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutants:&lt;/strong&gt; Used to measure how good our tests are by observing and comparing the runtime behaviour of the non-mutated and mutated programs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutations:&lt;/strong&gt; We can find two types of mutations:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Killed:&lt;/strong&gt; Implies that there is at least one failing test as result of the mutation ✅.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Survived:&lt;/strong&gt; It means that zero tests detected the mutation and it must be improved ❌&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mutation testing example.
&lt;/h2&gt;

&lt;p&gt;Today we're presenting a simple example of how can we apply PIT in a project, in this case, we are going to use a &lt;a href="https://github.com/bndF1/api-discounts-test/tree/add_pit_mutation_test" rel="noopener noreferrer"&gt;PoC&lt;/a&gt; that was developed some time ago. Tests weren't perfect and coverage was not the best, and that's why it can be a good example of how we can improve our project testing quality by relying on this framework.&lt;/p&gt;

&lt;p&gt;As we have spotted before, PIT, is available for Maven, so getting started is as easy as adding the plugin to our &lt;code&gt;pom.xml&lt;/code&gt; , inside the &lt;code&gt;&amp;lt;build&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.pitest&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;pitest-maven&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.6.4&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.pitest&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;pitest-junit5-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.14&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we are able to run our test using the following instruction &lt;code&gt;mvn --fail-at-end clean test pitest:mutationCoverage pitest:report-aggregate-module&lt;/code&gt; and a report will be generated, where we will be able to inspect the mutants, the &lt;em&gt;killed&lt;/em&gt; and the &lt;em&gt;survived.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This report will be available in the &lt;code&gt;target&lt;/code&gt; folder, under the &lt;code&gt;pit-report&lt;/code&gt; a &lt;code&gt;index.html&lt;/code&gt; will be present:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bqtzhmg61ibkkesm3m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bqtzhmg61ibkkesm3m3.png" alt="Generated from pit" width="379" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can open it in our browser and investigate the possible issues present in our codebase according to PIT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faeg3dv3iaferemfzsfjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faeg3dv3iaferemfzsfjw.png" alt="Initial codebase report" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, mutation coverage reports a &lt;strong&gt;24% of mutation coverage, 27% of line coverage&lt;/strong&gt; (based on our unit test coverage report). These is the global report for our project, which for simplicity we have configured PIT to exclude configuration classes, domain entities and repositories, leaving our services as the key for the success of the testing sources.&lt;/p&gt;

&lt;p&gt;To be more concise and to exemplify how can we deal with PIT, we are going to focus on the &lt;code&gt;com.bnd.io.discounts.service.impl&lt;/code&gt; package, and the &lt;code&gt;CouponServiceImpl.java&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvs5mtcp4mcdnrkli2bjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvs5mtcp4mcdnrkli2bjb.png" alt="Report for service package." width="800" height="405"&gt;&lt;/a&gt;&lt;code&gt;Report for service package.&lt;/code&gt; ☝️&lt;/p&gt;

&lt;p&gt;As we can see in this first report, the mutation coverage for the class of interest is 0%. But which are the mutants we have to solve?. We can have more details if we navigate to the class, and check what PIT points out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nnw99c9vsp4skea3i6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nnw99c9vsp4skea3i6k.png" alt=" raw `CouponServiceImpl.java` endraw  class." width="800" height="900"&gt;&lt;/a&gt;&lt;code&gt;CouponServiceImpl.java&lt;/code&gt; class ☝️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpwm31g4lmczbw06vfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpwm31g4lmczbw06vfv.png" alt="Mutations *KILLED &amp;amp; SURVIVED.*" width="800" height="290"&gt;&lt;/a&gt;&lt;code&gt;Mutations KILLED &amp;amp; SURVIVED&lt;/code&gt; ☝️&lt;/p&gt;

&lt;p&gt;Wow, there's a lot of information here... let's start step by step. So in our service class we have some methods, this won't be extrange for anyone, repository calls, business logics, etc. And then after we executed our mutation test platform, it reports that we have some pitfalls, some methods are not even tested and the mutants, have survived.&lt;/p&gt;

&lt;p&gt;Also a list of the active mutations is present, so we can know what is being applied in our test suite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Killing the mutants...
&lt;/h3&gt;

&lt;p&gt;Having concerned the above points, now, it's time to &lt;em&gt;kill&lt;/em&gt; the mutants. So, let's go for it! 🚀&lt;/p&gt;

&lt;p&gt;To be begin with we are going to focus on the mutations annotated as SURVIVED, we will deal with the NO_COVERAGE tests later. So solve the problem with the &lt;code&gt;findAll&lt;/code&gt; we need to change our unit test &lt;code&gt;CouponServiceImpl::findAll&lt;/code&gt; method, or add a new one:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindAllShouldNotReturnNull&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;PageImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unpaged&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;After running PIT, we added the previous test to kill that survived mutant. First mutant &lt;em&gt;killed!&lt;/em&gt; 🤘&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopuyuyg2sfens84nnv3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopuyuyg2sfens84nnv3j.png" alt="First mutant killed" width="800" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's add some more tests to have everything in place, for these first three tests, which mutants survived at the beginning:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frded2ydbqzgd2pzoem6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frded2ydbqzgd2pzoem6u.png" alt="more mutants killed" width="800" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We added these two test cases to achieve the current result:&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="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindOneShouldNotReturnEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&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="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyLong&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;We still have to deal with some tests, as you can see, because we don't have even coverage for them, let's go for that!. &lt;/p&gt;

&lt;p&gt;He have to bear in mind that we don't want to have any mutant!. Moreover it's important to focus on our tests verifications, this way, PIT mutants won't be able to survive, if the framework uses mutants of type &lt;em&gt;removed call to → survived.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3q7fkspu0tc104wnqhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3q7fkspu0tc104wnqhq.png" alt="mutations" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So finally, our test cases will remain as follow in order to &lt;em&gt;kill&lt;/em&gt; all mutants present at the beginning.&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="nd"&gt;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SpringExtension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CouponServiceImplTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;COUPON_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CODE"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CouponRepository&lt;/span&gt; &lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@InjectMocks&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CouponServiceImpl&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&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;EasyRandom&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeEach&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;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;easyRandom&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;EasyRandom&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCouponCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAllByDiscountType_DiscountTypeCodeEqualsIgnoreCaseAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCouponCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@AfterEach&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifyNoMoreInteractions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unpaged&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindAllShouldNotReturnNull&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;PageImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unpaged&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&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;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyLong&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFindOneShouldNotReturnEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;())).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyLong&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testDelete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&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="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyLong&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyLong&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveShouldWorkProperly&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;savedCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedCoupon&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveShouldThrowException&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;DataIntegrityViolationException&lt;/span&gt; &lt;span class="n"&gt;exception&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;DataIntegrityViolationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Entity exists in database"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Coupon&lt;/span&gt; &lt;span class="n"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;easyRandom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))).&lt;/span&gt;&lt;span class="na"&gt;thenThrow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;DataIntegrityViolationException&lt;/span&gt; &lt;span class="n"&gt;assertThrows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;DataIntegrityViolationException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="o"&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupon&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Coupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assertThrows&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="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assertThrows&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="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Entity exists in database"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findByCouponCodeAndActiveIsTrueShouldFindProperCoupon&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCouponCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findByCouponCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findByCouponCodeAndActiveIsTrueShouldNotFindAnyCoupon&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCouponCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ANOTHER_CODE"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&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="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findByCouponCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findAllByDiscountTypeCodeAndActiveIsTrueShouldWorkProperly&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;coupons&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAllByDiscountTypeCodeAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coupons&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="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findAllByDiscountType_DiscountTypeCodeEqualsIgnoreCaseAndActiveIsTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findByCouponCodeShouldWorkProperly&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&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;Coupon&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;optionalCoupon&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="na"&gt;couponServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCouponCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COUPON_CODE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optionalCoupon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&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="na"&gt;couponRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findByCouponCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anyString&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Excerpt of the full test suite for CouponServiceImplTest&lt;/p&gt;

&lt;p&gt;What have we done in the previous test suite to achieve the a report with full succes?. We added verifications, and assertions to ensure that behaviour for our tests is correct. This way, we solved the different kind of mutants present in the report.&lt;/p&gt;

&lt;p&gt;And now this is how our &lt;code&gt;CouponServiceImpl&lt;/code&gt; report looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl2khxwm411avoworcxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsl2khxwm411avoworcxe.png" alt="Improved PIT report." width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
Improved PIT report.&lt;/p&gt;

&lt;p&gt;As you can see in the new report, after killing the mutants and dealing with the NO_COVERAGE tests, we have increased our package report statics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions.
&lt;/h2&gt;

&lt;p&gt;Having concerned all the above points, we can notice the flaws of only relying in the code coverage as metric. &lt;em&gt;Evergreen&lt;/em&gt; tests can be present, which doesn't means that we are testing properly our software components. Thanks to the evolution of mutation tests, and within the combination of the code coverage metric, we can assure good quality software.&lt;/p&gt;

&lt;p&gt;Source code for this example, can be found &lt;a href="https://github.com/bndF1/api-discounts-test/tree/add_pit_mutation_test" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sources and references:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mkyong.com/maven/maven-pitest-mutation-testing-example/" rel="noopener noreferrer"&gt;https://mkyong.com/maven/maven-pitest-mutation-testing-example/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/java-mutation-testing-with-pitest" rel="noopener noreferrer"&gt;https://www.baeldung.com/java-mutation-testing-with-pitest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pitest.org/quickstart/basic_concepts/" rel="noopener noreferrer"&gt;http://pitest.org/quickstart/basic_concepts/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pitest.org/quickstart/mutators/" rel="noopener noreferrer"&gt;https://pitest.org/quickstart/mutators/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pedrorijo.com/blog/intro-mutation/" rel="noopener noreferrer"&gt;https://pedrorijo.com/blog/intro-mutation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ulir.ul.ie/bitstream/handle/10344/5518/Cole_2009_DEMO.pdf;sequence=2" rel="noopener noreferrer"&gt;https://ulir.ul.ie/bitstream/handle/10344/5518/Cole_2009_DEMO.pdf;sequence=2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>mutationtest</category>
    </item>
  </channel>
</rss>
