<?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: Yonatan Korem</title>
    <description>The latest articles on DEV Community by Yonatan Korem (@yonatankorem).</description>
    <link>https://dev.to/yonatankorem</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%2F477151%2Fe477d324-de05-475e-b5e3-e667f3b94d68.jpg</url>
      <title>DEV Community: Yonatan Korem</title>
      <link>https://dev.to/yonatankorem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yonatankorem"/>
    <language>en</language>
    <item>
      <title>If you use Amplify and Git branches, you are going to have a bad time</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Tue, 07 Jun 2022 11:38:25 +0000</pubDate>
      <link>https://dev.to/yonatankorem/if-you-use-amplify-and-git-branches-you-are-going-to-have-a-bad-time-4ck6</link>
      <guid>https://dev.to/yonatankorem/if-you-use-amplify-and-git-branches-you-are-going-to-have-a-bad-time-4ck6</guid>
      <description>&lt;h2&gt;
  
  
  AWS Amplify is...
&lt;/h2&gt;

&lt;p&gt;A combination of tools that aim to assist with development, deployment, and hosting of your serverless application.&lt;/p&gt;

&lt;p&gt;AWS Amplify is three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It's a cloud service that includes consoles, monitoring tools, build and deploy configurations, and so on.&lt;/li&gt;
&lt;li&gt;It's a CLI tool that allows you to create Amplify environments, modify them, add resources, and manually publish if you so choose.&lt;/li&gt;
&lt;li&gt;It's a library for frontend development that simplifies using the resources in your environment like authentication, HTTP calls to your gateways, and more.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don't have to use the CLI or the library, but you would probably want to since it saves a lot of headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying applications with Amplify
&lt;/h2&gt;

&lt;p&gt;When you create an Amplify app (which contains different environments under it), you can connect it to a branch in your repository. That creates a &lt;code&gt;Hosting Environment&lt;/code&gt;. Every hosting environment can be connected to a specific &lt;code&gt;Backend Environment&lt;/code&gt;. &lt;br&gt;
When connected to a branch, Amplify will be notified whenever a code was pushed to that branch. At that point, Amplify will rebuild the frontend code in the branch and deploy it.&lt;br&gt;
If connected to a backend environment, Amplify will also redeploy the backend, based on the contents of the branch.&lt;/p&gt;
&lt;h2&gt;
  
  
  Amplify CLI tries to follow how Git works
&lt;/h2&gt;

&lt;p&gt;After you created a backend environment &lt;code&gt;dev&lt;/code&gt; and deployed it, Amplify considers it as the equivalent of Git &lt;code&gt;remote&lt;/code&gt;. When you want to work on it, you must &lt;code&gt;pull&lt;/code&gt; that environment to your local machine. You can then change it and &lt;code&gt;push&lt;/code&gt; your changes back to &lt;code&gt;remote&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you &lt;code&gt;pull&lt;/code&gt; an environment with Amplify CLI, it does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Downloads the content of the environment. The code of the lambdas, the paths defined in the gateway, the templates of the resources, etc.&lt;/li&gt;
&lt;li&gt;Creates/modifies files that say "what is the current environment in this machine". Similarly to Git, where you can &lt;code&gt;checkout&lt;/code&gt; multiple branches and your local Git will know which branch you are currently using. For example, a file called &lt;code&gt;aws-exports.js&lt;/code&gt; that contains a JSON with a lot of configurations. When your application loads, you need to pass the content of that JSON to the AWS Amplify library so it will know what endpoint to contact when your code performs a HTTP call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you &lt;code&gt;push&lt;/code&gt; an environment, Amplify CLI will first check against the &lt;code&gt;remote&lt;/code&gt; to see if there is any local modifications. If there are, it will compile a .zip with all the files required and upload it to the one currently configured.&lt;/p&gt;
&lt;h2&gt;
  
  
  That's a lot of information. I thought Amplify was supposed to make my life simpler...
&lt;/h2&gt;

&lt;p&gt;Tools that make your life easier usually do it by abstracting a lot of knowledge and technical understanding. Your Nespresso machine doesn't even show you the coffee grinds. You just put this aluminum pocket into the hole, push the button, and viola!&lt;/p&gt;

&lt;p&gt;Amplify definitely will make your life easier. But this will come with a price, and when something breaks, you must understand what it does in order to fix the problem or preemptively avoid the pitfalls.&lt;/p&gt;
&lt;h2&gt;
  
  
  The reason Git and Amplify don't play well together
&lt;/h2&gt;

