<?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>Forem: Mikhail Istomin</title>
    <description>The latest articles on Forem by Mikhail Istomin (@mistomin).</description>
    <link>https://forem.com/mistomin</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%2F1061515%2Fd0c7f8c6-0f31-435c-bef6-03ad087f3b2c.PNG</url>
      <title>Forem: Mikhail Istomin</title>
      <link>https://forem.com/mistomin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mistomin"/>
    <language>en</language>
    <item>
      <title>The most valuable developer in the team is …</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Thu, 05 Sep 2024 00:51:22 +0000</pubDate>
      <link>https://forem.com/mistomin/the-most-valuable-developer-in-the-team-is--2h9c</link>
      <guid>https://forem.com/mistomin/the-most-valuable-developer-in-the-team-is--2h9c</guid>
      <description>&lt;p&gt;… the one who increases the productivity of their team members.&lt;/p&gt;

&lt;p&gt;You don’t have to be a team/tech lead or an architect to do things that boost the team`s performance. Even a middle-level developer can cause the impact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why should you care about colleagues’ performance? Because making things that improve the team performance saves money for the business. The team can do more for less time. The ability to make such improvements makes you &lt;strong&gt;valuable&lt;/strong&gt; for the business. For the current and future employers. It’s a win-win situation, good for the business, and good for you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it can facilitate your promotion&lt;/li&gt;
&lt;li&gt;it looks great in your CV&lt;/li&gt;
&lt;li&gt;it highlights your professionalism in the job interviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some ideas, on what to do to boost your team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I added some hints concerning metrics of how the impact can be measured. The metrics are super important. I believe that everything should be estimated in numbers. Numbers mean more than words. With figures at our disposal, we can effectively compare the impact of the different approaches. Moreover, we can track progress over time, enabling us to contrast our current situation with that of a year ago. &lt;/p&gt;

&lt;p&gt;Metrics play a crucial role when communicating with non-technical managers. People from the business side don't care about code and tech stuff. They care about money. And all the number metrics can be calculated into money one way or another. It’s a good way to highlight your impact on the project's success.&lt;/p&gt;

&lt;p&gt;I think the suggested metrics are the weakest part of the article, though. Please, post a comment if you have better ideas to estimate a developer's impact on a team’s performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Documentation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In my job, I follow the Rule of Two (invented by me 😄). It says&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If a colleague asks me a technical question about our project, and later another person asks me the same question, it makes sense to add an article/post in the project documentation with the answer, because most likely I will be asked about it again.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea is that the next time someone has the same question, they will quickly find the answer in the project documentation. It saves their time and my time as well. Saved time = more money for business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What things are worth documenting?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;various &lt;strong&gt;guides&lt;/strong&gt;. How to set up the local environment. Checklist for a good code review. How to perform typical product-related tasks. For instance, how to update the prices in your e-commerce product to test various corner cases. How to create a new user in the CRM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;code conventions&lt;/strong&gt; and coding practices established on the project&lt;/li&gt;
&lt;li&gt;details of your &lt;strong&gt;development process&lt;/strong&gt;. DOD and DOR. The current approach for task estimation. Branching and releasing strategy&lt;/li&gt;
&lt;li&gt;diagrams and graphs explaining &lt;strong&gt;dependencie&lt;/strong&gt;s between parts of the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;contact information&lt;/strong&gt; of the important persons on the project and counterparts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What if my project has no documentation at all?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, you might be that guy who introduces it. As a pioneer, you will be even more valuable to the business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Promote the documentation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s very important not only to write useful articles but also to let your colleagues know what you have done. After each documentation update write messages in the team chats and highlight them in daily meetings&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it will make you visible to the project management and a team lead as a valuable contributor&lt;/li&gt;
&lt;li&gt;your colleagues will remember that this piece of info exists in the documentation&lt;/li&gt;
&lt;li&gt;searching in the chat history will give your colleagues a hint. Useful in situations like “I know that we have the answer, but I don’t recall where exactly”&lt;/li&gt;
&lt;li&gt;it will encourage your colleagues to contribute to the documentation as well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s difficult to come up with a general metric for the quality and usefulness of the project documentation. The number of articles and the views count don’t say anything. But in some cases, there are some figures to calculate&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;concerning a guide for the start-up of the local environment, we can measure how much time it takes for a newcomer to prepare the local machine and pick up the first task. We can compare the time taken for the old/new guide&lt;/li&gt;
&lt;li&gt;documentation quality affects the time taken for the grooming and estimation of new features since the new things are connected to the old ones one way or another. We could measure the dynamics&lt;/li&gt;
&lt;li&gt;regularly ask colleagues to estimate documentation quality from 1 to 10 (for instance every month or every quarter). The average can be considered as a satisfaction level&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing the right architecture, framework, and libraries
&lt;/h2&gt;

&lt;p&gt;One of the most important topics. Let’s consider some cases from the team’s performance standpoint.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you are responsible for choosing the framework/library among several alternatives. You weigh the benefits and drawbacks of the things that are available and choose the one that will allow the team to write the code smoothly. The features and ecosystem of the chosen item allow the team to write less code relying on the out-of-the-box functionality&lt;/li&gt;
&lt;li&gt;you choose the framework/library/design which is aligned with the &lt;strong&gt;team's skills&lt;/strong&gt; and maturity level. It makes sense to prefer a simpler solution if the team's average level is low. But for the more skillful team, we can choose the more advanced approaches&lt;/li&gt;
&lt;li&gt;apply the right design pattern in the right place to simplify code maintenance in the long run&lt;/li&gt;
&lt;li&gt;you can introduce a library to simplify boilerplate tasks or reduce duplicate code. For instance, introducing &lt;a href="https://tanstack.com/query/latest/docs/framework/react/overview" rel="noopener noreferrer"&gt;tanstack query&lt;/a&gt; in a React app allows the team to use handy API to make network calls rather than write cumbersome and repetitive code for that&lt;/li&gt;
&lt;li&gt;when working on the design, a skillful developer makes good assumptions about how the system might be &lt;strong&gt;extended&lt;/strong&gt; in the future. Reasonable extension points can be added to the design. As a result, adding new features in the future will require small changes in the existing codebase&lt;/li&gt;
&lt;li&gt;the system should be split into independent and isolated parts which know as little as possible about other parts of the app. &lt;strong&gt;Low coupling&lt;/strong&gt; makes code changes more predictable and reduces the number of bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This topic can take the whole article, so I stop here. I think you got the point. The solid design and the right tools make the team very efficient. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scrum Velocity, or an average amount of work delivered in a month/quarter&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Improve development experience
&lt;/h2&gt;

&lt;p&gt;Introduce and propagate tools that make code writing and debugging easier and faster&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IDE plugins&lt;/strong&gt; for code highlighting, autocomplete, formatters, etc. In VScode the set of chosen plugins can be &lt;a href="https://code.visualstudio.com/docs/editor/extension-marketplace#_workspace-recommended-extensions" rel="noopener noreferrer"&gt;defined&lt;/a&gt; as a .json file located in the project repo to share with colleagues&lt;/li&gt;
&lt;li&gt;scripts to &lt;strong&gt;automate routine tasks&lt;/strong&gt;. For instance, in the JS world, we can introduce git hooks to automatically run linter checks before push rather than executing checks manually. Scripts to start multiple services at once are another good example&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI tools&lt;/strong&gt;. Even a basic understanding of how to utilize the capabilities of AI tools like Ghat GPT or Claude positively impacts a developer’s performance. Figure out how to use it and teach your colleagues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postman&lt;/strong&gt; collections and &lt;strong&gt;Swagger&lt;/strong&gt; can simplify API-related tasks. What arguments do that endpoints accept? No need to search through the codebase, it’s much easier to check Swagger instead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we can calculate the average time a task stays in “In Progress”.  Using the right tools will decrease the number&lt;/li&gt;
&lt;li&gt;an average amount of work (story points, T-Shirt sizes, whatever) delivered in a month or quarter. Scrum Velocity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unit-testing culture
&lt;/h2&gt;

&lt;p&gt;Plenty of bugs can be discovered in the early stage by unit tests. Organizing proper testing processes saves a lot of time and money in the long run. &lt;/p&gt;

&lt;p&gt;I agree, it’s not applicable to some kinds of projects. Startups, prototypes, or projects with constantly changing requirements will not benefit from tests. But for all other projects, I would recommend introducing unit tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the project has no unit tests at all, the adopter (you) will have to choose the technology/framework and write first 100 tests as an example and a starting point for the colleagues&lt;/li&gt;
&lt;li&gt;in some cases, it’s more efficient to write tests only for the most important and fragile logic leaving the rest of the app untested. I have an idea of how to prioritize code for testing. Will share in another post&lt;/li&gt;
&lt;li&gt;providing the mocks might require a lot of cumbersome code in some cases. It makes sense to use extra tools to simplify it. For instance, &lt;a href="https://www.npmjs.com/package/ng-mocks" rel="noopener noreferrer"&gt;ng-mocks&lt;/a&gt; for Angular&lt;/li&gt;
&lt;li&gt;you may write documentation and conduct some team-level master classes to share the knowledge and facilitate the testing adoption in the project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an average number of bugs discovered in a sprint, month, or quarter&lt;/li&gt;
&lt;li&gt;an average amount of work (story points, T-Shirt sizes, whatever) delivered in a month or quarter. Scrum Velocity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Knowledge sharing
&lt;/h2&gt;

&lt;p&gt;You can organize a call, master class, or regular meetings to share valuable project-related information with the team. It can be a screen sharing with the presentation or online coding. Whatever is suitable to efficiently share important ideas with colleagues. &lt;/p&gt;

&lt;p&gt;Avoid speaking about general topics. Focus on things that your colleagues can apply to the project right now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nonobvious but important things about &lt;strong&gt;domain logic&lt;/strong&gt; or business processes. Sometimes developers focus on writing code but have limited knowledge of how the business works. The lack of knowledge of this kind might lead to bugs. It makes sense to shed some light on the business that stands behind the app to make the development mode aware and conscious.&lt;/li&gt;
&lt;li&gt;tricky things about the &lt;strong&gt;tech stack&lt;/strong&gt; you are using on the project. Especially if you implement some things in a nonstandard way or if the implementation differs from what the framework/libraries documentation suggest&lt;/li&gt;
&lt;li&gt;any unclear topics highlighted on the retro or daily meetings are a good thing to clarify and share&lt;/li&gt;
&lt;li&gt;encourage colleagues to participate in discussions and share information as well&lt;/li&gt;
&lt;li&gt;make the knowledge-sharing sessions on schedule, say, once a week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;regular&lt;/strong&gt; knowledge-sharing sessions are supposed to boost the professional level of the team so we can estimate the dynamics in the development speed. Scrum Velocity, or an average amount of work delivered in a month/quarter&lt;/p&gt;

&lt;h2&gt;
  
  
  Other
&lt;/h2&gt;

&lt;p&gt;It’s already too much for a post. So I briefly share other ideas on how to impact the team’s performance&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;mentoring&lt;/strong&gt;. Take care of the less experienced developers in the team. Communicate with them directly to make them more efficient. Pair programming and code review have proved to be very efficient&lt;/li&gt;
&lt;li&gt;right &lt;strong&gt;task distribution&lt;/strong&gt; among the team members. A team lead should consider many factors when choosing a developer for a task&lt;/li&gt;
&lt;li&gt;improving the &lt;strong&gt;code review&lt;/strong&gt; culture. Sometimes people consider code review as a useless formality. That’s wrong since the code review is one of the essential quality gates&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>productivity</category>
      <category>community</category>
    </item>
    <item>
      <title>Streamlining Styles: CSS Variables for Maintainable Code</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Wed, 21 Aug 2024 23:32:45 +0000</pubDate>
      <link>https://forem.com/mistomin/streamlining-styles-css-variables-for-maintainable-code-2ild</link>
      <guid>https://forem.com/mistomin/streamlining-styles-css-variables-for-maintainable-code-2ild</guid>
      <description>&lt;p&gt;Here are some insights on how CSS variables can simplify support of reusable and customizable components. Regardless of the framework you're using, this approach remains framework-agnostic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample component
&lt;/h2&gt;

&lt;p&gt;Suppose I need to add the Progress Bar component to my UI kit. Using React as an example, here's a straightforward implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ProgressBar.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProgressBar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;percentage&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="nl"&gt;percentage&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And CSS to add colors and basic rules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.progress-bar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.progress-bar&lt;/span&gt; &lt;span class="nc"&gt;.fill&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&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;It's black by default and looks like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7dxbngbsh936p0qk4t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7dxbngbsh936p0qk4t0.png" alt="The default progress bar" width="235" height="56"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The component is supposed to be reused in various parts of my app. I expect that each consumer should have the flexibility to customize the color of the bar and its border to align with their specific needs and color scheme. &lt;/p&gt;

&lt;p&gt;I expect consumers to provide their own CSS rules to override the default colors. For example, a consumer can write the following CSS to make the progress bar green within the upload section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#upload&lt;/span&gt; &lt;span class="nc"&gt;.progress-bar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#upload&lt;/span&gt; &lt;span class="nc"&gt;.progress-bar&lt;/span&gt; &lt;span class="nc"&gt;.fill&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This customization works as expected. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3hnfquycrucp00n1mxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3hnfquycrucp00n1mxj.png" alt="Customized green progress bar" width="227" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each consumer can adopt the same approach, and at first glance, it seems like a solid solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;However, that way of customization comes with several drawbacks&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Future bugs:&lt;/strong&gt; In the long run, the progress bar component will be updated or refactored. The customization will break if classes are renamed or the hierarchy of the tags is changed.&lt;br&gt;
🤯 &lt;strong&gt;Consumer's cognitive load:&lt;/strong&gt; Developers using my component need to examine its HTML structure to determine the necessary CSS rules for overriding the default values.&lt;br&gt;
⚒️ &lt;strong&gt;Cumbersome customization code:&lt;/strong&gt; Modifying both the color of the bar and its border requires writing two separate rules.&lt;/p&gt;

&lt;p&gt;Of course, it's not a big deal for simple cases like our ProgressBar. However more complex components in a large UI kit, especially when used by many developers, can present significant challenges.&lt;/p&gt;
&lt;h2&gt;
  
  
  CSS variable as a solution
&lt;/h2&gt;

&lt;p&gt;To simplify customization and mitigate these issues, we can leverage CSS variables.&lt;/p&gt;

&lt;p&gt;In my sample component, changes are made only in the CSS file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.progress-bar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--progress-bar-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--progress-bar-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.progress-bar&lt;/span&gt; &lt;span class="nc"&gt;.fill&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--progress-bar-color&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;Note that I declare the variable &lt;code&gt;--progress-bar-color&lt;/code&gt;  to set the color. Consumers can now customize the component as easily as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#upload&lt;/span&gt; &lt;span class="nc"&gt;.progress-bar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--progress-bar-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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 new approach, let's revisit the list of customization problems&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Future bugs:&lt;/strong&gt; As the developer of the progress bar, I can modify class names and the hierarchy as needed. However, as long as I apply the CSS variable correctly to the updated elements, color customizations made by consumers remain intact.&lt;br&gt;
🤯 &lt;strong&gt;Consumer's cognitive load:&lt;/strong&gt; Consumers no longer need to examine my component's code to customize colors. The CSS variable acts as an 'interface' or 'abstraction,' allowing them to simply set the desired color without delving into the implementation details. &lt;br&gt;
⚒️ &lt;strong&gt;Cumbersome customization code:&lt;/strong&gt; Now, a single CSS rule can customize both the fill and the border elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra benefit
&lt;/h2&gt;

&lt;p&gt;In terms of color customization, relying on the CSS variable streamlines the application of a general color scheme. You can manage all color settings with a simple CSS file that defines variables across the entire page.&lt;/p&gt;

&lt;p&gt;Now, all the colors on the page can be controlled from a single location. To update the colors for the entire page, simply replace the CSS variable definitions with a new set.&lt;/p&gt;

&lt;p&gt;This approach also facilitates the implementation of features such as light/dark themes or user-defined color preferences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outcome
&lt;/h2&gt;

&lt;p&gt;💸 &lt;strong&gt;Better maintainability:&lt;/strong&gt; By adopting the customization through CSS variables, the codebase becomes more maintainable, making future updates simpler and less time-consuming.&lt;/p&gt;

&lt;p&gt;👍 &lt;strong&gt;Reduced Bug-Prone Code:&lt;/strong&gt; The clear separation between the component's internals and its customization interface minimizes the risk of bugs, as changes to internal implementation don't affect how the component is customized.&lt;/p&gt;

&lt;p&gt;😀 &lt;strong&gt;The code gets easier to understand:&lt;/strong&gt; The use of CSS variables makes the solution more intuitive and easier to understand. Developers can quickly grasp how to modify styles without delving into complex or opaque code.&lt;/p&gt;

&lt;p&gt;♾️ &lt;strong&gt;Framework-agnostic:&lt;/strong&gt; You can apply this approach everywhere since it relies on the browser features only.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Let's use Chrome Profiler to research obfuscated code</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Tue, 21 May 2024 15:48:36 +0000</pubDate>
      <link>https://forem.com/mistomin/lets-use-chrome-profiler-to-research-obfuscated-code-j01</link>
      <guid>https://forem.com/mistomin/lets-use-chrome-profiler-to-research-obfuscated-code-j01</guid>
      <description>&lt;p&gt;Imagine you want to figure out how some interesting feature on a website works. The challenge is that on modern websites, the client-side JavaScript code is usually minified and obfuscated, making the research quite difficult.&lt;/p&gt;

&lt;p&gt;Check out how the Chrome &lt;strong&gt;Performance&lt;/strong&gt; tool can help you study twisted JS code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I’m currently working on the React Donut chart with a big focus on accessibility (A11y). As an example, I took this &lt;a href="https://www.fusioncharts.com/extensions-accessibility/pie" rel="noopener noreferrer"&gt;chart&lt;/a&gt;. The problem is that I could not figure out how they managed to make the donut navigable with the keyboard arrows. Is it some combination of ARIA attributes or JS code involved? A deep dive into the code was needed.&lt;/p&gt;

&lt;p&gt;Of course, the JS bundles were obfuscated, so I decided to give the Profiler a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profiling
&lt;/h2&gt;

&lt;p&gt;The plan is the following&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start profiling&lt;/li&gt;
&lt;li&gt;Do some actions on the website to trigger the code I want to research (press the keyboard keys in my case )&lt;/li&gt;
&lt;li&gt;Stop profiling&lt;/li&gt;
&lt;li&gt;Analyze the generated diagram.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The diagram has the &lt;strong&gt;Interactions&lt;/strong&gt; section that tracks keyboard events. Let’s zoom and scroll to the Arrow Key event I need.&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%2Fppkt90brmubf9g2hvrym.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%2Fppkt90brmubf9g2hvrym.png" alt="Zoomed performance diagram" width="771" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bars on the diagram are &lt;strong&gt;clickable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The summary of a selected bar is displayed below the diagram. If the selected bar represents a JS function, the profiler shows the &lt;strong&gt;link to the code&lt;/strong&gt;. It’s amazingly helpful.&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%2Fz1liq64ssz6nm4slz3l7.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%2Fz1liq64ssz6nm4slz3l7.png" alt="Clicked bar" width="791" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the keyboard event handler that I was looking for.&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%2Fmnffv8emcep3klkbrvwt.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%2Fmnffv8emcep3klkbrvwt.png" alt="Source code location" width="800" height="342"&gt;&lt;/a&gt;&lt;br&gt;
Now, the &lt;strong&gt;Source&lt;/strong&gt; tab shows me the exact function in the JS bundle that handles the event. The Profiles saved me a lot of time. No need to look through the huge codebase and obfuscated bundles. The function is located and I can proceed with my research.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;Also, the profiler shows the &lt;code&gt;setTimeout&lt;/code&gt; statement which caused the function execution. Very helpful in some cases.&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%2Fawzgg6zpg3yvq97g7qxo.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%2Fawzgg6zpg3yvq97g7qxo.png" alt="setTimeout on the diagram" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>chrome</category>
    </item>
    <item>
      <title>Angular DI: the genetic tokens pitfall</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Fri, 15 Sep 2023 10:04:55 +0000</pubDate>
      <link>https://forem.com/mistomin/angular-di-the-genetic-tokens-pitfall-53g9</link>
      <guid>https://forem.com/mistomin/angular-di-the-genetic-tokens-pitfall-53g9</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Recently I have discovered that using generic tokens for DI in Angular has an unexpected problem. It's not a critical issue, but rather something to be aware of.&lt;/p&gt;

&lt;p&gt;In a nutshell, Angular and Typescript are not able to verify that a provided class really implements an interface, specified for a token. &lt;/p&gt;

&lt;h2&gt;
  
  
  App example
&lt;/h2&gt;

&lt;p&gt;I declare the DI token &lt;strong&gt;PaymentServiceToken&lt;/strong&gt; and provide the implementation on the module level.&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;IPaymentService&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getPaymentTypes&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="nf"&gt;authorizePayment&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PaymentServiceToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPaymentService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment Service token&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="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="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;PaymentServiceToken&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;PaymentService&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;AppModule&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;Note that the token is initialised as a &lt;strong&gt;generic&lt;/strong&gt; class to let the consumers know that the implementations for this token will implement the interface &lt;strong&gt;IPaymentService&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then the service can be consumed by a component via DI like 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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({...})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentComponent&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PaymentServiceToken&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;paymentService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;IPaymentService&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;// OR&lt;/span&gt;
  &lt;span class="c1"&gt;// private paymentService = inject(PaymentServiceToken);&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&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;paymentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPaymentTypes&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;As a result I expect interaction with the injected service to be type-safe. In case of service misuse the errors should be thrown in compilation time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz88ssrip1pmzo34fexjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz88ssrip1pmzo34fexjp.png" alt="Type checking error" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the same time I can provide other implementations for the same token on the &lt;strong&gt;module&lt;/strong&gt; level without making changes in the components level. Something like&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;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="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;PaymentServiceToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// useClass: PaymentService&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; 
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PaymentService&lt;/span&gt; 
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MockPaymentService&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;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is useful for some cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replace a real service with a mock version to avoid API calls&lt;/li&gt;
&lt;li&gt;replace an old service with a new version having some extra features or refactoring&lt;/li&gt;
&lt;li&gt;switching between implementations depending on configs or feature flags&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;To enable type checking I set up the token using the &lt;strong&gt;IPaymentService&lt;/strong&gt; interface. But what if, by mistake, I provide the implementation that &lt;strong&gt;doesn't implement the interface&lt;/strong&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PaymentServiceToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPaymentService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment Service token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// DeliveryService  doesn't implement IPaymentService&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeliveryService&lt;/span&gt;&lt;span class="p"&gt;(){}&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;PaymentServiceToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// useClass: PaymentService&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;DeliveryService&lt;/span&gt;  &lt;span class="c1"&gt;// &amp;lt;--- wrong service !!!&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;AppModule&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 result is a disaster. I have no errors in compile time. But in runtime the TypeError is thrown and the app is ruined&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp19udox5sk95be8n6wxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp19udox5sk95be8n6wxq.png" alt="Unexpected runtime error" width="712" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Providing the wrong service is for sure the developer's fault, but Typescript and Angular failed to detect it during compilation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Unfortunately, I haven't found a way to arrange proper type checking to verify that the token's implementation meets the token's interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;PaymentServiceToken&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;PaymentService&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- be extremely cautious here&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;Moreover, there is an open &lt;a href="https://github.com/angular/angular/issues/33883" rel="noopener noreferrer"&gt;issue in the Angular repo&lt;/a&gt; connected to the generic token's problem. Looks like there is no quick and simple solution.&lt;/p&gt;

&lt;p&gt;The only thing I can suggest is to define a function with typing which verifies that the returned class implements the certain interface.&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;function&lt;/span&gt; &lt;span class="nf"&gt;getPaymentService&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new &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;IPaymentService&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; 
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PaymentService&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MockPaymentService&lt;/span&gt;
&lt;span class="p"&gt;}&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;PaymentServiceToken&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="nf"&gt;getPaymentService&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;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can improve the function &lt;strong&gt;getPaymentService&lt;/strong&gt; to make it suitable for handling services with DI in constructors&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;function&lt;/span&gt; &lt;span class="nf"&gt;getPaymentService&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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;IPaymentService&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; 
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PaymentService&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MockPaymentService&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or rely on Angular's &lt;strong&gt;Type&lt;/strong&gt; &lt;a href="https://angular.io/api/core/Type" rel="noopener noreferrer"&gt;interface&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPaymentService&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPaymentService&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PaymentService&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MockPaymentService&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution will throw a compilation error if I mistakenly provide a wrong service&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmkr87j8tstqsua1i4lt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmkr87j8tstqsua1i4lt.png" alt="Compilation error for a wrong service" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honestly, I don't like this solution since you have to write such functions manually for each generic token. I just can't come up with something better than that.&lt;/p&gt;

&lt;p&gt;I hope the more useful solution will be introduced in the next versions of Angular.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>FAQ on Google Tag Manager (GTM) for non-GTM devs</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Fri, 18 Aug 2023 18:09:16 +0000</pubDate>
      <link>https://forem.com/mistomin/faq-on-google-tag-manager-gtm-for-non-gtm-devs-4e48</link>
      <guid>https://forem.com/mistomin/faq-on-google-tag-manager-gtm-for-non-gtm-devs-4e48</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;GTM is a valuable tool in the modern WEB ecosystem. But several times I faced the following issue. The FE team works on a website and the dedicated GTM-focused team works on GTM for the same website. The problem is that GTM-related knowledge gets concentrated in the GTM team and the FE team is completely unaware of GTM features and approaches. &lt;/p&gt;

&lt;p&gt;But at the same time, occasionally the FE team has to deal with bugs and unexpected behavior caused by GTM. In those cases lack of knowledge of GTM reduces the efficiency of the FE team.&lt;/p&gt;

&lt;p&gt;I have composed a short FAQ for non-GTM FE devs who just want to grasp the basic aspects of working with GTM. &lt;/p&gt;

&lt;h2&gt;
  
  
  How GTM works
&lt;/h2&gt;

&lt;p&gt;There are plenty of resources over the Internet explaining what is GTM and how it works. It will put it as simple as this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fuk0jvta5oyv47ig3r06y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuk0jvta5oyv47ig3r06y.png" alt="How GTM works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The GTM specialist (the guy in the fancy hat to the right) logs in to the GTM admin panel. &lt;/li&gt;
&lt;li&gt;He sets up the &lt;strong&gt;container&lt;/strong&gt; and puts some &lt;strong&gt;custom scripts&lt;/strong&gt; in it. Note that the container has a unique &lt;strong&gt;id&lt;/strong&gt; (the red label).&lt;/li&gt;
&lt;li&gt;The user (the guy in the sunglasses) opens the website. The HTML has the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag responsible for initializing GTM. I call it &lt;strong&gt;"loader"&lt;/strong&gt;, the green brick in the picture above. The &lt;strong&gt;loader&lt;/strong&gt; is added in HTML by the FE team. Also, the loader has a hardcoded container &lt;strong&gt;id&lt;/strong&gt;. The &lt;strong&gt;loader&lt;/strong&gt; makes a request to the Google servers to fetch the &lt;strong&gt;container&lt;/strong&gt; by &lt;strong&gt;id&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Once the container is received, custom scripts added by the GTM guy are executed in the browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Actually, things are a bit more complicated. Variables, triggers, and tags have to be configured in the GTM container as well to make it work. I omit all those complex details in order to provide a straightforward explanation and keep the focus on the GTM basics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;u&gt;Here I want to highlight two things:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: new custom scripts might be added to GTM without redeploying the main website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drawback&lt;/strong&gt;: the FE team working on the website might be completely unaware of the release schedule of the GTM team. Even the purpose of GTM scripts may be not shared with the FE team.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to disable GTM in the browser
&lt;/h2&gt;

&lt;p&gt;Sometimes you might want to disable GTM on the website to compare UX and behavior with GTM and without it. It's possible to do this via an admin panel of your site, site configs, or via modifying the code. But there is a simpler way. GTM can be easily disabled in the browser.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the devtools open the &lt;strong&gt;Network&lt;/strong&gt; tab and filter JS requests by the 'gtm' keyword. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then block the request &lt;code&gt;https://www.googletagmanager.com/gtm.js?id=&amp;lt;CONTAINER_ID&amp;gt;&lt;/code&gt;. Here &lt;code&gt;&amp;lt;CONTAINER_ID&amp;gt;&lt;/code&gt; is an arbitrary set of letters and digits. It's unique for your website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That's it. After the page reload the block will be applied and the container will never be loaded by your browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgcrxtck7hepel19yyadq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgcrxtck7hepel19yyadq.png" alt="Disabling GTM in the browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't forget that the blocking works in your browser only. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can &lt;strong&gt;unblock&lt;/strong&gt; scripts anytime on the &lt;strong&gt;Network Request Blocking&lt;/strong&gt; tab. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4l7ajgtanb7n6pdoubs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4l7ajgtanb7n6pdoubs5.png" alt="Enabling GTM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing dataLayer
&lt;/h2&gt;

&lt;p&gt;One of GTM's key features is &lt;strong&gt;dataLayer&lt;/strong&gt;. In a nutshell, it is a bus enabling interaction between scripts on the page and GTM scripts. The app's code push events in the &lt;strong&gt;dataLayer&lt;/strong&gt; to notify custom scripts in GTM about user actions and other important things.&lt;/p&gt;

&lt;p&gt;In some cases, it's essential for development and bug fixing to study published events and their payload. The easiest way is to type &lt;code&gt;dataLayer&lt;/code&gt; in the browser's console. You will see the events as a simple array.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl0xqcal6yhkm9928b31i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl0xqcal6yhkm9928b31i.png" alt="DataLayer in the browser console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not very handy, is it?&lt;/p&gt;

&lt;p&gt;So I recommend using the Chrome extension &lt;a href="https://chrome.google.com/webstore/detail/datalayer-checker/ffljdddodmkedhkcjhpmdajhjdbkogke" rel="noopener noreferrer"&gt;Datalayer Checker&lt;/a&gt; instead. It has the elegant user interface and many useful features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fpq0i7brvus19fjv7hrm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpq0i7brvus19fjv7hrm2.png" alt="Datalayer Checker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is one trick. By default, Chrome extensions are disabled in &lt;strong&gt;incognito&lt;/strong&gt; mode. So the Datalayer Checker will not be available in incognito which is not very useful. However, there is a special setting for that case. Go to the extension settings and enable it for incognito&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fa3cm2vvenu7fnxb3ufgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fa3cm2vvenu7fnxb3ufgi.png" alt="Enabling Datalayer Checker for Incognito "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gtm</category>
      <category>website</category>
    </item>
    <item>
      <title>Flaky unit tests in Angular</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Tue, 08 Aug 2023 10:25:39 +0000</pubDate>
      <link>https://forem.com/mistomin/flaky-unit-tests-in-angular-21n6</link>
      <guid>https://forem.com/mistomin/flaky-unit-tests-in-angular-21n6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A flaky test is an unstable test that randomly passes or fails despite no changes in the code or the test itself.&lt;/p&gt;

&lt;p&gt;When unit tests are a part of the CI pipeline, flaky tests become the real problem. Tests unpredictably fail and every time devs have to spend precious time investigating and fixing. Also, flaky tests reduce confidence in tests in general.&lt;/p&gt;

&lt;p&gt;In this article I want to research the nature of flaky unit tests in Angular and consider possible fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flaky test example
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The simple component
&lt;/h3&gt;

&lt;p&gt;Let's say we are developing a blog engine. The blog has the Backoffice, kind of an admin page, where authenticated users with admin permissions can set some settings, manage blog pages, etc.&lt;/p&gt;

&lt;p&gt;Each page of the blog has a header. One of the header responsibilities is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;render the Backoffice link if the current user is has admin permissions&lt;/li&gt;
&lt;li&gt;hide the Backoffice link if the current user is not an admin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm going to implement it as simple as possible. You can find the code in &lt;a href="https://github.com/ungear/ng-flaky-tests" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is our typing&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;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The service does nothing but storing the user data.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And finally the header component that consumes user data from the server and renders a link&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;div *ngIf="user"&amp;gt;
    &amp;lt;a class="backoffice-link" *ngIf="user.isAdmin" href="/backoffice"&amp;gt;&amp;lt;/a&amp;gt;
  &amp;lt;/div&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HeaderComponent&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="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&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;ngOnInit&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&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;
  
  
  The tests for the simple component
&lt;/h3&gt;

&lt;p&gt;Now I'm going to write some unit tests. Most of all, I want to cover &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;. It should be hidden for regular users, but visible for admins.&lt;/p&gt;

&lt;p&gt;The mock for a regular non-admin user&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./user.interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockReguarUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&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;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And here are the tests. I guess, it's the most straightforward way to write unit tests for our case&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HeaderComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&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;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentFixture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeaderComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userServiceStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockReguarUser&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// (1)&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userServiceStub&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// (2)&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;compileComponents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HeaderComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not render Backoffice link for regular users &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// to trigger ngOnInit&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.backoffice-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeFalsy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//(3)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render Backoffice link for admins users &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;userServiceStub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//(4)&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// to trigger ngOnInit&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.backoffice-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&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;Basically, I create a stub for the UserService, the &lt;code&gt;mockReguarUser&lt;/code&gt; constant is used as user data &lt;strong&gt;(1)&lt;/strong&gt;. Then, I provide the stub to the component &lt;strong&gt;(2)&lt;/strong&gt;. The component consumes the service stub via DI engine, reads user data and render HTML according to user properties.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;(3)&lt;/strong&gt; I check if the link is not displayed for a regular user. In &lt;strong&gt;(4)&lt;/strong&gt; I change the &lt;code&gt;isAdmin&lt;/code&gt; flag in mocked data to check how the header component handles admin users. &lt;/p&gt;

&lt;p&gt;The tests look fine, but when I run Karma the strange things happen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsrr0gv7ztpa3g4oct437.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsrr0gv7ztpa3g4oct437.gif" alt="Tests unpredictably pass/fail"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, tests are green, but then I start hitting the reload button to rerun test suit. Surprisingly the particular test passes or fails in a random way. So, without any changes in the code I get different results many times. That's exactly what a flaky test is. &lt;/p&gt;

&lt;h2&gt;
  
  
  Researching a flaky test
&lt;/h2&gt;

&lt;p&gt;First, let's figure out which test is unstable. The error message says&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Feybwy4aid9cia1grma03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Feybwy4aid9cia1grma03.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks like the the header component sometimes renders the Backoffice link for regular users, which it definitely should not do. I need to debug the test to find the root cause. &lt;/p&gt;

&lt;p&gt;Unfortunately, the test result is unstable. It makes debugging too difficult. I need a reliable way to reproduce the test failure to be able to dive deeper. Here we need to learn about the random seed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The seed
&lt;/h3&gt;

&lt;p&gt;By default Jasmine runs unit tests in a random order. Random tests execution helps developers write independent and reliable unit tests. Basically it's what the &lt;strong&gt;I&lt;/strong&gt; letter in &lt;strong&gt;F.I.R.S.T&lt;/strong&gt; stands for. Read more about the FIRST stuff &lt;a href="https://medium.com/@tasdikrahman/f-i-r-s-t-principles-of-testing-1a497acda8d6" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However this random order is controllable. Before running tests Jasmine generates a random number which is called the &lt;strong&gt;seed&lt;/strong&gt;. Then the order of tests execution is calculated according to the seed. Also, Jasmine let us know which seed were used for the test run. Moreover, the seed can be provided via config to make Jasmine run tests in the same order over and over again. &lt;/p&gt;

&lt;p&gt;That's what we can do to reproduce the failing test execution&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1)&lt;/strong&gt; Obtain the seed used for a failed test run. It can be taken from the browser's report&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F46yll11l81i38i4rzpja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F46yll11l81i38i4rzpja.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If a flaky test detected in CI and the browsers report is not available, the &lt;a href="https://www.npmjs.com/package/karma-jasmine-order-reporter" rel="noopener noreferrer"&gt;Jasmine order reporter&lt;/a&gt; can be used. The only thing is that you have to apply it beforehand. Then the seed can be found in logs of the CI pipeline&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Chrome 115.0.0.0 (Windows 10) JASMINE ORDER REPORTER: Started with seed 05217


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2)&lt;/strong&gt; Once we know the seed that results in failing test order, it can be applied in Karma configs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// karma.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other settings&lt;/span&gt;
    &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;jasmine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;05217&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;----------&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;Now tests will be executed in the same order every time. In our case it means that the issue with the nasty unit test can be reproduced and investigated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Studying the flaky test
&lt;/h3&gt;

&lt;p&gt;We already discovered that the header components sometimes renders the Backoffice link for regular users. Let's figure out why. I simply put &lt;strong&gt;debugger&lt;/strong&gt; in the &lt;code&gt;ngOnInit&lt;/code&gt; method and run tests to check what's going on when the flaky test gets executed. &lt;/p&gt;

&lt;p&gt;It turned out that the &lt;code&gt;this.userService.currentUser.isAdmin&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; when we run a test for a regular user. But the property is &lt;code&gt;false&lt;/code&gt; in &lt;code&gt;mockReguarUser&lt;/code&gt; we use in tests. How it becomes &lt;code&gt;true&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The reason is the order of tests execution.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HeaderComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userServiceStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mockReguarUser&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userServiceStub&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;compileComponents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// (1) &lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not render Backoffice link for regular users &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// to trigger ngOnInit&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.backoffice-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeFalsy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// (2) &lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render Backoffice link for admins users &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;userServiceStub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// to trigger ngOnInit&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.backoffice-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&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;When the test &lt;strong&gt;(1)&lt;/strong&gt; executed before &lt;strong&gt;(2)&lt;/strong&gt; everything is fine. But when &lt;strong&gt;(2)&lt;/strong&gt; executed first we face the problem. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fvup74optnng8yzd5s265.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fvup74optnng8yzd5s265.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test &lt;strong&gt;(2)&lt;/strong&gt; sets &lt;code&gt;userServiceStub.currentUser.isAdmin&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
But &lt;code&gt;userServiceStub.currentUser&lt;/code&gt; is a reference "shared" between both tests. So, when the test &lt;strong&gt;(1)&lt;/strong&gt; is executed next, it works with the &lt;strong&gt;modified&lt;/strong&gt; mock! Having &lt;code&gt;isAdmin = true&lt;/code&gt; results is unexpected behavior and the test fails. &lt;/p&gt;

&lt;p&gt;In the specific order of execution the test &lt;strong&gt;(2)&lt;/strong&gt; becomes a criminal and the test &lt;strong&gt;(1)&lt;/strong&gt; is a victim.&lt;/p&gt;

&lt;p&gt;I think now it's clear why tests unpredictably failed/passed when executed multiple times in a row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the flaky test
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cloning mocks
&lt;/h3&gt;

&lt;p&gt;We need to make tests more isolated from each other to fix the problem. Let's create a new copy of the mock for each test. Note how I clone &lt;code&gt;mockReguarUser&lt;/code&gt; in &lt;code&gt;beforeEach&lt;/code&gt; section to ensure that each test gets a separate mock. At the same time the original mock is kept intact.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HeaderComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&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;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentFixture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeaderComponent&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;// use the mock regular user&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;userServiceStub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;userServiceStub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;mockReguarUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// clone mock&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userServiceStub&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;compileComponents&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 a test can modify its mocks whatever it wants. The changes will not affect other tests. &lt;/p&gt;

&lt;h3&gt;
  
  
  Deep cloning
&lt;/h3&gt;

&lt;p&gt;The trick with cloning via the spread operator works fine because the &lt;code&gt;mockReguarUser&lt;/code&gt; has no nested objects. But the operator creates a &lt;strong&gt;shallow copy&lt;/strong&gt;. It is not enough for more complex mocks, since the nested objects will be copy by reference and the data still be shared among tests causing the same problem.&lt;/p&gt;

&lt;p&gt;Lodash &lt;a href="https://lodash.com/docs/#cloneDeep" rel="noopener noreferrer"&gt;cloneDeep &lt;/a&gt; is quite useful to handle complex mock cloning. It would be as simple as &lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="nx"&gt;userServiceStub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockReguarUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Flaky tests in multiple components&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Above we considered the relatively simple problem. The test that modifies mocks and the flaky test that unexpectedly fails due to the modifications both belong to the same component. And both tests sit in the same &lt;code&gt;.spec.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In more complex apps this problem might be more complicated. Changing mocks made in suits for one component might cause test flakiness for other component. The components might even belong to different Angular modules. &lt;/p&gt;

&lt;p&gt;In that case the investigation might be more difficult and solution probably will be more sophisticated. But the main idea is still the same. Most likely the problem can be fixed by applying cloning to prevent tests interaction via references in mocks.&lt;/p&gt;




&lt;p&gt;Links&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;my &lt;a href="https://github.com/ungear/ng-flaky-tests" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt; with the example of a flaky test&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/karma-jasmine-order-reporter" rel="noopener noreferrer"&gt;Jasmine order reporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lodash &lt;a href="https://lodash.com/docs/#cloneDeep" rel="noopener noreferrer"&gt;cloneDeep &lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>unittest</category>
    </item>
    <item>
      <title>TypeScript: type compatibility vs duck typing</title>
      <dc:creator>Mikhail Istomin</dc:creator>
      <pubDate>Mon, 17 Apr 2023 10:54:01 +0000</pubDate>
      <link>https://forem.com/mistomin/typescript-type-compatibility-vs-duck-typing-62d</link>
      <guid>https://forem.com/mistomin/typescript-type-compatibility-vs-duck-typing-62d</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;TypeScript is based on the &lt;strong&gt;structural&lt;/strong&gt; type system. In a nutshell, the types of variables involved in some operations in your code should not be explicitly "identical". TypeScript considers the operation valid if types have a similar structure and follow the same shape.&lt;/p&gt;

&lt;p&gt;I'm not going to provide a comprehensive article on type compatibility. The goal is to share with you a small research on a side-effect caused by this feature. Namely an issue with duck typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatible types example
&lt;/h2&gt;

&lt;p&gt;First, let's look at the following piece of code&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Beer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isDark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pizza&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="o"&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;Gangsta Paradise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Beer&lt;/span&gt; &lt;span class="o"&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;Pirate Rage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isDark&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="nx"&gt;pizza&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// valid operation because Pizza and Beer are compatible&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the last line, we assign the &lt;code&gt;Beer&lt;/code&gt; data to a variable having the &lt;code&gt;Pizza&lt;/code&gt; type. &lt;code&gt;Beer&lt;/code&gt; and &lt;code&gt;Pizza&lt;/code&gt; are separate, completely independent interfaces. But TypeScript considers them as compatible and allows us to put new data in the &lt;code&gt;pizza&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;In a real app such an assignment might be an issue causing mistake or vice versa a smart trick based on good understanding of TypeScript features. For our research, the idea of this assignment is not important. We only care that it is valid for Typescript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duck Typing
&lt;/h2&gt;

&lt;p&gt;Let's proceed with writing code for our app. Both &lt;code&gt;Pizza&lt;/code&gt; and &lt;code&gt;Beer&lt;/code&gt; get a new numerical property &lt;code&gt;price&lt;/code&gt;. Also, in specific cases, we want to make some discount on products. Let's say 10% discount on pizzas and 20% on beers. &lt;/p&gt;

&lt;p&gt;Following SOLID principles, we want to put the discount calculation logic in a separate function. The function is supposed to deal with all types of products. Something like 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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;price&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Beer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;isDark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;price&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDiscountPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Beer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBeer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="c1"&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;isBeer&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// beer gets 20% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// pizza gets 10% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&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;Pay attention to the &lt;code&gt;isBeer&lt;/code&gt; flag. We want to run different logic for pizzas and beers. But how to find out, which type of product the function is dealing with? &lt;/p&gt;

&lt;p&gt;If &lt;code&gt;Pizza&lt;/code&gt; and &lt;code&gt;Beer&lt;/code&gt; would be classes we could apply the &lt;code&gt;instanceof&lt;/code&gt; operator. But unfortunately, they are interfaces and  &lt;code&gt;instanceof&lt;/code&gt; would not work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duck typing&lt;/strong&gt; to the rescue! According to the interfaces we defined, &lt;code&gt;Beer&lt;/code&gt; has the &lt;code&gt;isDark&lt;/code&gt; property, but &lt;code&gt;Pizza&lt;/code&gt; don't. So we can calculate &lt;code&gt;isBeer&lt;/code&gt; like&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;function&lt;/span&gt; &lt;span class="nf"&gt;getDiscountPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Beer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBeer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isDark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;product&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;isBeer&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// beer gets 20% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// pizza gets 10% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&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;blockquote&gt;
&lt;p&gt;Note&lt;br&gt;
It would be better to wrap &lt;code&gt;isBeer&lt;/code&gt; into a type guard. But let's keep it as it is for simplicity&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Issue with duck typing for compatible types
&lt;/h2&gt;

&lt;p&gt;Let's put together the &lt;code&gt;getDiscountPrice&lt;/code&gt; function and the type compatibility case we studied in the beginning.&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;price&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Beer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&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;isDark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;price&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pizza&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="o"&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;Gangsta Paradise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Beer&lt;/span&gt; &lt;span class="o"&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;Pirate Rage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isDark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;pizza&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                          &lt;span class="c1"&gt;// (1)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDiscountPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pizza&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// (2)&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;price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                    &lt;span class="c1"&gt;// price is 90&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDiscountPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pizza&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Beer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBeer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isDark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;product&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;isBeer&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// beer gets 10% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// pizza gets 20% off&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&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;After the assignment in line &lt;code&gt;(1)&lt;/code&gt; the variable &lt;code&gt;pizza&lt;/code&gt; is still typed as &lt;code&gt;Pizza&lt;/code&gt;. Given the code of &lt;code&gt;getDiscountPrice&lt;/code&gt; we might expect that the calculated discount price will be &lt;code&gt;80&lt;/code&gt; (since any &lt;code&gt;Pizza&lt;/code&gt; is supposed to get 20% off). &lt;/p&gt;

&lt;p&gt;But actually, the calculated price will be &lt;code&gt;90&lt;/code&gt;. We have &lt;code&gt;90&lt;/code&gt; because the pizza data happened to have the &lt;code&gt;isDark&lt;/code&gt; property which is unexpected for our duck typing approach. You can run this example and check the result in &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgArAF4bsg3gKGWRDgFsIAuZAZzClAHMAaQ5AB3qSpAFdSAjaCwC++fKEixEKAEIRoeViXJVa9EM1bBqAEThQA1lX4B7EwBsIcECyIdgXYn0FQRYy2HaZsVdFhwAvHjEZJTIAOQA4tYMtDio+nAAJtoQ4UzsnGEAjAAMucjCANz4HsiC0FRyCkG4ISoR6FBwkMgASnAMaRnaeoZUdDwQGfaOeQXFYmzegeXyUEVES8srq6sA9OvIABTZAJRiCCYgtJkOKEFdYDraRzzgqFnb0-57i5s7AEwHRycWEAA6cwmBjPLJvNaQlYfbYAZgO+Bg9wQYGAx2QVxu1DuDyeHBMSR4KN8M2QAB9kNUoHtuM5oAQiL9TtoqcgguFevoDOFkKBMgSiWASkRgDBtiz5nsGUsPhUoBiIGBqMg8gBSZAmGAwVhEKCKnhQED8wkogGjFAAKmQuQBAE5WMJkBBzNQINKiB8XtgFUrkJ9curNdrlnqwAajfiTWAzVlkFabQAOB34YRAA" rel="noopener noreferrer"&gt;TypeScript Sandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can rightly say "&lt;em&gt;Wait a minute, the code works as expected. You, as a developer, put some strange data in the pizza variable in the line &lt;code&gt;(1)&lt;/code&gt;. Don't blame TypeScript&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;Well, I know, I agree with you. That's the developer's fault. But the TypeScript let me do it, no compilation error was thrown. Type compatibility system considers code like &lt;code&gt;(1)&lt;/code&gt; as valid.&lt;/p&gt;

&lt;p&gt;It might be a problem in a real-world big app. Imagine that pieces of code &lt;code&gt;(1)&lt;/code&gt;, &lt;code&gt;(2)&lt;/code&gt;, and the function declaration for &lt;code&gt;getDiscountPrice&lt;/code&gt; sit in different modules. The data flow and modules interaction is complicated. But the TS compilation reveals no errors. Valid type compatibility might result in a tricky issue if the assignment on &lt;code&gt;(1)&lt;/code&gt; is made by mistake. &lt;/p&gt;

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

&lt;p&gt;TypeScript is a great tool. Its type checking is able to detect mistakes in code making the codebase safer. But TypeScript is not able to reveal all the flaws. For me, one of the most severe drawbacks of Typescript is the fact that the border between "detectable" and "non-detectable" mistakes is sometimes blurred.&lt;/p&gt;

&lt;p&gt;I mean the code above is absolutely valid from the TS perspective. And still, it has some unexpected, error-prone behavior.&lt;/p&gt;

&lt;p&gt;Know the tools you use. I obtained deeper understanding of TypeScript when studying this case. I hope it will be helpful for you as well.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