&lt;p&gt;Imagine the following scenario:&lt;br&gt;
You have a &lt;code&gt;main&lt;/code&gt; Git branch and you have your &lt;code&gt;mainBE&lt;/code&gt; backend environment that currently has a lambda function &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To develop a new backend service, you branch out of &lt;code&gt;main&lt;/code&gt; to a feature branch called &lt;code&gt;feat&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git checkout main
&amp;gt; git checkout -b feat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also clone &lt;code&gt;mainBE&lt;/code&gt; to a new &lt;br&gt;
environment: &lt;code&gt;featBE&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; amplify env checkout mainBE
&amp;gt; amplify add env featBE
&amp;gt; amplify push --y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action changes &lt;code&gt;team-provider-info.json&lt;/code&gt; by introducing a new key to the object: &lt;code&gt;featBE&lt;/code&gt;. The value currently (almost) equals that of &lt;code&gt;mainBE&lt;/code&gt;. It will now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"mainBE": {
    "awscloudformation": {
      [...]
      "Region": "us-east-1",
      "AmplifyAppId": "someRandomId"
    },
    "categories": {
      "function": {
        "foo": {
          [...]
          "envVarName": "environment variable value"
        },
    }
},
"featBE": {
    "awscloudformation": {
      [...]
      "Region": "us-east-1",
      "AmplifyAppId": "someRandomId"
    },
    "categories": {
      "function": {
        "foo": {
          [...]
          "envVarName": "environment variable value"
        },
        "bar": {
          [...]
        },
    }
}

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

&lt;/div&gt;



&lt;p&gt;You then add the new lambda called &lt;code&gt;bar&lt;/code&gt; and push it to your feature environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; amplify add function
&amp;gt; amplify push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the two entries are different. featBE has details of a new lambda, while mainBE does not.&lt;/p&gt;

&lt;p&gt;You develop the new service, test it locally and deployed, and everything is done. You then merge your feature branch back into the main branch.&lt;br&gt;
Problem is, any CI/CD process that tries to deploy the backend will fail. The content of &lt;code&gt;team-provider-info.json&lt;/code&gt; under the &lt;code&gt;mainBE&lt;/code&gt; key has no definition for the &lt;code&gt;bar&lt;/code&gt; lambda.&lt;/p&gt;

&lt;p&gt;To successfully deploy &lt;code&gt;mainBE&lt;/code&gt; with the new service, you will need to pull &lt;code&gt;featBE&lt;/code&gt;, switch to &lt;code&gt;mainBE&lt;/code&gt;, and push to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; amplify env checkout featBE
&amp;gt; amplify pull --y // to overwrite the current content, assuming this is done on a different machine
&amp;gt; amplify env checkout mainBE
&amp;gt; amplify push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amplify will see the new content and update &lt;code&gt;mainBE&lt;/code&gt;.&lt;br&gt;
But, like before, this will update &lt;code&gt;team-provider-info.json&lt;/code&gt;, which means your backend environment doesn't match the code in your source control.&lt;/p&gt;

&lt;p&gt;You'll need to push this new difference into your git &lt;code&gt;main&lt;/code&gt; branch. This might sound somewhat reasonable, but if your setup uses the Git flow of having &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;testing&lt;/code&gt;, and &lt;code&gt;production&lt;/code&gt; branches (and maybe more), you'll find that this cycle of having to merge branches, merge backends, then merge again will grow exponentially with every branch in your flow.&lt;/p&gt;

&lt;p&gt;For example: let's assume we already performed all the above mentioned, but we also have staging and production environments.&lt;/p&gt;

&lt;p&gt;First, we need to merge the new feature to staging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git checkout staging
&amp;gt; git merge main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, stagingBE won't build. We need to fix this by taking the backend definition in mainBE and applying them to stagingBE&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; amplify env checkout mainBE
&amp;gt; amplify pull --y
&amp;gt; amplify env checkout stagingBE
&amp;gt; amplify push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our local branch is ahead of main (and staging)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git checkout main
&amp;gt; git commit -m "Updated Amplify setup of stagingBE"
&amp;gt; git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;main is updated, but now main and staging are not aligned&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git checkout staging
&amp;gt; git merge main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;stagingBE should be ok now, but to make sure that the deployed backend matches 100% to the source code, we will redeploy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; amplify push --y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now staging environment is ok, but we still have production to deal with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; git checkout production
&amp;gt; git merge staging
&amp;gt; amplify env checkout stagingBE
&amp;gt; amplify pull --y
&amp;gt; amplify env checkout productionBE
&amp;gt; amplify push --y
&amp;gt; git checkout main
&amp;gt; git commit -m "Update Amplify setup of productionBE"
&amp;gt; git push
&amp;gt; git checkout staging
&amp;gt; git merge main
&amp;gt; git checkout production
&amp;gt; git merge staging
&amp;gt; amplify push --y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This is the abbreviated version as most Amplify CLI commands require more information either manually entered or via headless mode.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This whole process can take at best ~15 minutes because Amplify takes time to pull and push. At worst, your CI/CD: tests, automation, deployments, etc will need to execute between after each git push in this process, which will take much much longer.&lt;/p&gt;

&lt;p&gt;In the end, no matter what you do, you will end up in a situation where the deployed backend is not based on your source code, which is not a situation you want to be in, certainly not on a regular basis.&lt;/p&gt;

&lt;p&gt;By the way, the CI/CD built into the Amplify console won't do all of this. It just takes whatever there is in your source code and tries to deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finale
&lt;/h2&gt;

&lt;p&gt;All in all, Amplify is a pretty powerful tool but seems to support a common, basic use case. If you need anything more than this, you're probably better off using other tools.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>amplify</category>
    </item>
    <item>
      <title>What Test Driven Development is really about</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Fri, 27 May 2022 17:28:56 +0000</pubDate>
      <link>https://dev.to/yonatankorem/what-test-driven-development-is-really-about-37ak</link>
      <guid>https://dev.to/yonatankorem/what-test-driven-development-is-really-about-37ak</guid>
      <description>&lt;p&gt;When I write a post, I tend to start with some definitions. What is this framework? What is the meaning of the term ?&lt;/p&gt;

&lt;p&gt;This time, we are going to mix it up. Take a moment and think about the meaning of Test Driven Development or TDD for short? What does it mean to work this way, and why would you do it?&lt;/p&gt;

&lt;h2&gt;
  
  
  This is where you take a moment...
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The answers I usually hear
&lt;/h2&gt;

&lt;p&gt;"To work TDD, you write all your tests, and then implement the code to make them pass"&lt;/p&gt;

&lt;p&gt;"TDD is about writing as many tests as you can to make sure you have 100% code coverage"&lt;/p&gt;

&lt;p&gt;"TDD means you don't have a design"&lt;/p&gt;

&lt;p&gt;"TDD is only used with low level unit tests"&lt;/p&gt;

&lt;p&gt;The answers I hear are not wrong, but in my mind, are not accurate.&lt;br&gt;
TDD is not about code coverage, though you'll probably have a high coverage with it.&lt;br&gt;
TDD is not about having as many tests as you can, though the ones you'll end up with will probably cover a lot of edge cases.&lt;br&gt;
TDD is not about having no design at all, just not having it up front. But you'll have one in the end.&lt;/p&gt;

&lt;p&gt;I think that TDD is not even about tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  TDD is about being like water.
&lt;/h3&gt;

&lt;p&gt;You've probably encountered Bruce Lee's famous quote:&lt;/p&gt;

&lt;p&gt;"Be like water, my friend"&lt;/p&gt;

&lt;p&gt;By working with TDD, you allow yourself the freedom of not being trapped in a pre-determined design that might and might not be the right now. You shape the vessel that you need your software to fill, and fill it a little. Shape it some more, fill it some more. Your code adapts to an increasingly specific vessel.&lt;/p&gt;

&lt;h3&gt;
  
  
  TDD is about thinking like an artist
&lt;/h3&gt;

&lt;p&gt;A sculpture doesn't carve the wood to the exact shape of the image they wish to create. They carve enough to get a rough form that looks right, and then carve some more. Slowly but inevitably they will get to the point where the carving is about the finest of details.&lt;/p&gt;

&lt;h3&gt;
  
  
  TDD is about knowing you are on the right path
&lt;/h3&gt;

&lt;p&gt;When you work in the TDD flow, you are always adjusting, but rarely going backwards. Each test paves just a little more of the road. You rarely go backwards because you might take a wrong turn, but you will know you went backwards right away. Allowing you to fix it, go back, and try a different direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enough philosophy for now
&lt;/h2&gt;

&lt;p&gt;TDD is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the simplest test that should break. You know what it is, because you know what the implementation is lacking.&lt;/li&gt;
&lt;li&gt;then you make it work, without braking any other existing test. It doesn't have to be the best solution. Most of the time, the most straightforward approach is best.&lt;/li&gt;
&lt;li&gt;Clean up your (tiny) mess. You can't create a giant mess in 5 minutes. It's impossible. Cleaning up a tiny mess will take a tiny bit of time.&lt;/li&gt;
&lt;li&gt;Go back to step 1 until you can't think of any more tests. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A while ago, I watched an online lecture from uncle Bob. It wasn't even about TDD, but the topic found its way there. In that lecture, somewhat off-handedly, uncle Bob said:&lt;br&gt;
"You avoid writing the tests that you know you'll need in the end. Instead, you write a test which proves that what you thought was wrong with your code, is real."&lt;/p&gt;

&lt;p&gt;That sentence helped me understand why TDD was difficult for me to do at first. I would pick the tests that were the end goal and found myself not having that short iterations, where I could feel the code evolve. I would just write the tests that proved what I needed and then I would write the code I knew I wanted to write.&lt;br&gt;
I was not like water.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emergent Design
&lt;/h2&gt;

&lt;p&gt;I once did a programming Kata that asked you to write an online API for a persistent stack. I decided to attempt it with TDD.&lt;br&gt;
I avoided this process: I'll use a MongoDB for the persistency, and I'll do the backend with ExpressJS, and so on...&lt;br&gt;
Instead, TDD meant that I first need the stack itself. Once that was made, I knew I could put that library anywhere and it was well tested. Then I built just the API and ran it locally. Now I know the API works. It returns garbage, but it works.&lt;br&gt;
Put the stack library in the logic of the API, and I got a HTTP stack going.&lt;br&gt;
The stack just used in-memory storage, so as long as the server was running, it worked.&lt;br&gt;
I wrote a persistency interface that just wrote to a JSON file. That worked well, so I just put that layer into the stack, but it broke the tests because the tests did not mock it.&lt;br&gt;
"Oh, right!" I realized that I should inject that layer into the stack so it just uses it like an array.&lt;/p&gt;

&lt;p&gt;I didn't have to spend time designing up-front too much.&lt;br&gt;
I didn't spend time on large refactoring sessions.&lt;/p&gt;

&lt;p&gt;There are endless columns, write-ups, and articles about doing "enough design", and not solving problems you don't have. In its essence.&lt;br&gt;
Same goes for tests, clean code, clean architecture, and so forth.&lt;/p&gt;

&lt;h2&gt;
  
  
  TDD is about discipline
&lt;/h2&gt;

&lt;p&gt;It is a discipline you employ that helps you. It helps you create software that is clean, testable and tested, flexible, and long lasting.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Finding the limitations of AWS Amplify</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Thu, 27 Jan 2022 10:23:45 +0000</pubDate>
      <link>https://dev.to/yonatankorem/finding-the-limitations-of-aws-amplify-200a</link>
      <guid>https://dev.to/yonatankorem/finding-the-limitations-of-aws-amplify-200a</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;This post is based on the experience I had with &lt;a href="mailto:Amplify@7.6.3"&gt;Amplify@7.6.3&lt;/a&gt; in November 2021. &lt;br&gt;
When you read this, things might be different...&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Serverless infrastructure
&lt;/h2&gt;

&lt;p&gt;AWS cloud is rich platform, full of servers, elastic searches, databases, and a lot more cloudy stuff. AWS also provides tools to build your application "serverless". That is, write your backend as functionalities and let AWS handle the deployment of it. For example, instead of creating a project for a micro-service and deploying it to a cloud server instance, you just write an AWS Lambda and tell AWS via configurations how it connects to other elements like APIs, databases, or other AWS Lambdas.&lt;br&gt;
AWS takes your Lambda and does all that infrastructure work for you.&lt;/p&gt;

&lt;p&gt;There are pros and cons for using a serverless infrastructure at large and AWS specifically. Those relates to your level of control, payment model, and so on. But for now, I'm going to leave all that aside and focus on two AWS tools for building a serverless application&lt;/p&gt;




&lt;h2&gt;
  
  
  SAM (Serverless Application Model) and Amplify
&lt;/h2&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%2Fsg9hb0czsjkdtd6u3kq5.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%2Fsg9hb0czsjkdtd6u3kq5.png" alt="Amplify and SAM logos" width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
SAM is one tool AWS provides that allows you to define, via a .yaml file, your backend. What resources you need, how they connect to one another, and so forth.&lt;br&gt;
Amplify is another tool provided by AWS. In fact, it is three tools that work together.&lt;/p&gt;

&lt;p&gt;The first tool is the Amplify CLI. The CLI gives you the ability to define your backend, similarly to SAM (since it is sort of a friendlier interface over SAM), but in a command line. You just tell Amplify that you want to create a new Lambda, that it needs access to specific global environment variables, and connect it to your DynamoDB triggers (events that the lambda will be invoked when they occur). Few button clicks, and you're good to go.&lt;/p&gt;

&lt;p&gt;Second is the Amplify console. It lets you monitor different deployments, called environments, attach it to your repo and have CI\CD that deploys your backend and frontend when you commit changes to it. It allows you to customize the build process, manage domains, control access and various other options.&lt;/p&gt;

&lt;p&gt;The third, is the Amplify library. The library is used in your frontend. It can completely configure your frontend in a couple of lines of code, since Amplify CLI created files that the Amplify library uses to configure everything. You give the library the config file and off you go adding authentication and API calls to your frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amplify CLI and GIT
&lt;/h2&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%2F1qed6rjh7hfgerjnowkp.jpeg" 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%2F1qed6rjh7hfgerjnowkp.jpeg" alt="Amplify environment switching diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Amplify manages the project in the top level as an "Application". Under that, there could be multiple backend environments, and multiple frontends - each deployed from a connected repository branch. You push your changes into your github repo, under the "testing" branch and Amplify will redeploy the front end that is connected to that branch, and update the backend that is connected to that frontend.&lt;/p&gt;

&lt;p&gt;The use of multiple environments tries to create a similar way of work as GIT. You can checkout backend environments. Switch between checked out environments. Push (deploy) and pull to your local machine.&lt;br&gt;
You can even create new environments based on the current state of others (i.e. &lt;code&gt;git checkout -b ...&lt;/code&gt;)&lt;br&gt;
You perform all these actions via the Amplify CLI tool with commands like &lt;code&gt;amplify env checkout ENV_NAME&lt;/code&gt; or &lt;code&gt;amplify init&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  "When this baby hits 88 mph, you're gonna see some serious shit"
&lt;/h2&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%2Fbcbrfxvzh03oct2oix73.jpeg" 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%2Fbcbrfxvzh03oct2oix73.jpeg" alt="Doc and Marty" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
We've been working on a web application that required fairly straightforward backend: a database, some HTTP methods, authentication, and that's about it. Then, the company had an idea of what direction the product will take and it involved doing a lot of new stuff. We wanted to take a couple of days to see if the idea is technologically viable. We knew that we are going to work fast, encounter a lot of unknowns, and push the boundaries of our knowledge. The hope was that in one week, we'll be able to show the company some serious shit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&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%2Fnobyj3b8ay5wyxlka6c2.jpeg" 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%2Fnobyj3b8ay5wyxlka6c2.jpeg" alt="Dev team" width="275" height="183"&gt;&lt;/a&gt;&lt;br&gt;
We were a number of developers, split into three different areas of responsibilities.&lt;br&gt;
One team focused on creating a custom authentication flow with AWS Cognito.&lt;br&gt;
The second focused on mostly frontend exploration, with some need for storage and a way to access it.&lt;br&gt;
The third focused on integration with a third party tool that required lambdas that would be triggered by AWS on certain events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Amplify is powerful
&lt;/h2&gt;

&lt;p&gt;Setting up a new Amplify application, hooking it up to our repo, creating a backend environment, deploying the front end, and connecting it to that backend was a snap. &lt;br&gt;
Adding an API gateway with a specific path, along with a lambda and dynamoDB was a single command in CLI.&lt;br&gt;
Hats off to AWS, because it was amazingly simple and easy.&lt;br&gt;
It even managed the CI/CD fairly well. When we pushed changed to the repo, it would update the backend and deploy the frontend all on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we struggled with Amplify
&lt;/h2&gt;

&lt;p&gt;We had three teams, so naturally we had four branches: main and one for each team. The way Amplify works with your repo, and allows you to switch environments, is by having files that define the deployment, and those that define the current environment you are working on. For example, the actual code of your lambda is stored. The file &lt;code&gt;aws-exports.js&lt;/code&gt; that contains information about the active environment is not stored.&lt;br&gt;
Thing is, git and amplify don't actually work together. When you change your branch, the files that are not tracked by git remain the same. You are still on the old environment, but now Amplify sees that your local backend setup is different than what is in the environment.&lt;br&gt;
We tried working the way AWS recommends but it didn't take long until the CLI seemed to go crazy.&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%2Ful13fg203v1f7jvkr3em.jpeg" 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%2Ful13fg203v1f7jvkr3em.jpeg" alt="Confusion" width="272" height="185"&gt;&lt;/a&gt;&lt;br&gt;
I would try to change my environment and it would ask for authentication again, even though I just did. I would pick using access keys and nothing would happen.&lt;br&gt;
If I picked using an AWS profile, it would error out with some error that did not explain itself well.&lt;/p&gt;

&lt;p&gt;Because you can deploy your local changes to the cloud without going through the repo, it's easy to collide with others working on the same environment. Naturally, we'd want to have different environments, but when the CLI often went crazy we avoided it and tried to work safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Amplify plain does not work
&lt;/h2&gt;

&lt;p&gt;The moment we started working on the custom authentication, we encountered a major boundary of Amplify.&lt;br&gt;
AWS custom authentication requires connecting lambdas to several Cognito triggers. Amplify CLI just does not support it. We had to manually connect everything via the Cognito console.&lt;/p&gt;

&lt;p&gt;We had an issue that blocked us for a whole day (which was about 20% of the total time allocated for us). We had a working API Gateway that connected to a lambda, which accessed a DynamoDB table. We needed another one. Created a new path in the API, created a new lambda and DynamoDB, and so on. Everything looked exactly like the existing infrastructure. Only the new stuff didn't work. We would get CORS error all the time. Tried to check the CORS settings, authentication settings, it all seemed ok. Tried to do the process again and again. Tried the create a new API Gateway. Nothing worked...&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%2Fjb2pjpnojjopufa1ifd6.jpeg" 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%2Fjb2pjpnojjopufa1ifd6.jpeg" alt="Anger from the movie Inside" width="225" height="225"&gt;&lt;/a&gt;&lt;br&gt;
Only later one of the developers noticed that the API gateway resource did not update correctly. Only when we created a new environment and the API was reconfigured prior to being deployed, that the issue was finally fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The last day
&lt;/h2&gt;

&lt;p&gt;As these things go, somehow everything managed to cross the finish line at the very last minute. But we all felt that we succeeded in spite of Amplify.&lt;/p&gt;

&lt;p&gt;Part of the team was more familiar with SAM, and by the end of it they said that SAM, while being more complex and leave a lot of the responsibility with the developers, is probably the better tool since it give you the power to configure everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Amplify is a good tool when your requirements match its capabilities. You could setup a live web page with login capabilities, that stores and loads data via a RESTful API, in literally a few minutes. If you need anything more than that, Amplify is limited and you might find yourself struggling to manage some elements via the AWS console and some via Amplify.&lt;/p&gt;

&lt;p&gt;Amplify CLI is a great tool in concept, but we felt it was too unstable and unpredictable. But if you only use a single environment, you won't encounter the most troubling aspects of it.&lt;/p&gt;

&lt;p&gt;The Amplify library is pretty good! My only major issue with it is that you have to use Amplify CLI with it or it won't work.&lt;/p&gt;

&lt;p&gt;In the end, it's the question of what would you rather have: a big toolbox that allows you to build and control whatever you want, or a pocket knife that is great when you need to cut something but you would have a bad time trying to hammer a nail with it.&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%2F3l4a9s4g4ewpjoxrse67.jpeg" 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%2F3l4a9s4g4ewpjoxrse67.jpeg" alt="Boyfriend looking at other girl meme" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>cloud</category>
      <category>serverless</category>
    </item>
    <item>
      <title>"Single Responsibility" will make your code better without you even noticing</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Tue, 02 Nov 2021 11:12:07 +0000</pubDate>
      <link>https://dev.to/yonatankorem/single-responsibility-will-make-your-code-better-without-you-even-noticing-3ep7</link>
      <guid>https://dev.to/yonatankorem/single-responsibility-will-make-your-code-better-without-you-even-noticing-3ep7</guid>
      <description>&lt;p&gt;This column is not about what is the "Single Responsibility Principle". There are a lot of other places you can read all about it. &lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" rel="noopener noreferrer"&gt;Robert Martin's blog is a good place to start&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is also not about how strict you should be applying single responsibility.&lt;/p&gt;

&lt;p&gt;This column is about how following this principle will make your code better. Your code will be shorter, simpler, maintainable, testable, and various other adjectives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercise in imagination
&lt;/h2&gt;

&lt;p&gt;Imagine a hamburger cookbook. It tells you what you need to make the patty, how to grill it, how to make and bake the buns, and how to put it all together. Now imagine that it is all on the same page.&lt;br&gt;
The ingredients list is long and difficult to understand what goes in the bun and what in the burger.&lt;br&gt;
The preparation guide tells you how to do everything combined. The steps jump between the patty and the bun - it's time saving because while the bun bakes, the next couple of steps is about the burger. But it is also comprised of dozens of steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP Makes your code easier to follow
&lt;/h2&gt;

&lt;p&gt;Why do cookbooks separate the items? It is much better to do all at same time, plus it saves paper because there is less white spaces. They separate it to make each part easier to follow and understand. It also makes it harder to confuse the ingredients.&lt;/p&gt;

&lt;p&gt;Your class/function/file becomes simpler to follow because it focuses on one subject. You can feel safe that your backend API controller only handles defining the API and validating the inputs. Nothing more and nothing less.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP makes your code shorter
&lt;/h2&gt;

&lt;p&gt;With the same example of the cookbook: instead of a single recipe taking three pages, you get two parts - each taking two pages. Combined you might end up with more pages, but each component of the hamburger is shorter.&lt;/p&gt;

&lt;p&gt;In the cookbook, though it has more pages, it is easy to find what you are looking for. It has a structure and logic to it.&lt;/p&gt;

&lt;p&gt;True, you will end up with more files in your repository. But each one is shorter, and the entire thing is organized and structured so anything you need, you know where to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP will make it easier to debug problems
&lt;/h2&gt;

&lt;p&gt;If you use the bad cookbook to make your burger and confuse the seasoning between the bun and patty, you could get a salty hamburger and tasteless bun, because a portion of the salt that was meant for the bun is in the patty.&lt;br&gt;
If you use the normal cookbook, you might get a poorly seasoned hamburger, but it will not impact how the bun ended up.&lt;/p&gt;

&lt;p&gt;Problems are easier to find because they are contained.&lt;br&gt;
Your API responded with an error. It responded, so the controller got the message. You look at the body and all the fields have the correct type and length. Like before, the controller only defines the API and validates inputs.&lt;br&gt;
Together that automatically means there is no reason to investigate the controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP makes your code easier to unit test
&lt;/h2&gt;

&lt;p&gt;When your class has a single responsibility, it depends on other components for any other functionality it requires.&lt;br&gt;
The class handles some logic, which means it does not handle creation of its dependencies. Hence, your class gets the dependencies from outside.&lt;/p&gt;

&lt;p&gt;When your class does that, it becomes easier to inject fake dependencies - which is exactly what you need to unit test.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP helps naming things
&lt;/h2&gt;

&lt;p&gt;From the function level, to your folder structure, having "things" be responsible for one thing makes it easier to name them.&lt;/p&gt;

&lt;p&gt;A component that does one specific thing, can have an equally specific name, at the same abstraction level.&lt;br&gt;
When the class encapsulates HTTP calls to get and set &lt;code&gt;Contact&lt;/code&gt; from a DB, it becomes clear that it should be named &lt;code&gt;ContactGateway&lt;/code&gt;&lt;br&gt;
The folder that contains all the components and logic that handles the login page, would probably be named &lt;code&gt;LoginModule&lt;/code&gt;&lt;br&gt;
When your library handles thread pools using a SQL server, it would probably be named &lt;code&gt;SqlThreadPool&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP helps following established design patterns
&lt;/h2&gt;

&lt;p&gt;Now that your class does one thing, and is named to match, you'll find yourself following established design patterns. When you separate the modeling of a graph from the algorithm that traverses it, you end up with the &lt;code&gt;Strategy&lt;/code&gt; class and the context it operates on.&lt;br&gt;
The graph is comprised of individual nodes, each encapsulating its data and logic. Congratulations! You are using the &lt;code&gt;Composite&lt;/code&gt; design pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP makes your code readable
&lt;/h2&gt;

&lt;p&gt;When you combine all of the above, you get code that is shorter, highly focused, with lower cyclomatic complexity. Plus, the code is easy to find.&lt;/p&gt;

&lt;p&gt;These are all things that every developer will appreciate. Think of the times where you had to juggle multiple trails of thought to try and figure out why something does not work right.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP makes your project better
&lt;/h2&gt;

&lt;p&gt;Because it helps generate code that is easier to maintain, test, refactor, and extend.&lt;br&gt;
Maintainable code is critical for allowing your project to continue consistent and fast development.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;SRP helps you make better hamburgers.&lt;/p&gt;

</description>
      <category>design</category>
      <category>programming</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Designing a Robust HTTP Error Handling System in Angular</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Tue, 12 Oct 2021 06:25:02 +0000</pubDate>
      <link>https://dev.to/yonatankorem/designing-a-robust-http-error-handling-system-in-angular-b2e</link>
      <guid>https://dev.to/yonatankorem/designing-a-robust-http-error-handling-system-in-angular-b2e</guid>
      <description>&lt;h2&gt;
  
  
  A Story Told Over and Over
&lt;/h2&gt;

&lt;p&gt;I've been a part of a number of different Angular front end projects in the past years. In every one of those projects, there came a point in time where we were asked to implement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When a call to the backend fails due to authentication errors (401), route the user to the login page.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It didn't take long until another use case arrived:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When a call to the backend fails, alert the user of the failure with a generic "The requested operation failed".&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Soon after, another use case:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When the user tries to get the information of an existing contact, and the operation fails, display a toast "Contact not found".&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This would escalate further when the same operation failure would need a different error handling when done from different components. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If the user tries to edit a contact and the error is 404 (not found), then toast "Contact not found, would you like to create one?" along with a "Create" button.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've seen, and been involved with the design decisions that attempted to handle these use cases. Here are a couple of case studies.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Idealized
&lt;/h3&gt;

&lt;p&gt;This approach tried to contextualize the error itself. An interceptor would wrap the error and give it a default message. The error would not be handled by the different layers. Instead each one could attach a new message. When a specific layer would want to "finish" handling the error, it would manually call an error handling service that would pick the appropriate message and display it.&lt;/p&gt;

&lt;p&gt;In theory, this should have worked and support all the different use cases. It did, but it was complex. Too complex. Developers would not use it correctly, and defects would pop up. The gap between the theory described, and the practicality of it was tremendous.&lt;/p&gt;

&lt;p&gt;Plus, it still required someone, somewhere, to handle the error. If no one does, all this mechanism does nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Simplistic
&lt;/h3&gt;

&lt;p&gt;This approach went the complete opposite way. Have a simple mechanism: an interceptor would have a hard coded black list of errors it would always handle, like authentication issues that it would reroute. It also had a hard coded white list of URLs and error codes it would not handle at all.&lt;/p&gt;

&lt;p&gt;This design was good, but it left large gaps. Any change to the URLs, any change to the possible error codes returned, would mean one of those hard coded lists would need to be manually updated. It also still didn't solve the issue with errors not being caught at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Need to Get Back to Basics
&lt;/h2&gt;

&lt;p&gt;If we look at the requirements fresh, we can see that the basic message of "The requested operation failed", is the message we would want to display if no one else handled the error. That means that we have to first let all components and services the opportunity to handle the error and only if none of them does, then we should display the default message.&lt;/p&gt;

&lt;p&gt;Here lies the root of the problem with all the designs I've encountered: An interceptor is the first component that has the opportunity to handle the error, not the last one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the ErrorHandler
&lt;/h2&gt;

&lt;p&gt;Angular has a built in service called &lt;code&gt;ErrorHandler&lt;/code&gt;. Any error that your app does not handle will reach this service. The Angular service just outputs the exception to the console. If you want to display a toast for specific unhandled errors, all you need to do is:&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="c1"&gt;// my-error-handler.service.ts&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyErrorHandler&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with the exception&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// app.module.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyErrorHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difficult part here is that ALL uncaught exceptions end up here, not just HTTP ones. Luckily, we can differentiate between them with this:&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// Handle HTTP errors&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cover our fallback use case so no error goes unhandled, but what about errors we want to always handle the same way?&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the HTTP Interceptor
&lt;/h2&gt;

&lt;p&gt;While the &lt;code&gt;ErrorHandler&lt;/code&gt; is our last line of defense, the interceptor is our first. That makes it ideal to handle the authentication errors which we would want to re-route back to a login page.&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="c1"&gt;// my-interceptor.ts&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyInterceptor&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;HttpInterceptor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// route if the error is an authentication error&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// app.module.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyErrorHandler&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTTP_INTERCEPTORS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyInterceptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;multi&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="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  For Everything in Between
&lt;/h2&gt;

&lt;p&gt;We took care of the first two requirements. Let's handle this next:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When the user tries to get the information of an existing contact, and the operation fails, display a toast "Contact not found".&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our instinct might be to let the service that performed the HTTP request will handle it within the scope of the observable.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// toast the appropriate message&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;Which is OK until the last requirement appears:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If the user tries to edit a contact and the error is 404 (not found), then toast "Contact not found, would you like to create one?" along with a "Create" button.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need a way for all the parties involved to have the chance to say "please toast this message" and only when everyone finished, then decide what to show.&lt;/p&gt;

&lt;h2&gt;
  
  
  RxJS handles all your needs
&lt;/h2&gt;

&lt;p&gt;RxJS has two operators that we need to implement our solution:&lt;br&gt;
CatchError and Finally.&lt;/p&gt;

&lt;p&gt;CatchError is triggered when an error happens in the stream, and it must return another observable, or throw an error.&lt;/p&gt;

&lt;p&gt;Finally is triggered when the stream completes, or when it errors.&lt;/p&gt;

&lt;p&gt;The important part here is the order of them being called when the observable is constructed with multiple of both.&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="c1"&gt;// serviceA&lt;/span&gt;
&lt;span class="nf"&gt;getFromBackend&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// some service level cleanup)&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// serviceB&lt;/span&gt;
&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFromBackend&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// log something&lt;/span&gt;
         &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// componentC&lt;/span&gt;
&lt;span class="nf"&gt;onButtonClick&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// set the button to disabled&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;serviceB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;({})),&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
         &lt;span class="c1"&gt;// do something with the value &lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// set the button back to enabled&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the backend returns an error, the order of calls will be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;catchError - serviceB&lt;/li&gt;
&lt;li&gt;catchError - componentC&lt;/li&gt;
&lt;li&gt;finally - serviceA&lt;/li&gt;
&lt;li&gt;finally - componentC&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is exactly what we need - anyone that wants to do something with the error does it first. Then, in a "finally" operator we could trigger the toast service. (Thank you to &lt;a class="mentioned-user" href="https://dev.to/elirans"&gt;@elirans&lt;/a&gt; for the idea)&lt;/p&gt;

&lt;p&gt;We don't want any element that wants to toast, to rely on someone else triggering the toast service. Anyone that wants to toast will need both the catchError and finally operators. Trouble is, there will be a lot of repeated code, and the risk of missing some crucial part of the behavior is high.&lt;/p&gt;

&lt;p&gt;Because of that, we're going to create our own pipe operator!&lt;/p&gt;

&lt;h2&gt;
  
  
  It's really not that scary
&lt;/h2&gt;

&lt;p&gt;A pipe operator is just a function that takes a stream as an input and returns a stream as an output.&lt;br&gt;
In reality, most pipe operators are factory methods that return a pipe operator. We'll do just that.&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="c1"&gt;// toastOnError.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toastToConsoleOnError&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;messageToToast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;errorToToast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;toast&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="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messageToToast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;errorToToast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="p"&gt;}),&lt;/span&gt;
         &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorToToast&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;errorToToast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorToToast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="nx"&gt;errorToToast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// since we save the reference to the error object, any future access to this field will get a null value.&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// serviceB&lt;/span&gt;
&lt;span class="nf"&gt;findContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&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="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFromBackend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&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;toastToConsoleOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Contact not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// componentC (Component level toast)&lt;/span&gt;
&lt;span class="nf"&gt;onEditRequest&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;serviceB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findContact&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;searchTerm&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;toastToConsoleOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Contact not found. Would you like to create one?&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// componentD (Service level toast)&lt;/span&gt;
&lt;span class="nf"&gt;onQuickViewRequest&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;serviceB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findContact&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the specific implementation above has its weaknesses (for example, if one element uses the operator, and another does not, you'll get two toasts), the core idea is the same and you can adjust the implementation for your needs: Maybe you need a way to mute the toasts, or maybe you want to toast if there is a condition met on the error.&lt;/p&gt;

&lt;p&gt;With this new operator, if someone wants to toast they will, unless someone with more context also wants to toast, and we won't have two toasts popping up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our journey complete
&lt;/h2&gt;

&lt;p&gt;We broke down the problem into three sections, and deal with each using a different mechanism:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a HTTP interceptor for handling errors that is always the same.&lt;/li&gt;
&lt;li&gt;Use the Angular ErrorHandler as a failsafe to catch any error that is not handled elsewhere.&lt;/li&gt;
&lt;li&gt;Create a pipe operator that uses catchError and finally to allow elements to store/overwrite the toast to display, and display it in the finally operator.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>design</category>
    </item>
    <item>
      <title>Why I fell out of love with inheritance</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Wed, 18 Aug 2021 08:32:12 +0000</pubDate>
      <link>https://dev.to/yonatankorem/why-i-fell-out-of-love-with-inheritance-1fh</link>
      <guid>https://dev.to/yonatankorem/why-i-fell-out-of-love-with-inheritance-1fh</guid>
      <description>&lt;h2&gt;
  
  
  A tale of growing up, and realizing your heroes have flaws
&lt;/h2&gt;

&lt;h4&gt;
  
  
  The Beginning
&lt;/h4&gt;

&lt;p&gt;Almost nine years ago, when I was near the end of my BSc, I was sure that inheritance is the greatest thing an OO programmer has in their arsenal of tools. During most of my studies, we were taught the principles of OOP, why interfaces are important, and how inheritance is a great tool for reusing code, abstracting your code and design, and what a generally powerful tool it is. That's not incorrect. It is good for those things. But it took me a few years to realize that when I idolized those concepts, I tended to use inheritance where it shouldn't have been used.&lt;/p&gt;

&lt;p&gt;We were shown the example where inheritance fails:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A circle, and an ellipse. Which is the abstraction of which?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But we were also told examples like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;employee&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
  &lt;span class="nf"&gt;generateHoursReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;assignVehicle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Manager&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;assignEmployee&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CEO&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Manager&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;When you think about it in terms of technical abstraction, it makes perfect sense. A CEO is a manager. A Manager is an employee. A CEO is an employee.&lt;/p&gt;

&lt;p&gt;All three share the basic functionality of the employee, and each extends those functions, and/or add new functionality. This solution is exactly the solution I would come up with, before I started to internalize the first of the SOLID principles, and learned more about the delegation/composition pattern.&lt;/p&gt;

&lt;h4&gt;
  
  
  Single Responsibility Principle
&lt;/h4&gt;

&lt;p&gt;Robert C. Martin wrote about the SOLID principles in the &lt;a href="https://books.google.com/books?id=0HYhAQAAIAAJ&amp;amp;redir_esc=y" rel="noopener noreferrer"&gt;Agile Software Development&lt;/a&gt; and the definition was that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A module (class, interface, package,…) should do only one thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was later refined by Martin to state&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A module should have only one reason to change&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I won't go into details on the meaning of the refinement, and you'll find a lot written about it already, especially in &lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" rel="noopener noreferrer"&gt;Martin's own blog&lt;/a&gt;. But let's apply this principle to our Employee example.&lt;/p&gt;

&lt;p&gt;Looking at the Employee class, we can see that it handles three things: financials, motor department, and HR subjects. To discuss it with Martin’s refinement in mind, there are three departments that might give a reason to change something in the employee class.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Payroll department decides to update the way they calculate the salary of employees.&lt;/li&gt;
&lt;li&gt;Motor department wants to make it so only managers can be assigned vehicles due to budget cuts.&lt;/li&gt;
&lt;li&gt;HR replaced their reporting system and require a new template for the hourly report.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It took me a while to understand why this is even an issue. I would think that the &lt;code&gt;Employee&lt;/code&gt; class knows how to handle the specifics for its own level, and once you travel up the chain, the &lt;code&gt;Manager&lt;/code&gt; will probably override the things it needs, and so on.&lt;/p&gt;

&lt;p&gt;But...&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You implement the &lt;code&gt;pay&lt;/code&gt; (finance) and &lt;code&gt;generateHoursReport&lt;/code&gt; (HR), and quickly notice a piece of repetitive code between the two that counts the total amount of hours. You’ve read about code smells and you want to be DRY, so you refactor it out to a third, private method: &lt;code&gt;getTotalHours&lt;/code&gt;.&lt;br&gt;
Months later, HR wants to change the report so that it shows the remaining hours. The new developer is not familiar with the system and changes &lt;code&gt;getTotalHours&lt;/code&gt; so that it returns the value times -1. &lt;code&gt;generateHoursReport&lt;/code&gt; now works as expected, but &lt;code&gt;pay&lt;/code&gt; is now very broken. The change requested in one method affected the other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We have this structure, and now we want to introduce a new type of employee: &lt;code&gt;Contractor&lt;/code&gt;. The contractor needs to generate a hours report, but not to your system, and your system does not need to pay him because you pay his company. You want to have Contractor extend Employee, but the new class should not include a pay method. Maybe have Employee extend the Contractor, but an employee is not a contractor.&lt;br&gt;
So you start to introduce base classes that do not actually represent anything, it’s just a “base” class to extend from.&lt;br&gt;
I promise you this: a year later, your simple inheritance structure became a huge inheritance tree, with classes like &lt;code&gt;RootEmployee&lt;/code&gt;, &lt;code&gt;ContractorWithVehicle&lt;/code&gt;, and &lt;code&gt;TechnicalManager&lt;/code&gt; that cannot have any employees.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;How can we change &lt;code&gt;Employee&lt;/code&gt; and its structure to avoid these issues? How can we design the system to support all of these departments?&lt;/p&gt;

&lt;p&gt;One way to do it, is to compartmentalize the logic to three different parts, and change the design to one of composition &amp;amp; delegation. This creates four pieces of code, each responsible for one topic: HR, Payroll, Motor, and the Employee that composites the three and interfaces with them by providing information for the relevant employee. With this modification, our design now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SalaryEmployeePayment&lt;/span&gt; &lt;span class="n"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IReportFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;generateHoursReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HourlyEmployeeReportFactory&lt;/span&gt; &lt;span class="n"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;IReportFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;generateHoursReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IVehicleDecorator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;assignVehicle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeasingVehicleDecorator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;assignVehicle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;paymentStrategy&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IReportFactory&lt;/span&gt; &lt;span class="n"&gt;reportFactory&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IVehicleDecorator&lt;/span&gt; &lt;span class="n"&gt;vehicleDecorator&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IReportFactory&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IVehicleDecorator&lt;/span&gt; &lt;span class="n"&gt;v&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="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paymentStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;generateHoursReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reportFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateHoursReport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;assignVehicle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vehicleDecorator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assignVehicle&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SalaryEmployeePayment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HourlyEmployeeReportFacotry&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LeasingVehicleDecorator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagerPayment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HourlyEmployeeReportFactory&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LeasingVehicleDecorator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ceo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagerPayment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HourlyEmployeeReportFactory&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CompensationVehicleDecorator&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;With this separation, we only need one &lt;code&gt;Employee&lt;/code&gt; class, and the inheritance is provided by giving it different behaviors for each part.&lt;br&gt;
Replacing the behavior of one element has no effect on the other parts of the system, which is basically the core idea behind the single responsibility principle.&lt;br&gt;
Inheritance may still be used, but it will be applied to a single element of behavior, and will not cause the &lt;code&gt;ContractorWithVehicle&lt;/code&gt; type of problem or create a need for &lt;a href="https://en.wikipedia.org/wiki/Multiple_inheritance" rel="noopener noreferrer"&gt;multiple inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Composition &amp;amp; Delegation
&lt;/h4&gt;

&lt;p&gt;Composition does not necessarily mean delegation. The composition design pattern describes a way to define an object by its connection to other objects: &lt;code&gt;TreeNode&lt;/code&gt;, or &lt;code&gt;ListNode&lt;/code&gt; are the most basic of examples for it.&lt;/p&gt;

&lt;p&gt;Delegation does not necessarily mean composition. Delegation (as is implied by the name) can be used when we want our object to fulfill a specific API, without being connected to the implementation of it.&lt;/p&gt;

&lt;p&gt;The above example, and plenty of others like it (like &lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance#Example" rel="noopener noreferrer"&gt;GameObject&lt;/a&gt;) show how using inheritance can sometimes lead to poor design, especially when the inheritance is already implemented and more, different usages appear.&lt;/p&gt;

&lt;p&gt;The composition design has more benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It makes our design more testable, since each part of the code can be tested completely separately&lt;/li&gt;
&lt;li&gt;It makes our design more aligned with the Liskov Substitution Principle&lt;/li&gt;
&lt;li&gt;It makes our design more aligned with the Interface Segregation Principle&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Composition and Delegation together, make us look at our classes in terms of behaviors, and not as only “X is a Y”.&lt;/p&gt;

&lt;h4&gt;
  
  
  Wrap up
&lt;/h4&gt;

&lt;p&gt;I want to stress one final thing about “loving” a concept. In the past, thinking that a specific design is &lt;strong&gt;best&lt;/strong&gt; often got me to a place where I tried to fit the problem to the design, and not the other way around. &lt;/p&gt;

&lt;p&gt;Remember that you have more than a hammer. Don't see your problems as only nails.&lt;/p&gt;

</description>
      <category>design</category>
      <category>oop</category>
    </item>
    <item>
      <title>Migrating your web application to NGXS state management</title>
      <dc:creator>Yonatan Korem</dc:creator>
      <pubDate>Mon, 16 Aug 2021 07:53:54 +0000</pubDate>
      <link>https://dev.to/yonatankorem/migrating-your-web-application-to-ngxs-state-management-33je</link>
      <guid>https://dev.to/yonatankorem/migrating-your-web-application-to-ngxs-state-management-33je</guid>
      <description>&lt;h1&gt;
  
  
  What's state management?
&lt;/h1&gt;

&lt;p&gt;State management is the concept of having the state of your application be decoupled from the logic or UI of your application, but also not having multiple copies of your data. That saves you from having to sync your data, and allows for an application that will be more consistent and have less defects.&lt;/p&gt;

&lt;p&gt;One of the most popular state management patterns is &lt;em&gt;REDUX&lt;/em&gt; which emphasizes reactive programming. With this pattern, you have a "single source of truth" and your application observes that data. When it changes, your application reacts to that change as needed by the specific component.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's NGXS?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.ngxs.io/" rel="noopener noreferrer"&gt;NGXS&lt;/a&gt; is a front end state management framework for Angular. It's similar to the popular NgRx framework, but offers a lower learning curve, and with it your code contains less boilerplate code - which is something that plagues NgRx.&lt;/p&gt;

&lt;p&gt;In NGXS there are three basic concepts to understand before you start integrating it to your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions
&lt;/h3&gt;

&lt;p&gt;The action is an object that represents a single notification to the store that something happened. For example, an action like &lt;em&gt;SaveUserPreferences&lt;/em&gt; would be dispatched when the user clicks on the "Save" button.&lt;br&gt;
An action also has an optional payload which will be readable by any action handler.&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;class&lt;/span&gt; &lt;span class="nc"&gt;SaveUserPreferences&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Preferences] UserLevel.Save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Preferences&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;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;The state class is responsible for handling the partial state of the application. It contains an instance of the state model, and action handlers for whichever actions you want.&lt;br&gt;
The action handlers can modify the state model and/or dispatch more actions.&lt;/p&gt;

&lt;p&gt;The first part is the state model:&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;PreferencesStateModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;userLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;systemLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Preferences&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second part is the state itself:&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;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PreferencesStateModel&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PreferencesState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The name can be used to get the state&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// The initial value of the state&lt;/span&gt;
        &lt;span class="na"&gt;userLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="na"&gt;systemLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PreferencesState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;prefService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PreferencesService&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="nd"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SaveUserPreferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;savePreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;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;prefService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&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;tap&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LogSuccessfulSave&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;h3&gt;
  
  
  Store
&lt;/h3&gt;

&lt;p&gt;The store is an injectable singleton that will be the interface of your application with the state. Your template will observe parts of the state, and your logic will dispatch actions through it.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PreferenceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;state$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PreferenceStateModel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&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;Store&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;clickHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SaveUserPreferences&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;preferences&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Introduction over, let's get to work
&lt;/h1&gt;

&lt;p&gt;tl;dr - &lt;a href="https://github.com/MoistJohn/TourOfHeroes-NGXS/tree/master/src" rel="noopener noreferrer"&gt;The end result&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There I was, a new framework all to myself, but nothing to do with it yet. Cue cartoon lightbulb: instead of doing a bunch of work just to setup some mock website, instead I could migrate something to NGXS. What better for an Angular framework than the Angular tutorial - &lt;a href="https://angular.io/generated/live-examples/toh-pt6/stackblitz.html" rel="noopener noreferrer"&gt;Tour of Heroes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The app has three pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Dashboard
Containing a partial list of heroes and a search bar to find a hero by name.&lt;/li&gt;
&lt;li&gt;The Heroes
Containing the list of all heroes, the ability to delete them, and an input field to add new heroes to the database.&lt;/li&gt;
&lt;li&gt;The Hero
Displays the information of a specific hero, with the option to change it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each component has its own data, each loads "from the server" upon loading, each using the &lt;strong&gt;HeroService&lt;/strong&gt; to perform actions.&lt;br&gt;
One page even uses the Angular &lt;strong&gt;ActivatedRoute&lt;/strong&gt; and &lt;em&gt;Location&lt;/em&gt; objects to read the query parameters, and to navigate to other URLs.&lt;/p&gt;

&lt;p&gt;I wanted to reach the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All data of the website is contained within the NGXS store.&lt;/li&gt;
&lt;li&gt;All components use only Actions for the actions the user can perform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My method is simple: work incrementally, and continuously test against the current implementation. I will take one component and slowly rip out its data and service usage, and replace it with the store and its actions.&lt;/p&gt;
&lt;h1&gt;
  
  
  How did it go?
&lt;/h1&gt;

&lt;p&gt;I picked the Heroes page, since it is the most straightforward. A list of heroes, add a hero, and delete a hero.&lt;br&gt;
Originally, when the component loads, it performs "GET" via a service, and stores the result locally.&lt;br&gt;
Instead, I've defined a GetHeroes action:&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="c1"&gt;// hero.actions.ts&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;GetHeroes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Heroes] Get Heroes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;defined the Heroes state to include a list of heroes, and the action handler that performs the GET and stores the result in the state.&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;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroStateModel&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HERO_STATE_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;heroes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HeroState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;heroService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeroService&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="nd"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GetHeroes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;getHeroes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroStateModel&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="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;heroService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeroes&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;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heroes&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;heroes&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;Now the component dispatches the action and "selects" the list from the store. The component template looks at the value of the observable and displays it.&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;HeroesComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HeroState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;heroes$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Hero&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&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;Store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetHeroes&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;BAM!&lt;/p&gt;

&lt;p&gt;Did the same for the Add and Delete: Create the actions, dispatch from the component, handle by calling the service and updating the state according to the result.&lt;/p&gt;

&lt;p&gt;BAM!&lt;/p&gt;

&lt;p&gt;Without much work, the data and logic were completely decoupled from the component. The service wasn't changed at all, and each handler is incredibly focused on what it needs to do.&lt;br&gt;
I then noticed that the Add handler and Get handler both write to the state. Not good! I created a StoreHeroes action and now the two handlers do even less. Call the API and dispatch a new action with the results.&lt;/p&gt;

&lt;p&gt;DOUBLE BAM!&lt;/p&gt;

&lt;p&gt;Up to here, using NGXS was amazingly simple, had very little boilerplate code, and resulted in highly decoupled code.&lt;/p&gt;
&lt;h1&gt;
  
  
  One down, two to go
&lt;/h1&gt;

&lt;p&gt;The easiest page done, I decided to go with the Dashboard next. It will be similar to the Heroes page since it also takes the complete heroes list, only this one manipulates it a little.&lt;/p&gt;

&lt;p&gt;Inject the store. Select the heroes stream. Create a secondary stream by mapping the complete list, to the first four items in it. Replace the *ngFor to iterate over the stream instead, and...&lt;/p&gt;

&lt;p&gt;KABLAM!&lt;/p&gt;

&lt;p&gt;The UI was already set to have it be clickable, and when clicking on a hero, it would route to it's page. That part just worked because I only changed the way the information was bound to the template. It was still the same exact structure. I didn't like having the template handling the route, but I decided to get to that later.&lt;/p&gt;

&lt;p&gt;Next step was replacing the search. This would be the first time things were not trivial.&lt;br&gt;
I thought: "Easy... I'll take the complete list and filter it with the search term".&lt;br&gt;
But when I looked at the existing code, I noticed that the search is performed via a server call (or at least a mock server call since it is all in-memory).&lt;br&gt;
Usually, I would take the search term, dispatch an action with it, and wait on the response to populate the state. Since the user can manipulate the search term before the response arrives, that means multiple actions can be dispatched. Luckily, NGXS allows to specify "abort this action handle if another action is dispatched".&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;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HeroSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cancelUncompleted&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="nf"&gt;searchHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroStateModel&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeroSearch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClearSearchResults&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;heroService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;searchHeroes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchToken&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;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heroes&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&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="na"&gt;heroesSearchResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;heroes&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;h1&gt;
  
  
  Last one...
&lt;/h1&gt;

&lt;p&gt;The hero details page was the most complex (which was not that complex) because it was the only one that enabled the user to modify fields of a single hero. That meant that I couldn't just use the value from the store directly.&lt;br&gt;
I also didn't have the hero to display in the store yet.&lt;/p&gt;

&lt;p&gt;The original component would read the hero ID from the route, fetch it with the service, and store it locally for modifications.&lt;br&gt;
When you selected a hero via the search, dashboard, or heroes page, the template would route you to a different URL and put the requested hero ID in it.&lt;br&gt;
But I don't want my components to do that stuff. They should be as "dumb" as possible.&lt;br&gt;
Instead, all the places that changed the route would now dispatch a new action:&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;SelectHero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[Hero] Select Hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;heroId&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="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;The action handler would fetch the hero with the existing service, save it to the store, and then navigate to the detailed view, same as it did before.&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;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SelectHero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;selectHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroStateModel&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SelectHero&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;heroService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroId&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;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&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="na"&gt;selectedHero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;`/detail/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hero&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="s2"&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;Now the component doesn't need to load anything. The selected hero will already be in the store when the route is changed. All it needs to do is select it from the state. As I mentioned before, to enable editing, the component would need a copy of selected hero. To do that, I just need to subscribe to the stream and save a copy with a tap operator&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hero$&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;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// shallow clone here is enough&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the user edits the hero and clicks save, another action will be dispatched - &lt;strong&gt;UpdateHero&lt;/strong&gt;. The action handler will do the actual work and the state will be updated accordingly.&lt;/p&gt;

&lt;p&gt;Only one thing left: You could manually route directly into the detailed view without ever having the &lt;strong&gt;SelectHero&lt;/strong&gt; action dispatched. To fix that, the component will still take the ID from the route and dispatch the &lt;strong&gt;SelectHero&lt;/strong&gt; with it, but the action handler will ignore it if that ID is already the selected hero.&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;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SelectHero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;selectHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroStateModel&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;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SelectHero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;selectedHero&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;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Ignore it. This hero is already selected&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;heroService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroId&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;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&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="na"&gt;selectedHero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;`/detail/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hero&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="s2"&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;KABLAMO!&lt;/p&gt;

&lt;p&gt;With that, I was done. No component injected any service, all the operations were done via action dispatching, and the entire application state was in the store.&lt;br&gt;
(There was a bit more that could have been done with the message logging, but that felt trivial at this point in the exercise)&lt;/p&gt;

&lt;h1&gt;
  
  
  Lessons Learned
&lt;/h1&gt;

&lt;h3&gt;
  
  
  The incremental approach to migration works well
&lt;/h3&gt;

&lt;p&gt;Especially for state managements where you can slowly add to the state. Starting by defining the migration goals, studying the application, and defining a roadmap, made the process work great.&lt;/p&gt;

&lt;h3&gt;
  
  
  NGXS has a learning curve
&lt;/h3&gt;

&lt;p&gt;But it is fairly slight curve. The straightforward usage of NGXS is simple and you can start using it pretty well. When you try to get complicated, you'll encounter the finer details of the framework. For example, the fact that the observable returned by the dispatch method will emit the state when the action completes, not the value from the async operation that happens in it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The NGXS router plugin is limited (at the time of writing)
&lt;/h3&gt;

&lt;p&gt;At some point, I wanted to get rid of the use of the &lt;strong&gt;ActivatedRoute&lt;/strong&gt; and the &lt;strong&gt;Router&lt;/strong&gt; and replace them with a &lt;a href="https://www.ngxs.io/plugins/router" rel="noopener noreferrer"&gt;NGXS plugin&lt;/a&gt;.&lt;br&gt;
While it was great for navigation and getting parameters passed through the URL, the "back" functionality that exist in the "location" object did not. While it can be extended, I just felt it was not worth the trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tour of heroes is a good starting point, but...
&lt;/h3&gt;

&lt;p&gt;There are a lot of other features in NGXS that proved unnecessary for this project. The entire &lt;a href="https://www.ngxs.io/advanced/actions-life-cycle" rel="noopener noreferrer"&gt;action life cycle&lt;/a&gt; is a huge feature that does not exist at all in NgRx, that can save a lot of boilerplate code when you want to know if a specific action completed and did it succeed.&lt;/p&gt;

&lt;p&gt;Hope you've found this article as helpful as I found it interesting to do.&lt;/p&gt;

</description>
      <category>redux</category>
      <category>ngxs</category>
      <category>angular</category>
    </item>
  </channel>
</rss>
